aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorSteve Hodgson <shodgson@solarflare.com>2010-04-28 05:27:36 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-28 15:44:32 -0400
commit6369545945b90daa1a73fca174da9194c398417c (patch)
tree1331418d5c6b547eed8154fedceed68585506aa5 /drivers/net/sfc
parent00bbb4a5344a5f81cf5d48e781e5c0df3e588d17 (diff)
sfc: Handle serious errors in exactly one interrupt handler
'Fatal' errors set an interrupt flag associated with a specific event queue; only read the syndrome vector if we see that queue's flag set (legacy interrupts) or in the interrupt handler for that queue (MSI). Do not ignore an interrupt if the fatal error flag is set but specific error flags are all zero. Even if we don't schedule a reset, we must respect the queue mask and rearm the appropriate event queues. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/falcon.c13
-rw-r--r--drivers/net/sfc/net_driver.h2
-rw-r--r--drivers/net/sfc/nic.c35
3 files changed, 29 insertions, 21 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index d294d66fd60..d09ad1b1cd8 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -175,16 +175,19 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
175 EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", 175 EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
176 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); 176 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
177 177
178 /* Check to see if we have a serious error condition */
179 syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
180 if (unlikely(syserr))
181 return efx_nic_fatal_interrupt(efx);
182
183 /* Determine interrupting queues, clear interrupt status 178 /* Determine interrupting queues, clear interrupt status
184 * register and acknowledge the device interrupt. 179 * register and acknowledge the device interrupt.
185 */ 180 */
186 BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS); 181 BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS);
187 queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); 182 queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q);
183
184 /* Check to see if we have a serious error condition */
185 if (queues & (1U << efx->fatal_irq_level)) {
186 syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
187 if (unlikely(syserr))
188 return efx_nic_fatal_interrupt(efx);
189 }
190
188 EFX_ZERO_OWORD(*int_ker); 191 EFX_ZERO_OWORD(*int_ker);
189 wmb(); /* Ensure the vector is cleared before interrupt ack */ 192 wmb(); /* Ensure the vector is cleared before interrupt ack */
190 falcon_irq_ack_a1(efx); 193 falcon_irq_ack_a1(efx);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index cb018e27209..70aea3af9ae 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -672,6 +672,7 @@ union efx_multicast_hash {
672 * This register is written with the SMP processor ID whenever an 672 * This register is written with the SMP processor ID whenever an
673 * interrupt is handled. It is used by efx_nic_test_interrupt() 673 * interrupt is handled. It is used by efx_nic_test_interrupt()
674 * to verify that an interrupt has occurred. 674 * to verify that an interrupt has occurred.
675 * @fatal_irq_level: IRQ level (bit number) used for serious errors
675 * @spi_flash: SPI flash device 676 * @spi_flash: SPI flash device
676 * This field will be %NULL if no flash device is present (or for Siena). 677 * This field will be %NULL if no flash device is present (or for Siena).
677 * @spi_eeprom: SPI EEPROM device 678 * @spi_eeprom: SPI EEPROM device
@@ -756,6 +757,7 @@ struct efx_nic {
756 struct efx_buffer irq_status; 757 struct efx_buffer irq_status;
757 volatile signed int last_irq_cpu; 758 volatile signed int last_irq_cpu;
758 unsigned long irq_zero_count; 759 unsigned long irq_zero_count;
760 unsigned fatal_irq_level;
759 761
760 struct efx_spi_device *spi_flash; 762 struct efx_spi_device *spi_flash;
761 struct efx_spi_device *spi_eeprom; 763 struct efx_spi_device *spi_eeprom;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 664fd6ceed5..23738f80835 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1229,15 +1229,9 @@ static inline void efx_nic_interrupts(struct efx_nic *efx,
1229 bool enabled, bool force) 1229 bool enabled, bool force)
1230{ 1230{
1231 efx_oword_t int_en_reg_ker; 1231 efx_oword_t int_en_reg_ker;
1232 unsigned int level = 0;
1233
1234 if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx))
1235 /* Set the level always even if we're generating a test
1236 * interrupt, because our legacy interrupt handler is safe */
1237 level = 0x1f;
1238 1232
1239 EFX_POPULATE_OWORD_3(int_en_reg_ker, 1233 EFX_POPULATE_OWORD_3(int_en_reg_ker,
1240 FRF_AZ_KER_INT_LEVE_SEL, level, 1234 FRF_AZ_KER_INT_LEVE_SEL, efx->fatal_irq_level,
1241 FRF_AZ_KER_INT_KER, force, 1235 FRF_AZ_KER_INT_KER, force,
1242 FRF_AZ_DRV_INT_EN_KER, enabled); 1236 FRF_AZ_DRV_INT_EN_KER, enabled);
1243 efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); 1237 efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
@@ -1291,8 +1285,6 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
1291 EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), 1285 EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
1292 EFX_OWORD_VAL(fatal_intr), 1286 EFX_OWORD_VAL(fatal_intr),
1293 error ? "disabling bus mastering" : "no recognised error"); 1287 error ? "disabling bus mastering" : "no recognised error");
1294 if (error == 0)
1295 goto out;
1296 1288
1297 /* If this is a memory parity error dump which blocks are offending */ 1289 /* If this is a memory parity error dump which blocks are offending */
1298 mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); 1290 mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER);
@@ -1324,7 +1316,7 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
1324 "NIC will be disabled\n"); 1316 "NIC will be disabled\n");
1325 efx_schedule_reset(efx, RESET_TYPE_DISABLE); 1317 efx_schedule_reset(efx, RESET_TYPE_DISABLE);
1326 } 1318 }
1327out: 1319
1328 return IRQ_HANDLED; 1320 return IRQ_HANDLED;
1329} 1321}
1330 1322
@@ -1346,9 +1338,11 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
1346 queues = EFX_EXTRACT_DWORD(reg, 0, 31); 1338 queues = EFX_EXTRACT_DWORD(reg, 0, 31);
1347 1339
1348 /* Check to see if we have a serious error condition */ 1340 /* Check to see if we have a serious error condition */
1349 syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); 1341 if (queues & (1U << efx->fatal_irq_level)) {
1350 if (unlikely(syserr)) 1342 syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
1351 return efx_nic_fatal_interrupt(efx); 1343 if (unlikely(syserr))
1344 return efx_nic_fatal_interrupt(efx);
1345 }
1352 1346
1353 if (queues != 0) { 1347 if (queues != 0) {
1354 if (EFX_WORKAROUND_15783(efx)) 1348 if (EFX_WORKAROUND_15783(efx))
@@ -1413,9 +1407,11 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
1413 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); 1407 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
1414 1408
1415 /* Check to see if we have a serious error condition */ 1409 /* Check to see if we have a serious error condition */
1416 syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); 1410 if (channel->channel == efx->fatal_irq_level) {
1417 if (unlikely(syserr)) 1411 syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
1418 return efx_nic_fatal_interrupt(efx); 1412 if (unlikely(syserr))
1413 return efx_nic_fatal_interrupt(efx);
1414 }
1419 1415
1420 /* Schedule processing of the channel */ 1416 /* Schedule processing of the channel */
1421 efx_schedule_channel(channel); 1417 efx_schedule_channel(channel);
@@ -1553,6 +1549,13 @@ void efx_nic_init_common(struct efx_nic *efx)
1553 FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); 1549 FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
1554 efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER); 1550 efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER);
1555 1551
1552 if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx))
1553 /* Use an interrupt level unused by event queues */
1554 efx->fatal_irq_level = 0x1f;
1555 else
1556 /* Use a valid MSI-X vector */
1557 efx->fatal_irq_level = 0;
1558
1556 /* Enable all the genuinely fatal interrupts. (They are still 1559 /* Enable all the genuinely fatal interrupts. (They are still
1557 * masked by the overall interrupt mask, controlled by 1560 * masked by the overall interrupt mask, controlled by
1558 * falcon_interrupts()). 1561 * falcon_interrupts()).