Author: yongari
Date: Wed Jul 17 04:53:53 2013
New Revision: 253408
URL: http://svnweb.freebsd.org/changeset/base/253408

Log:
  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 <geans...@broadcom.com>
  Reviewed by:  Geans Pin <geans...@broadcom.com>

Modified:
  head/sys/dev/bge/if_bge.c
  head/sys/dev/bge/if_bgereg.h

Modified: head/sys/dev/bge/if_bge.c
==============================================================================
--- head/sys/dev/bge/if_bge.c   Wed Jul 17 02:37:40 2013        (r253407)
+++ head/sys/dev/bge/if_bge.c   Wed Jul 17 04:53:53 2013        (r253408)
@@ -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 *
 {
        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 *
        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

Modified: head/sys/dev/bge/if_bgereg.h
==============================================================================
--- head/sys/dev/bge/if_bgereg.h        Wed Jul 17 02:37:40 2013        
(r253407)
+++ head/sys/dev/bge/if_bgereg.h        Wed Jul 17 04:53:53 2013        
(r253408)
@@ -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
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to