sfc: Work around unreliable legacy interrupt status
In rare cases, reading the legacy interrupt status register can acknowledge an event queue whose attention flag has not yet been set in the register. Until we service this event queue it will not generate any more interrupts. Therefore, as a secondary check, poll the next slot in each active event queue whose flag is not set. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
bb145a9e28
Коммит
a9de9a74c6
|
@ -1435,6 +1435,7 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct efx_nic *efx = dev_id;
|
struct efx_nic *efx = dev_id;
|
||||||
efx_oword_t *int_ker = efx->irq_status.addr;
|
efx_oword_t *int_ker = efx->irq_status.addr;
|
||||||
|
irqreturn_t result = IRQ_NONE;
|
||||||
struct efx_channel *channel;
|
struct efx_channel *channel;
|
||||||
efx_dword_t reg;
|
efx_dword_t reg;
|
||||||
u32 queues;
|
u32 queues;
|
||||||
|
@ -1449,23 +1450,24 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
|
||||||
if (unlikely(syserr))
|
if (unlikely(syserr))
|
||||||
return falcon_fatal_interrupt(efx);
|
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 */
|
/* Schedule processing of any interrupting queues */
|
||||||
channel = &efx->channel[0];
|
efx_for_each_channel(channel, efx) {
|
||||||
while (queues) {
|
if ((queues & 1) ||
|
||||||
if (queues & 0x01)
|
falcon_event_present(
|
||||||
|
falcon_event(channel, channel->eventq_read_ptr))) {
|
||||||
efx_schedule_channel(channel);
|
efx_schedule_channel(channel);
|
||||||
channel++;
|
result = IRQ_HANDLED;
|
||||||
|
}
|
||||||
queues >>= 1;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче