summaryrefslogtreecommitdiffstats
path: root/sys/dev/re/if_re.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/re/if_re.c')
-rw-r--r--sys/dev/re/if_re.c70
1 files changed, 54 insertions, 16 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index e415557..888f8d6 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -104,8 +104,8 @@ __FBSDID("$FreeBSD$");
* interrupt moderation using the timer interrupt registers, which
* significantly reduces TX interrupt load. There is also support
* for jumbo frames, however the 8169/8169S/8110S can not transmit
- * jumbo frames larger than 7.5K, so the max MTU possible with this
- * driver is 7500 bytes.
+ * jumbo frames larger than 7440, so the max MTU possible with this
+ * driver is 7422 bytes.
*/
#include <sys/param.h>
@@ -203,6 +203,10 @@ static int re_allocmem (device_t, struct rl_softc *);
static int re_newbuf (struct rl_softc *, int, struct mbuf *);
static int re_rx_list_init (struct rl_softc *);
static int re_tx_list_init (struct rl_softc *);
+#ifdef RE_FIXUP_RX
+static __inline void re_fixup_rx
+ (struct mbuf *);
+#endif
static void re_rxeof (struct rl_softc *);
static void re_txeof (struct rl_softc *);
#ifdef DEVICE_POLLING
@@ -1371,14 +1375,20 @@ re_newbuf(sc, idx, m)
} else
m->m_data = m->m_ext.ext_buf;
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+#ifdef RE_FIXUP_RX
/*
- * 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 non-x86 platforms.
+ * The RealTek chip requires RX buffers to be aligned on 64-bit
+ * boundaries, but that will hose non-x86 machines. To get around
+ * this, we leave some empty space at the start of each buffer
+ * and for non-x86 hosts, 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
arg.sc = sc;
arg.rl_idx = idx;
arg.rl_maxsegs = 1;
@@ -1404,6 +1414,26 @@ re_newbuf(sc, idx, m)
return (0);
}
+#ifdef RE_FIXUP_RX
+static __inline void
+re_fixup_rx(m)
+ 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;
+
+ return;
+}
+#endif
+
static int
re_tx_list_init(sc)
struct rl_softc *sc;
@@ -1478,7 +1508,6 @@ re_rxeof(sc)
BUS_DMASYNC_POSTREAD);
while (!RL_OWN(&sc->rl_ldata.rl_rx_list[i])) {
-
cur_rx = &sc->rl_ldata.rl_rx_list[i];
m = sc->rl_ldata.rl_rx_mbuf[i];
total_len = RL_RXBYTES(cur_rx);
@@ -1494,7 +1523,7 @@ re_rxeof(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 {
@@ -1526,7 +1555,12 @@ re_rxeof(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,
@@ -1560,7 +1594,9 @@ re_rxeof(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:
@@ -1583,6 +1619,9 @@ re_rxeof(sc)
m->m_pkthdr.len = m->m_len =
(total_len - ETHER_CRC_LEN);
+#ifdef RE_FIXUP_RX
+ re_fixup_rx(m);
+#endif
ifp->if_ipackets++;
m->m_pkthdr.rcvif = ifp;
@@ -1858,8 +1897,8 @@ re_encap(sc, m_head, idx)
/*
* Set up checksum offload. Note: checksum offload bits must
* appear in all descriptors of a multi-descriptor transmit
- * attempt. (This is according to testing done with an 8169
- * chip. I'm not sure if this is a requirement or a bug.)
+ * attempt. This is according to testing done with an 8169
+ * chip. This is a requirement.
*/
arg.rl_flags = 0;
@@ -1913,7 +1952,7 @@ re_encap(sc, m_head, idx)
/*
* Insure that the map for this transmission
* is placed at the array index of the last descriptor
- * in this chain.
+ * in this chain. (Swap last and first dmamaps.)
*/
sc->rl_ldata.rl_tx_dmamap[*idx] =
sc->rl_ldata.rl_tx_dmamap[arg.rl_idx];
@@ -2177,7 +2216,6 @@ re_init_locked(sc)
* reloaded on each transmit. This gives us TX interrupt
* moderation, which dramatically improves TX frame rate.
*/
-
if (sc->rl_type == RL_8169)
CSR_WRITE_4(sc, RL_TIMERINT_8169, 0x800);
else
OpenPOWER on IntegriCloud