From e255b776bcc2db5d4643aa998867543dbd71cd0b Mon Sep 17 00:00:00 2001 From: John Polstra Date: Mon, 24 Jun 2002 22:04:15 +0000 Subject: [PATCH] Work around what appears to be a chip bug in the BCM5701 that shows up when operating in PCI-X mode. For some received packets there is data corruption in the first few bytes in that case. Aligning the packet buffer eliminates the corruption. With this fix, the code that offsets the packet buffer up by 2 bytes to align the payload is disabled for BCM5701s operating in PCI-X mode. On the i386, which permits unaligned accesses, the payload is left unaligned. On other platforms, the packet is copied after reception to force alignment of the payload. Obviously, this work-around reduces performance in those cases (BCM5701 plus PCI-X) where it is in effect. MFC after: 3 days --- sys/dev/bge/if_bge.c | 38 ++++++++++++++++++++++++++++++++++++-- sys/dev/bge/if_bgereg.h | 1 + 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index d4440f89cbb..433911f583f 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -725,7 +725,8 @@ bge_newbuf_std(sc, i, m) m_new->m_data = m_new->m_ext.ext_buf; } - m_adj(m_new, ETHER_ALIGN); + if (!sc->bge_rx_alignment_bug) + m_adj(m_new, ETHER_ALIGN); sc->bge_cdata.bge_rx_std_chain[i] = m_new; r = &sc->bge_rdata->bge_rx_std_ring[i]; BGE_HOSTADDR(r->bge_addr) = vtophys(mtod(m_new, caddr_t)); @@ -778,7 +779,8 @@ bge_newbuf_jumbo(sc, i, m) m_new->m_ext.ext_size = BGE_JUMBO_FRAMELEN; } - m_adj(m_new, ETHER_ALIGN); + if (!sc->bge_rx_alignment_bug) + m_adj(m_new, ETHER_ALIGN); /* Set up the descriptor. */ r = &sc->bge_rdata->bge_rx_jumbo_ring[i]; sc->bge_cdata.bge_rx_jumbo_chain[i] = m_new; @@ -1673,6 +1675,27 @@ bge_attach(dev) } } + /* + * When using the BCM5701 in PCI-X mode, data corruption has + * been observed in the first few bytes of some received packets. + * Aligning the packet buffer in memory eliminates the corruption. + * Unfortunately, this misaligns the packet payloads. On platforms + * which do not support unaligned accesses, we will realign the + * payloads by copying the received packets. + */ + switch (sc->bge_asicrev) { + case BGE_ASICREV_BCM5701_A0: + case BGE_ASICREV_BCM5701_B0: + case BGE_ASICREV_BCM5701_B2: + case BGE_ASICREV_BCM5701_B5: + /* If in PCI-X mode, work around the alignment bug. */ + if ((pci_read_config(dev, BGE_PCI_PCISTATE, 4) & + (BGE_PCISTATE_PCI_BUSMODE | BGE_PCISTATE_PCI_BUSSPEED)) == + BGE_PCISTATE_PCI_BUSSPEED) + sc->bge_rx_alignment_bug = 1; + break; + } + /* * Call MI attach routine. */ @@ -1905,6 +1928,17 @@ bge_rxeof(sc) } ifp->if_ipackets++; +#ifndef __i386__ + /* + * The i386 allows unaligned accesses, but for other + * platforms we must make sure the payload is aligned. + */ + if (sc->bge_rx_alignment_bug) { + bcopy(m->m_data, m->m_data + ETHER_ALIGN, + cur_rx->bge_len); + m->m_data += ETHER_ALIGN; + } +#endif eh = mtod(m, struct ether_header *); m->m_pkthdr.len = m->m_len = cur_rx->bge_len; m->m_pkthdr.rcvif = ifp; diff --git a/sys/dev/bge/if_bgereg.h b/sys/dev/bge/if_bgereg.h index 55de0038525..d2216a1022e 100644 --- a/sys/dev/bge/if_bgereg.h +++ b/sys/dev/bge/if_bgereg.h @@ -2131,6 +2131,7 @@ struct bge_softc { u_int8_t bge_unit; /* interface number */ u_int8_t bge_extram; /* has external SSRAM */ u_int8_t bge_tbi; + u_int8_t bge_rx_alignment_bug; u_int32_t bge_asicrev; struct bge_ring_data *bge_rdata; /* rings */ struct bge_chain_data bge_cdata; /* mbufs */