Merge branch 'core/percpu' into percpu-cpumask-x86-for-linus-2
[linux-2.6.git] / drivers / net / sfc / falcon.c
index 064307c..d4629ab 100644 (file)
  * @next_buffer_table: First available buffer table id
  * @pci_dev2: The secondary PCI device if present
  * @i2c_data: Operations and state for I2C bit-bashing algorithm
+ * @int_error_count: Number of internal errors seen recently
+ * @int_error_expire: Time at which error count will be expired
  */
 struct falcon_nic_data {
        unsigned next_buffer_table;
        struct pci_dev *pci_dev2;
        struct i2c_algo_bit_data i2c_data;
+
+       unsigned int_error_count;
+       unsigned long int_error_expire;
 };
 
 /**************************************************************************
@@ -119,8 +124,12 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 #define FALCON_EVQ_SIZE 4096
 #define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
 
-/* Max number of internal errors. After this resets will not be performed */
-#define FALCON_MAX_INT_ERRORS 4
+/* If FALCON_MAX_INT_ERRORS internal errors occur within
+ * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
+ * disable it.
+ */
+#define FALCON_INT_ERROR_EXPIRE 3600
+#define FALCON_MAX_INT_ERRORS 5
 
 /* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
  */
@@ -146,13 +155,6 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 /* Dummy SRAM size code */
 #define SRM_NB_BSZ_ONCHIP_ONLY (-1)
 
-/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
-#define PCI_EXP_DEVCAP_PWR_VAL_LBN     18
-#define PCI_EXP_DEVCAP_PWR_SCL_LBN     26
-#define PCI_EXP_DEVCTL_PAYLOAD_LBN     5
-#define PCI_EXP_LNKSTA_LNK_WID         0x3f0
-#define PCI_EXP_LNKSTA_LNK_WID_LBN     4
-
 #define FALCON_IS_DUAL_FUNC(efx)               \
        (falcon_rev(efx) < FALCON_REV_B0)
 
@@ -727,6 +729,9 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
                tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
                tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
                tx_queue = &efx->tx_queue[tx_ev_q_label];
+               channel->irq_mod_score +=
+                       (tx_ev_desc_ptr - tx_queue->read_count) &
+                       efx->type->txd_ring_mask;
                efx_xmit_done(tx_queue, tx_ev_desc_ptr);
        } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
                /* Rewrite the FIFO write pointer */
@@ -896,6 +901,8 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
                        discard = true;
        }
 
+       channel->irq_mod_score += 2;
+
        /* Handle received packet */
        efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
                      checksummed, discard);
@@ -1073,14 +1080,15 @@ void falcon_set_int_moderation(struct efx_channel *channel)
                 * program is based at 0.  So actual interrupt moderation
                 * achieved is ((x + 1) * res).
                 */
-               unsigned int res = 5;
-               channel->irq_moderation -= (channel->irq_moderation % res);
-               if (channel->irq_moderation < res)
-                       channel->irq_moderation = res;
+               channel->irq_moderation -= (channel->irq_moderation %
+                                           FALCON_IRQ_MOD_RESOLUTION);
+               if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION)
+                       channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION;
                EFX_POPULATE_DWORD_2(timer_cmd,
                                     TIMER_MODE, TIMER_MODE_INT_HLDOFF,
                                     TIMER_VAL,
-                                    (channel->irq_moderation / res) - 1);
+                                    channel->irq_moderation /
+                                    FALCON_IRQ_MOD_RESOLUTION - 1);
        } else {
                EFX_POPULATE_DWORD_2(timer_cmd,
                                     TIMER_MODE, TIMER_MODE_DIS,
@@ -1187,31 +1195,29 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
        struct efx_channel *channel = &efx->channel[0];
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
-       unsigned int read_ptr, i;
+       unsigned int read_ptr = channel->eventq_read_ptr;
+       unsigned int end_ptr = (read_ptr - 1) & FALCON_EVQ_MASK;
 
-       read_ptr = channel->eventq_read_ptr;
-       for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+       do {
                efx_qword_t *event = falcon_event(channel, read_ptr);
                int ev_code, ev_sub_code, ev_queue;
                bool ev_failed;
+
                if (!falcon_event_present(event))
                        break;
 
                ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
-               if (ev_code != DRIVER_EV_DECODE)
-                       continue;
-
                ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-               switch (ev_sub_code) {
-               case TX_DESCQ_FLS_DONE_EV_DECODE:
+               if (ev_code == DRIVER_EV_DECODE &&
+                   ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) {
                        ev_queue = EFX_QWORD_FIELD(*event,
                                                   DRIVER_EV_TX_DESCQ_ID);
                        if (ev_queue < EFX_TX_QUEUE_COUNT) {
                                tx_queue = efx->tx_queue + ev_queue;
                                tx_queue->flushed = true;
                        }
-                       break;
-               case RX_DESCQ_FLS_DONE_EV_DECODE:
+               } else if (ev_code == DRIVER_EV_DECODE &&
+                          ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) {
                        ev_queue = EFX_QWORD_FIELD(*event,
                                                   DRIVER_EV_RX_DESCQ_ID);
                        ev_failed = EFX_QWORD_FIELD(*event,
@@ -1225,11 +1231,10 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
                                else
                                        rx_queue->flushed = true;
                        }
-                       break;
                }
 
                read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-       }
+       } while (read_ptr != end_ptr);
 }
 
 /* Handle tx and rx flushes at the same time, since they run in
@@ -1377,7 +1382,6 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
        efx_oword_t *int_ker = efx->irq_status.addr;
        efx_oword_t fatal_intr;
        int error, mem_perr;
-       static int n_int_errors;
 
        falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
        error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
@@ -1404,7 +1408,14 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
                pci_clear_master(nic_data->pci_dev2);
        falcon_disable_interrupts(efx);
 
-       if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
+       /* Count errors and reset or disable the NIC accordingly */
+       if (nic_data->int_error_count == 0 ||
+           time_after(jiffies, nic_data->int_error_expire)) {
+               nic_data->int_error_count = 0;
+               nic_data->int_error_expire =
+                       jiffies + FALCON_INT_ERROR_EXPIRE * HZ;
+       }
+       if (++nic_data->int_error_count < FALCON_MAX_INT_ERRORS) {
                EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
                efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
        } else {
@@ -1423,6 +1434,7 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
 {
        struct efx_nic *efx = dev_id;
        efx_oword_t *int_ker = efx->irq_status.addr;
+       irqreturn_t result = IRQ_NONE;
        struct efx_channel *channel;
        efx_dword_t reg;
        u32 queues;
@@ -1437,23 +1449,24 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
        if (unlikely(syserr))
                return falcon_fatal_interrupt(efx);
 
-       if (queues == 0)
-               return IRQ_NONE;
-
-       efx->last_irq_cpu = raw_smp_processor_id();
-       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
-                 irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
-
        /* Schedule processing of any interrupting queues */
-       channel = &efx->channel[0];
-       while (queues) {
-               if (queues & 0x01)
+       efx_for_each_channel(channel, efx) {
+               if ((queues & 1) ||
+                   falcon_event_present(
+                           falcon_event(channel, channel->eventq_read_ptr))) {
                        efx_schedule_channel(channel);
-               channel++;
+                       result = IRQ_HANDLED;
+               }
                queues >>= 1;
        }
 
-       return IRQ_HANDLED;
+       if (result == IRQ_HANDLED) {
+               efx->last_irq_cpu = raw_smp_processor_id();
+               EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+                         irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+       }
+
+       return result;
 }
 
 
@@ -2249,6 +2262,7 @@ static int falcon_probe_phy(struct efx_nic *efx)
                efx->phy_op = &falcon_sft9001_phy_ops;
                break;
        case PHY_TYPE_QT2022C2:
+       case PHY_TYPE_QT2025C:
                efx->phy_op = &falcon_xfp_phy_ops;
                break;
        default:
@@ -3113,8 +3127,10 @@ void falcon_remove_nic(struct efx_nic *efx)
        struct falcon_nic_data *nic_data = efx->nic_data;
        int rc;
 
+       /* Remove I2C adapter and clear it in preparation for a retry */
        rc = i2c_del_adapter(&efx->i2c_adap);
        BUG_ON(rc);
+       memset(&efx->i2c_adap, 0, sizeof(efx->i2c_adap));
 
        falcon_remove_spi_devices(efx);
        falcon_free_buffer(efx, &efx->irq_status);