diff options
author | Steve Hodgson <shodgson@solarflare.com> | 2010-04-28 05:27:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-28 15:44:32 -0400 |
commit | 6369545945b90daa1a73fca174da9194c398417c (patch) | |
tree | 1331418d5c6b547eed8154fedceed68585506aa5 /drivers/net/sfc/falcon.c | |
parent | 00bbb4a5344a5f81cf5d48e781e5c0df3e588d17 (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/falcon.c')
-rw-r--r-- | drivers/net/sfc/falcon.c | 13 |
1 files changed, 8 insertions, 5 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); |