svn commit: r214087 - head/sys/dev/bge
Pyun YongHyeon
yongari at FreeBSD.org
Tue Oct 19 23:04:24 UTC 2010
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
More information about the svn-src-all
mailing list