sfc: Workaround flush failures on Falcon B0
authorSteve Hodgson <shodgson@solarflare.com>
Tue, 1 Jun 2010 11:17:51 +0000 (11:17 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Jun 2010 09:21:06 +0000 (02:21 -0700)
Under certain conditions a PHY may backpressure Falcon B0
in such a way that flushes timeout. In normal circumstances
the phy poller would fix the PHY, and the flush could complete.

But efx_nic_flush_queues() is always called after efx_stop_all(),
so the poller has been stopped. Even if this weren't the case,
how long would we have to wait for the poller to fix this? And
several callers of efx_nic_flush_queues() are about to reset
the device anyway - so we don't need to do anything.

Work around this bug by scheduling a reset. Ensure that the
MAC is never rewired back into the datapath before the reset
runs (we already ignore all rx events anyway).

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/sfc/efx.c
drivers/net/sfc/falcon.c
drivers/net/sfc/nic.c
drivers/net/sfc/workarounds.h

index 0319000..d1a1d32 100644 (file)
@@ -27,6 +27,7 @@
 #include "nic.h"
 
 #include "mcdi.h"
+#include "workarounds.h"
 
 /**************************************************************************
  *
@@ -556,10 +557,18 @@ static void efx_fini_channels(struct efx_nic *efx)
        BUG_ON(efx->port_enabled);
 
        rc = efx_nic_flush_queues(efx);
-       if (rc)
+       if (rc && EFX_WORKAROUND_7803(efx)) {
+               /* Schedule a reset to recover from the flush failure. The
+                * descriptor caches reference memory we're about to free,
+                * but falcon_reconfigure_mac_wrapper() won't reconnect
+                * the MACs because of the pending reset. */
+               EFX_ERR(efx, "Resetting to recover from flush failure\n");
+               efx_schedule_reset(efx, RESET_TYPE_ALL);
+       } else if (rc) {
                EFX_ERR(efx, "failed to flush queues\n");
-       else
+       } else {
                EFX_LOG(efx, "successfully flushed all queues\n");
+       }
 
        efx_for_each_channel(channel, efx) {
                EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
index 655b697..8558865 100644 (file)
@@ -548,7 +548,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 {
        struct efx_link_state *link_state = &efx->link_state;
        efx_oword_t reg;
-       int link_speed;
+       int link_speed, isolate;
+
+       isolate = (efx->reset_pending != RESET_TYPE_NONE);
 
        switch (link_state->speed) {
        case 10000: link_speed = 3; break;
@@ -570,7 +572,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
         * discarded. */
        if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
                EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
-                                   !link_state->up);
+                                   !link_state->up || isolate);
        }
 
        efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
@@ -584,7 +586,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
        EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
        /* Unisolate the MAC -> RX */
        if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
-               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
        efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
index 5d3aaec..ec0bb80 100644 (file)
@@ -1219,9 +1219,6 @@ int efx_nic_flush_queues(struct efx_nic *efx)
                rx_queue->flushed = FLUSH_DONE;
        }
 
-       if (EFX_WORKAROUND_7803(efx))
-               return 0;
-
        return -ETIMEDOUT;
 }
 
index 518f7fc..782e45a 100644 (file)
@@ -54,7 +54,7 @@
 /* Increase filter depth to avoid RX_RESET */
 #define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
 /* Flushes may never complete */
-#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_AB
 /* Leak overlength packets rather than free */
 #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A