aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Hodgson <shodgson@solarflare.com>2010-04-28 05:28:27 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-28 15:44:35 -0400
commit41b7e4c3268d9d2056b9c94cceb386649f7b185b (patch)
tree706d46fdd10943ba86d4eda2ff210bc506997144
parentb7b40eeb0f76e73503a7e5a98d1353c2e42d9a18 (diff)
sfc: Extend the legacy interrupt workarounds
Siena has two problems with legacy interrupts: 1. There is no synchronisation between the ISR read completion, and the interrupt deassert message. 2. A downstream read at the "wrong" moment can return 0, and suppress generating the next interrupt. Falcon should suffer from both of these, and it appears it does. Enable EFX_WORKAROUND_15783 on Falcon as well. Also, when we see queues == 0, ensure we always schedule or rearm every event queue. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/sfc/nic.c23
-rw-r--r--drivers/net/sfc/workarounds.h2
2 files changed, 10 insertions, 15 deletions
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 23738f80835b..b61674cb0c19 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1356,33 +1356,28 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
1356 } 1356 }
1357 result = IRQ_HANDLED; 1357 result = IRQ_HANDLED;
1358 1358
1359 } else if (EFX_WORKAROUND_15783(efx) && 1359 } else if (EFX_WORKAROUND_15783(efx)) {
1360 efx->irq_zero_count++ == 0) {
1361 efx_qword_t *event; 1360 efx_qword_t *event;
1362 1361
1363 /* Ensure we rearm all event queues */ 1362 /* We can't return IRQ_HANDLED more than once on seeing ISR=0
1363 * because this might be a shared interrupt. */
1364 if (efx->irq_zero_count++ == 0)
1365 result = IRQ_HANDLED;
1366
1367 /* Ensure we schedule or rearm all event queues */
1364 efx_for_each_channel(channel, efx) { 1368 efx_for_each_channel(channel, efx) {
1365 event = efx_event(channel, channel->eventq_read_ptr); 1369 event = efx_event(channel, channel->eventq_read_ptr);
1366 if (efx_event_present(event)) 1370 if (efx_event_present(event))
1367 efx_schedule_channel(channel); 1371 efx_schedule_channel(channel);
1372 else
1373 efx_nic_eventq_read_ack(channel);
1368 } 1374 }
1369
1370 result = IRQ_HANDLED;
1371 } 1375 }
1372 1376
1373 if (result == IRQ_HANDLED) { 1377 if (result == IRQ_HANDLED) {
1374 efx->last_irq_cpu = raw_smp_processor_id(); 1378 efx->last_irq_cpu = raw_smp_processor_id();
1375 EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", 1379 EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
1376 irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); 1380 irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
1377 } else if (EFX_WORKAROUND_15783(efx)) {
1378 /* We can't return IRQ_HANDLED more than once on seeing ISR0=0
1379 * because this might be a shared interrupt, but we do need to
1380 * check the channel every time and preemptively rearm it if
1381 * it's idle. */
1382 efx_for_each_channel(channel, efx) {
1383 if (!channel->work_pending)
1384 efx_nic_eventq_read_ack(channel);
1385 }
1386 } 1381 }
1387 1382
1388 return result; 1383 return result;
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index acd9c734e483..518f7fc91473 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -37,7 +37,7 @@
37/* Truncated IPv4 packets can confuse the TX packet parser */ 37/* Truncated IPv4 packets can confuse the TX packet parser */
38#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB 38#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
39/* Legacy ISR read can return zero once */ 39/* Legacy ISR read can return zero once */
40#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA 40#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS
41/* Legacy interrupt storm when interrupt fifo fills */ 41/* Legacy interrupt storm when interrupt fifo fills */
42#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA 42#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
43 43