Commit fd371e32 authored by Steve Hodgson's avatar Steve Hodgson Committed by David S. Miller

sfc: Workaround flush failures on Falcon B0

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: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 319ba649
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "nic.h" #include "nic.h"
#include "mcdi.h" #include "mcdi.h"
#include "workarounds.h"
/************************************************************************** /**************************************************************************
* *
...@@ -556,10 +557,18 @@ static void efx_fini_channels(struct efx_nic *efx) ...@@ -556,10 +557,18 @@ static void efx_fini_channels(struct efx_nic *efx)
BUG_ON(efx->port_enabled); BUG_ON(efx->port_enabled);
rc = efx_nic_flush_queues(efx); 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"); EFX_ERR(efx, "failed to flush queues\n");
else } else {
EFX_LOG(efx, "successfully flushed all queues\n"); EFX_LOG(efx, "successfully flushed all queues\n");
}
efx_for_each_channel(channel, efx) { efx_for_each_channel(channel, efx) {
EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel); EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
......
...@@ -548,7 +548,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) ...@@ -548,7 +548,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
{ {
struct efx_link_state *link_state = &efx->link_state; struct efx_link_state *link_state = &efx->link_state;
efx_oword_t reg; efx_oword_t reg;
int link_speed; int link_speed, isolate;
isolate = (efx->reset_pending != RESET_TYPE_NONE);
switch (link_state->speed) { switch (link_state->speed) {
case 10000: link_speed = 3; break; case 10000: link_speed = 3; break;
...@@ -570,7 +572,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) ...@@ -570,7 +572,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
* discarded. */ * discarded. */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 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); efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
...@@ -584,7 +586,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) ...@@ -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); EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
/* Unisolate the MAC -> RX */ /* Unisolate the MAC -> RX */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) 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); efx_writeo(efx, &reg, FR_AZ_RX_CFG);
} }
......
...@@ -1219,9 +1219,6 @@ int efx_nic_flush_queues(struct efx_nic *efx) ...@@ -1219,9 +1219,6 @@ int efx_nic_flush_queues(struct efx_nic *efx)
rx_queue->flushed = FLUSH_DONE; rx_queue->flushed = FLUSH_DONE;
} }
if (EFX_WORKAROUND_7803(efx))
return 0;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
/* Increase filter depth to avoid RX_RESET */ /* Increase filter depth to avoid RX_RESET */
#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A #define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
/* Flushes may never complete */ /* 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 */ /* Leak overlength packets rather than free */
#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment