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>
This commit is contained in:
Pyun YongHyeon 2013-07-17 04:53:53 +00:00
parent 92ad6ac7d4
commit 29b44b096f
2 changed files with 55 additions and 4 deletions

View File

@ -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

View File

@ -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