summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2006-06-27 05:53:38 +0000
committerBrad Smith <brad@cvs.openbsd.org>2006-06-27 05:53:38 +0000
commit28681f35c10ccde86838726362d3371058e88e49 (patch)
treeb2a6c97bf963d00af9055d90d230dd5a5398ea16 /sys
parent2f21f98928d3d427c8cbc9db3fbeaee6de69d646 (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.c60
-rw-r--r--sys/dev/ic/rtl81x9reg.h11
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)