aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSteve Hodgson <shodgson@solarflare.com>2010-06-01 07:17:51 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-02 05:21:06 -0400
commitfd371e32fe53f137a0f940d61772bda92180007b (patch)
treec2ce5d564aae698ecc643d8af42696e374a60728 /drivers
parent319ba649af30321ea221740833785b46e1fe6af3 (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sfc/efx.c13
-rw-r--r--drivers/net/sfc/falcon.c8
-rw-r--r--drivers/net/sfc/nic.c3
-rw-r--r--drivers/net/sfc/workarounds.h2
4 files changed, 17 insertions, 9 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 0319000379e..d1a1d32e73e 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -27,6 +27,7 @@
27#include "nic.h" 27#include "nic.h"
28 28
29#include "mcdi.h" 29#include "mcdi.h"
30#include "workarounds.h"
30 31
31/************************************************************************** 32/**************************************************************************
32 * 33 *
@@ -556,10 +557,18 @@ static void efx_fini_channels(struct efx_nic *efx)
556 BUG_ON(efx->port_enabled); 557 BUG_ON(efx->port_enabled);
557 558
558 rc = efx_nic_flush_queues(efx); 559 rc = efx_nic_flush_queues(efx);
559 if (rc) 560 if (rc && EFX_WORKAROUND_7803(efx)) {
561 /* Schedule a reset to recover from the flush failure. The
562 * descriptor caches reference memory we're about to free,
563 * but falcon_reconfigure_mac_wrapper() won't reconnect
564 * the MACs because of the pending reset. */
565 EFX_ERR(efx, "Resetting to recover from flush failure\n");
566 efx_schedule_reset(efx, RESET_TYPE_ALL);
567 } else if (rc) {
560 EFX_ERR(efx, "failed to flush queues\n"); 568 EFX_ERR(efx, "failed to flush queues\n");
561 else 569 } else {
562 EFX_LOG(efx, "successfully flushed all queues\n"); 570 EFX_LOG(efx, "successfully flushed all queues\n");
571 }
563 572
564 efx_for_each_channel(channel, efx) { 573 efx_for_each_channel(channel, efx) {
565 EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel); 574 EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 655b697b45b..8558865ff38 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -548,7 +548,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
548{ 548{
549 struct efx_link_state *link_state = &efx->link_state; 549 struct efx_link_state *link_state = &efx->link_state;
550 efx_oword_t reg; 550 efx_oword_t reg;
551 int link_speed; 551 int link_speed, isolate;
552
553 isolate = (efx->reset_pending != RESET_TYPE_NONE);
552 554
553 switch (link_state->speed) { 555 switch (link_state->speed) {
554 case 10000: link_speed = 3; break; 556 case 10000: link_speed = 3; break;
@@ -570,7 +572,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
570 * discarded. */ 572 * discarded. */
571 if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { 573 if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
572 EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 574 EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
573 !link_state->up); 575 !link_state->up || isolate);
574 } 576 }
575 577
576 efx_writeo(efx, &reg, FR_AB_MAC_CTRL); 578 efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
@@ -584,7 +586,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
584 EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); 586 EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
585 /* Unisolate the MAC -> RX */ 587 /* Unisolate the MAC -> RX */
586 if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) 588 if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
587 EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); 589 EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
588 efx_writeo(efx, &reg, FR_AZ_RX_CFG); 590 efx_writeo(efx, &reg, FR_AZ_RX_CFG);
589} 591}
590 592
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 5d3aaec5855..ec0bb80f5ae 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1219,9 +1219,6 @@ int efx_nic_flush_queues(struct efx_nic *efx)
1219 rx_queue->flushed = FLUSH_DONE; 1219 rx_queue->flushed = FLUSH_DONE;
1220 } 1220 }
1221 1221
1222 if (EFX_WORKAROUND_7803(efx))
1223 return 0;
1224
1225 return -ETIMEDOUT; 1222 return -ETIMEDOUT;
1226} 1223}
1227 1224
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 518f7fc9147..782e45a613d 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -54,7 +54,7 @@
54/* Increase filter depth to avoid RX_RESET */ 54/* Increase filter depth to avoid RX_RESET */
55#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A 55#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
56/* Flushes may never complete */ 56/* Flushes may never complete */
57#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A 57#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_AB
58/* Leak overlength packets rather than free */ 58/* Leak overlength packets rather than free */
59#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A 59#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
60 60