Author: yongari
Date: Tue Oct 19 23:04:23 2010
New Revision: 214087
URL: http://svn.freebsd.org/changeset/base/214087

Log:
  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

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   Tue Oct 19 22:11:50 2010        (r214086)
+++ head/sys/dev/bge/if_bge.c   Tue Oct 19 23:04:23 2010        (r214087)
@@ -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 *);
@@ -2633,6 +2634,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;
@@ -4060,6 +4063,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;
@@ -4132,6 +4168,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: head/sys/dev/bge/if_bgereg.h
==============================================================================
--- head/sys/dev/bge/if_bgereg.h        Tue Oct 19 22:11:50 2010        
(r214086)
+++ head/sys/dev/bge/if_bgereg.h        Tue Oct 19 23:04:23 2010        
(r214087)
@@ -2727,6 +2727,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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to