diff options
author | Steve Hodgson <shodgson@solarflare.com> | 2010-06-01 07:17:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-02 05:21:06 -0400 |
commit | fd371e32fe53f137a0f940d61772bda92180007b (patch) | |
tree | c2ce5d564aae698ecc643d8af42696e374a60728 /drivers/net/sfc | |
parent | 319ba649af30321ea221740833785b46e1fe6af3 (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/net/sfc')
-rw-r--r-- | drivers/net/sfc/efx.c | 13 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 8 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 3 | ||||
-rw-r--r-- | drivers/net/sfc/workarounds.h | 2 |
4 files changed, 17 insertions, 9 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 0319000379e1..d1a1d32e73ee 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 655b697b45b2..8558865ff380 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, ®, FR_AB_MAC_CTRL); | 578 | efx_writeo(efx, ®, 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, ®, FR_AZ_RX_CFG); | 590 | efx_writeo(efx, ®, FR_AZ_RX_CFG); |
589 | } | 591 | } |
590 | 592 | ||
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 5d3aaec58556..ec0bb80f5ae8 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 518f7fc91473..782e45a613d6 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 | ||