diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2006-06-27 05:53:38 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2006-06-27 05:53:38 +0000 |
commit | 28681f35c10ccde86838726362d3371058e88e49 (patch) | |
tree | b2a6c97bf963d00af9055d90d230dd5a5398ea16 /sys | |
parent | 2f21f98928d3d427c8cbc9db3fbeaee6de69d646 (diff) |
- add fixup code in the RX path for strict alignment architectures.
- add a workaround for reception of Jumbo frames.
- don't try to adjust alignment on non-strict alignment architectures,
this resolves an issue with the PCI Express adapters.
From FreeBSD
ok drahn@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/re.c | 60 | ||||
-rw-r--r-- | sys/dev/ic/rtl81x9reg.h | 11 |
2 files changed, 59 insertions, 12 deletions
diff --git a/sys/dev/ic/re.c b/sys/dev/ic/re.c index 86cb8ae58cd..23bda1f56c5 100644 --- a/sys/dev/ic/re.c +++ b/sys/dev/ic/re.c @@ -1,4 +1,4 @@ -/* $OpenBSD: re.c,v 1.28 2006/06/24 02:36:15 brad Exp $ */ +/* $OpenBSD: re.c,v 1.29 2006/06/27 05:53:37 brad Exp $ */ /* $FreeBSD: if_re.c,v 1.31 2004/09/04 07:54:05 ru Exp $ */ /* * Copyright (c) 1997, 1998-2003 @@ -161,6 +161,9 @@ int re_allocmem(struct rl_softc *); int re_newbuf(struct rl_softc *, int, struct mbuf *); int re_rx_list_init(struct rl_softc *); int re_tx_list_init(struct rl_softc *); +#ifdef __STRICT_ALIGNMENT +void re_fixup_rx(struct mbuf *); +#endif void re_rxeof(struct rl_softc *); void re_txeof(struct rl_softc *); int re_intr(void *); @@ -946,13 +949,21 @@ re_newbuf(struct rl_softc *sc, int idx, struct mbuf *m) } else m->m_data = m->m_ext.ext_buf; + m->m_len = m->m_pkthdr.len = MCLBYTES; +#ifdef __STRICT_ALIGNMENT /* - * Initialize mbuf length fields and fixup - * alignment so that the frame payload is - * longword aligned. + * This is part of an evil trick to deal with strict alignment + * architectures. The RealTek chip requires RX buffers to be + * aligned on 64-bit boundaries, but that will hose strict + * alignment architectures. To get around this, we leave some + * empty space at the start of each buffer and for strict + * alignment architectures, we copy the buffer back six + * bytes to achieve word alignment. This is slightly more + * efficient than allocating a new buffer, copying the + * contents, and discarding the old buffer. */ - m->m_len = m->m_pkthdr.len = MCLBYTES; - m_adj(m, ETHER_ALIGN); + m_adj(m, RE_ETHER_ALIGN); +#endif map = sc->rl_ldata.rl_rx_dmamap[idx]; error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT); @@ -990,6 +1001,23 @@ out: return (ENOMEM); } +#ifdef __STRICT_ALIGNMENT +void +re_fixup_rx(struct mbuf *m) +{ + int i; + uint16_t *src, *dst; + + src = mtod(m, uint16_t *); + dst = src - (RE_ETHER_ALIGN - ETHER_ALIGN) / sizeof *src; + + for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) + *dst++ = *src++; + + m->m_data -= RE_ETHER_ALIGN - ETHER_ALIGN; +} +#endif + int re_tx_list_init(struct rl_softc *sc) { @@ -1074,7 +1102,7 @@ re_rxeof(struct rl_softc *sc) sc->rl_ldata.rl_rx_dmamap[i]); if (!(rxstat & RL_RDESC_STAT_EOF)) { - m->m_len = MCLBYTES - ETHER_ALIGN; + m->m_len = RE_RX_DESC_BUFLEN; if (sc->rl_head == NULL) sc->rl_head = sc->rl_tail = m; else { @@ -1106,7 +1134,12 @@ re_rxeof(struct rl_softc *sc) if (sc->rl_type == RL_8169) rxstat >>= 1; - if (rxstat & RL_RDESC_STAT_RXERRSUM) { + /* + * if total_len > 2^13-1, both _RXERRSUM and _GIANT will be + * set, but if CRC is clear, it will still be a valid frame. + */ + if (rxstat & RL_RDESC_STAT_RXERRSUM && !(total_len > 8191 && + (rxstat & RL_RDESC_STAT_ERRS) == RL_RDESC_STAT_GIANT)) { ifp->if_ierrors++; /* * If this is part of a multi-fragment packet, @@ -1140,7 +1173,9 @@ re_rxeof(struct rl_softc *sc) RL_DESC_INC(i); if (sc->rl_head != NULL) { - m->m_len = total_len % (MCLBYTES - ETHER_ALIGN); + m->m_len = total_len % RE_RX_DESC_BUFLEN; + if (m->m_len == 0) + m->m_len = RE_RX_DESC_BUFLEN; /* * Special case: if there's 4 bytes or less * in this buffer, the mbuf can be discarded: @@ -1163,6 +1198,9 @@ re_rxeof(struct rl_softc *sc) m->m_pkthdr.len = m->m_len = (total_len - ETHER_CRC_LEN); +#ifdef __STRICT_ALIGNMENT + re_fixup_rx(m); +#endif ifp->if_ipackets++; m->m_pkthdr.rcvif = ifp; @@ -1326,8 +1364,8 @@ re_intr(void *arg) } } - if (!IFQ_IS_EMPTY(&ifp->if_snd)) - (*ifp->if_start)(ifp); + if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) + re_start(ifp); return (claimed); } diff --git a/sys/dev/ic/rtl81x9reg.h b/sys/dev/ic/rtl81x9reg.h index f3c056b1918..fbbbba8a8fd 100644 --- a/sys/dev/ic/rtl81x9reg.h +++ b/sys/dev/ic/rtl81x9reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rtl81x9reg.h,v 1.21 2005/09/17 00:45:44 brad Exp $ */ +/* $OpenBSD: rtl81x9reg.h,v 1.22 2006/06/27 05:53:37 brad Exp $ */ /* * Copyright (c) 1997, 1998 @@ -527,6 +527,8 @@ struct rl_desc { #define RL_RDESC_STAT_TCPSUMBAD 0x00002000 /* TCP checksum bad */ #define RL_RDESC_STAT_FRAGLEN 0x00001FFF /* RX'ed frame/frag len */ #define RL_RDESC_STAT_GFRAGLEN 0x00003FFF /* RX'ed frame/frag len */ +#define RL_RDESC_STAT_ERRS (RL_RDESC_STAT_GIANT|RL_RDESC_STAT_RUNT| \ + RL_RDESC_STAT_CRCERR) #define RL_RDESC_VLANCTL_TAG 0x00010000 /* VLAN tag available (rl_vlandata valid)*/ @@ -573,6 +575,13 @@ struct rl_stats { #define RL_OWN(x) (letoh32((x)->rl_cmdstat) & RL_RDESC_STAT_OWN) #define RL_RXBYTES(x) (letoh32((x)->rl_cmdstat) & sc->rl_rxlenmask) #define RL_PKTSZ(x) ((x)/* >> 3*/) +#ifdef __STRICT_ALIGNMENT +#define RE_ETHER_ALIGN sizeof(uint64_t) +#define RE_RX_DESC_BUFLEN (MCLBYTES - RE_ETHER_ALIGN) +#else +#define RE_ETHER_ALIGN 0 +#define RE_RX_DESC_BUFLEN MCLBYTES +#endif #define RL_ADDR_LO(y) ((u_int64_t) (y) & 0xFFFFFFFF) #define RL_ADDR_HI(y) ((u_int64_t) (y) >> 32) |