sfc: Extend the legacy interrupt workarounds
authorSteve Hodgson <shodgson@solarflare.com>
Wed, 28 Apr 2010 09:28:27 +0000 (09:28 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Apr 2010 19:44:35 +0000 (12:44 -0700)
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>
drivers/net/sfc/nic.c
drivers/net/sfc/workarounds.h

index 23738f8..b61674c 100644 (file)
@@ -1356,33 +1356,28 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
                }
                result = IRQ_HANDLED;
 
-       } else if (EFX_WORKAROUND_15783(efx) &&
-                  efx->irq_zero_count++ == 0) {
+       } else if (EFX_WORKAROUND_15783(efx)) {
                efx_qword_t *event;
 
-               /* Ensure we rearm all event queues */
+               /* We can't return IRQ_HANDLED more than once on seeing ISR=0
+                * because this might be a shared interrupt. */
+               if (efx->irq_zero_count++ == 0)
+                       result = IRQ_HANDLED;
+
+               /* Ensure we schedule or rearm all event queues */
                efx_for_each_channel(channel, efx) {
                        event = efx_event(channel, channel->eventq_read_ptr);
                        if (efx_event_present(event))
                                efx_schedule_channel(channel);
+                       else
+                               efx_nic_eventq_read_ack(channel);
                }
-
-               result = 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));
-       } else if (EFX_WORKAROUND_15783(efx)) {
-               /* We can't return IRQ_HANDLED more than once on seeing ISR0=0
-                * because this might be a shared interrupt, but we do need to
-                * check the channel every time and preemptively rearm it if
-                * it's idle. */
-               efx_for_each_channel(channel, efx) {
-                       if (!channel->work_pending)
-                               efx_nic_eventq_read_ack(channel);
-               }
        }
 
        return result;
index acd9c73..518f7fc 100644 (file)
@@ -37,7 +37,7 @@
 /* Truncated IPv4 packets can confuse the TX packet parser */
 #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
 /* Legacy ISR read can return zero once */
-#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA
+#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS
 /* Legacy interrupt storm when interrupt fifo fills */
 #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA