aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 d294d66fd600..d09ad1b1cd8b 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 cb018e272097..70aea3af9ae7 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 664fd6ceed55..23738f80835b 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()).