diff options
-rw-r--r-- | sys/dev/bge/if_bge.c | 38 | ||||
-rw-r--r-- | 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 d4440f8..433911f 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; @@ -1674,6 +1676,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. */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); @@ -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 55de003..d2216a1 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 */ |