summaryrefslogtreecommitdiffstats
path: root/sys/dev/bge
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2013-07-17 04:53:53 +0000
committeryongari <yongari@FreeBSD.org>2013-07-17 04:53:53 +0000
commit245aaea467cf9f61dfd01b887de0297ba2ea60bc (patch)
treed1652e6e39b4519096af9dedc863e74b74659216 /sys/dev/bge
parent6a81f43eb6540d6da860c9ce9303da94fa1dcc62 (diff)
downloadFreeBSD-src-245aaea467cf9f61dfd01b887de0297ba2ea60bc.zip
FreeBSD-src-245aaea467cf9f61dfd01b887de0297ba2ea60bc.tar.gz
Implement workaround for BCM5719/BCM5720 TX hang.
The read DMA request logic operation is based on having sufficient available space in the transmit data buffer (TXMBUF) before a read DMA can be requested. There are four read DMA channels that use the TXMBUF, and the logic checks if the available free space in the TXMBUF is large enough for all the data in the four Send Buffers for which buffer descriptors have been fetched. The Enable_Request signal is asserted only if the free TXMBUF space is larger than the sum of the four DMA length registers. The power-up default value of BGE_RDMA_LSO_CRPTEN_CTRL register bit 25 (bit 21 on BCM5720) is zero, which selects the DMA length registers to connect to the input of the adder block. The DMA length registers are asynchronously reset following BCM5719/BCM5720 power-up, and due to the lack of synchronous deassertion of the length registers reset signal these resisters may contain uninitialized values following the reset deassertion. In the case of the failure the uninitialized DMA length register values added up to more than the TXMBUF size, which prevented the assertion of the Enable_Request signal and any subsequent read DMA to start. This lockup condition is the root cause of failing to generate any transmit traffic. To workaround the issue, select alternate output of multiplexers and transmit the first four Ethernet frames. This overwrites the DMA length registers with valid values. Reported by: Geans Pin <geanspin@broadcom.com> Reviewed by: Geans Pin <geanspin@broadcom.com>
Diffstat (limited to 'sys/dev/bge')
-rw-r--r--sys/dev/bge/if_bge.c53
-rw-r--r--sys/dev/bge/if_bgereg.h6
2 files changed, 55 insertions, 4 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index 306acc6..ee60626 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -2508,6 +2508,24 @@ bge_blockinit(struct bge_softc *sc)
CSR_WRITE_4(sc, BGE_RDMA_MODE, val);
DELAY(40);
+ if (sc->bge_flags & BGE_FLAG_RDMA_BUG) {
+ for (i = 0; i < BGE_NUM_RDMA_CHANNELS / 2; i++) {
+ val = CSR_READ_4(sc, BGE_RDMA_LENGTH + i * 4);
+ if ((val & 0xFFFF) > BGE_FRAMELEN)
+ break;
+ if (((val >> 16) & 0xFFFF) > BGE_FRAMELEN)
+ break;
+ }
+ if (i != BGE_NUM_RDMA_CHANNELS / 2) {
+ val = CSR_READ_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL);
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5719)
+ val |= BGE_RDMA_TX_LENGTH_WA_5719;
+ else
+ val |= BGE_RDMA_TX_LENGTH_WA_5720;
+ CSR_WRITE_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL, val);
+ }
+ }
+
/* Turn on RX data completion state machine */
CSR_WRITE_4(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE);
@@ -3319,10 +3337,18 @@ bge_attach(device_t dev)
sc->bge_flags |= BGE_FLAG_5717_PLUS | BGE_FLAG_5755_PLUS |
BGE_FLAG_575X_PLUS | BGE_FLAG_5705_PLUS | BGE_FLAG_JUMBO |
BGE_FLAG_JUMBO_FRAME;
- if (sc->bge_asicrev == BGE_ASICREV_BCM5719 &&
- sc->bge_chipid == BGE_CHIPID_BCM5719_A0) {
- /* Jumbo frame on BCM5719 A0 does not work. */
- sc->bge_flags &= ~BGE_FLAG_JUMBO;
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5719 ||
+ sc->bge_asicrev == BGE_ASICREV_BCM5720) {
+ /*
+ * Enable work around for DMA engine miscalculation
+ * of TXMBUF available space.
+ */
+ sc->bge_flags |= BGE_FLAG_RDMA_BUG;
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5719 &&
+ sc->bge_chipid == BGE_CHIPID_BCM5719_A0) {
+ /* Jumbo frame on BCM5719 A0 does not work. */
+ sc->bge_flags &= ~BGE_FLAG_JUMBO;
+ }
}
break;
case BGE_ASICREV_BCM5755:
@@ -4740,6 +4766,7 @@ bge_stats_update_regs(struct bge_softc *sc)
{
struct ifnet *ifp;
struct bge_mac_stats *stats;
+ uint32_t val;
ifp = sc->bge_ifp;
stats = &sc->bge_mac_stats;
@@ -4840,6 +4867,24 @@ bge_stats_update_regs(struct bge_softc *sc)
ifp->if_collisions = (u_long)stats->etherStatsCollisions;
ifp->if_ierrors = (u_long)(stats->NoMoreRxBDs + stats->InputDiscards +
stats->InputErrors);
+
+ if (sc->bge_flags & BGE_FLAG_RDMA_BUG) {
+ /*
+ * If controller transmitted more than BGE_NUM_RDMA_CHANNELS
+ * frames, it's safe to disable workaround for DMA engine's
+ * miscalculation of TXMBUF space.
+ */
+ if (stats->ifHCOutUcastPkts + stats->ifHCOutMulticastPkts +
+ stats->ifHCOutBroadcastPkts > BGE_NUM_RDMA_CHANNELS) {
+ val = CSR_READ_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL);
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5719)
+ val &= ~BGE_RDMA_TX_LENGTH_WA_5719;
+ else
+ val &= ~BGE_RDMA_TX_LENGTH_WA_5720;
+ CSR_WRITE_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL, val);
+ sc->bge_flags &= ~BGE_FLAG_RDMA_BUG;
+ }
+ }
}
static void
diff --git a/sys/dev/bge/if_bgereg.h b/sys/dev/bge/if_bgereg.h
index 6f9822e..8ed8432 100644
--- a/sys/dev/bge/if_bgereg.h
+++ b/sys/dev/bge/if_bgereg.h
@@ -1586,6 +1586,8 @@
#define BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_512 0x00020000
#define BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_4K 0x00030000
#define BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_LSO_4K 0x000C0000
+#define BGE_RDMA_TX_LENGTH_WA_5719 0x02000000
+#define BGE_RDMA_TX_LENGTH_WA_5720 0x00200000
/* BD Read DMA Mode register */
#define BGE_RDMA_BD_MODE 0x4A00
@@ -1603,6 +1605,9 @@
#define BGE_RDMA_NON_LSO_MODE_RESET 0x00000001
#define BGE_RDMA_NON_LSO_MODE_ENABLE 0x00000002
+#define BGE_RDMA_LENGTH 0x4BE0
+#define BGE_NUM_RDMA_CHANNELS 4
+
/*
* Write DMA control registers
*/
@@ -2972,6 +2977,7 @@ struct bge_softc {
#define BGE_FLAG_SHORT_DMA_BUG 0x08000000
#define BGE_FLAG_4K_RDMA_BUG 0x10000000
#define BGE_FLAG_MBOX_REORDER 0x20000000
+#define BGE_FLAG_RDMA_BUG 0x40000000
uint32_t bge_mfw_flags; /* Management F/W flags */
#define BGE_MFW_ON_RXCPU 0x00000001
#define BGE_MFW_ON_APE 0x00000002
OpenPOWER on IntegriCloud