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: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
319ba649af
commit
fd371e32fe
|
@ -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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
* 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, ®, FR_AB_MAC_CTRL);
|
efx_writeo(efx, ®, 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);
|
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, ®, FR_AZ_RX_CFG);
|
efx_writeo(efx, ®, FR_AZ_RX_CFG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 @@
|
||||||
/* 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
|
||||||
|
|
||||||
|
|
Reference in New Issue