Author: yongari
Date: Wed Nov  3 00:03:26 2010
New Revision: 214714
URL: http://svn.freebsd.org/changeset/base/214714

Log:
  MFC r214087,214219,214251,214292:
  r214087:
    Add workaround for BCM5906 controller silicon bug. If device
    receive two back-to-back send BDs with less than or equal to 8
    total bytes then the device may hang. The two back-to-back send
    BDs must be in the same frame for this failure to occur.
    Thanks to davidch for detailed errata information.
  
    Reviewed by:        davidch
  
  r214219:
    Add workaround for BCM5906 A1 controller silicon bug. When
    auto-negotiation results in half-duplex operation, excess collision
    on the ethernet link may cause internal chip delays that may result
    in subsequent valid frames being dropped due to insufficient
    receive buffer resources. The workaround is to choose de-pipeline
    method as a flow control decision for SDI. De-pipeline method
    allows only 1 data in TxMbuf at a time such that a request to RDMA
    from SDI is made only when TxMbuf is empty. Thanks for david for
    providing detailed errata information.
  
  r214251:
    Apply the same workaround for SDI flow control used on BCM5906 A1
    to BCM6906 A0/A2. This should fix a long standing BCM5906 A2 lockup
    issues. Data sheet explicitly mentions BCM5906 A0, A1 and A2 use
    de-pipelined mode on these revisions.
    Special thanks to Buganini who tried all combinations of
    experimental patches for more than 10 days.
  
    Tested by:  Buganini <buganini <> gmail dot com >
  
  r214292:
    Use bge_chipid to compare controller ids. r214251 incorrectly used
    bge_chiprev.
  
    Reported by:        Buganini <buganini <> gmail dot com >

Modified:
  stable/8/sys/dev/bge/if_bge.c
  stable/8/sys/dev/bge/if_bgereg.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/bge/if_bge.c
==============================================================================
--- stable/8/sys/dev/bge/if_bge.c       Tue Nov  2 23:56:35 2010        
(r214713)
+++ stable/8/sys/dev/bge/if_bge.c       Wed Nov  3 00:03:26 2010        
(r214714)
@@ -374,6 +374,7 @@ static void bge_tick(void *);
 static void bge_stats_clear_regs(struct bge_softc *);
 static void bge_stats_update(struct bge_softc *);
 static void bge_stats_update_regs(struct bge_softc *);
+static struct mbuf *bge_check_short_dma(struct mbuf *);
 static struct mbuf *bge_setup_tso(struct bge_softc *, struct mbuf *,
     uint16_t *);
 static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *);
@@ -1696,6 +1697,14 @@ bge_blockinit(struct bge_softc *sc)
                bge_writembx(sc, BGE_MBX_RX_MINI_PROD_LO, 0);
        }
 
+       /* Choose de-pipeline mode for BCM5906 A0, A1 and A2. */
+       if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
+               if (sc->bge_chipid == BGE_CHIPID_BCM5906_A0 ||
+                   sc->bge_chipid == BGE_CHIPID_BCM5906_A1 ||
+                   sc->bge_chipid == BGE_CHIPID_BCM5906_A2)
+                       CSR_WRITE_4(sc, BGE_ISO_PKT_TX,
+                           (CSR_READ_4(sc, BGE_ISO_PKT_TX) & ~3) | 2);
+       }
        /*
         * The BD ring replenish thresholds control how often the
         * hardware fetches new BD's from the producer rings in host
@@ -2637,6 +2646,8 @@ bge_attach(device_t dev)
        case BGE_ASICREV_BCM5752:
        case BGE_ASICREV_BCM5906:
                sc->bge_flags |= BGE_FLAG_575X_PLUS;
+               if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
+                       sc->bge_flags |= BGE_FLAG_SHORT_DMA_BUG;
                /* FALLTHROUGH */
        case BGE_ASICREV_BCM5705:
                sc->bge_flags |= BGE_FLAG_5705_PLUS;
@@ -4064,6 +4075,39 @@ bge_cksum_pad(struct mbuf *m)
 }
 
 static struct mbuf *
+bge_check_short_dma(struct mbuf *m)
+{
+       struct mbuf *n;
+       int found;
+
+       /*
+        * If device receive two back-to-back send BDs with less than
+        * or equal to 8 total bytes then the device may hang.  The two
+        * back-to-back send BDs must in the same frame for this failure
+        * to occur.  Scan mbuf chains and see whether two back-to-back
+        * send BDs are there. If this is the case, allocate new mbuf
+        * and copy the frame to workaround the silicon bug.
+        */
+       for (n = m, found = 0; n != NULL; n = n->m_next) {
+               if (n->m_len < 8) {
+                       found++;
+                       if (found > 1)
+                               break;
+                       continue;
+               }
+               found = 0;
+       }
+
+       if (found > 1) {
+               n = m_defrag(m, M_DONTWAIT);
+               if (n == NULL)
+                       m_freem(m);
+       } else
+               n = m;
+       return (n);
+}
+
+static struct mbuf *
 bge_setup_tso(struct bge_softc *sc, struct mbuf *m, uint16_t *mss)
 {
        struct ip *ip;
@@ -4136,6 +4180,13 @@ bge_encap(struct bge_softc *sc, struct m
        csum_flags = 0;
        mss = 0;
        vlan_tag = 0;
+       if ((sc->bge_flags & BGE_FLAG_SHORT_DMA_BUG) != 0 &&
+           m->m_next != NULL) {
+               *m_head = bge_check_short_dma(m);
+               if (*m_head == NULL)
+                       return (ENOBUFS);
+               m = *m_head;
+       }
        if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
                *m_head = m = bge_setup_tso(sc, m, &mss);
                if (*m_head == NULL)

Modified: stable/8/sys/dev/bge/if_bgereg.h
==============================================================================
--- stable/8/sys/dev/bge/if_bgereg.h    Tue Nov  2 23:56:35 2010        
(r214713)
+++ stable/8/sys/dev/bge/if_bgereg.h    Wed Nov  3 00:03:26 2010        
(r214714)
@@ -306,6 +306,7 @@
 #define        BGE_CHIPID_BCM5787_A0           0xb000
 #define        BGE_CHIPID_BCM5787_A1           0xb001
 #define        BGE_CHIPID_BCM5787_A2           0xb002
+#define        BGE_CHIPID_BCM5906_A0           0xc000
 #define        BGE_CHIPID_BCM5906_A1           0xc001
 #define        BGE_CHIPID_BCM5906_A2           0xc002
 #define        BGE_CHIPID_BCM57780_A0          0x57780000
@@ -880,6 +881,7 @@
 #define        BGE_SDI_STATS_CTL               0x0C08
 #define        BGE_SDI_STATS_ENABLE_MASK       0x0C0C
 #define        BGE_SDI_STATS_INCREMENT_MASK    0x0C10
+#define        BGE_ISO_PKT_TX                  0x0C20
 #define        BGE_LOCSTATS_COS0               0x0C80
 #define        BGE_LOCSTATS_COS1               0x0C84
 #define        BGE_LOCSTATS_COS2               0x0C88
@@ -2728,6 +2730,7 @@ struct bge_softc {
 #define        BGE_FLAG_40BIT_BUG      0x01000000
 #define        BGE_FLAG_4G_BNDRY_BUG   0x02000000
 #define        BGE_FLAG_RX_ALIGNBUG    0x04000000
+#define        BGE_FLAG_SHORT_DMA_BUG  0x08000000
        uint32_t                bge_phy_flags;
 #define        BGE_PHY_WIRESPEED       0x00000001
 #define        BGE_PHY_ADC_BUG         0x00000002
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to