summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjmg <jmg@FreeBSD.org>2004-09-28 18:22:24 +0000
committerjmg <jmg@FreeBSD.org>2004-09-28 18:22:24 +0000
commitdf6cea827e6bb56b0b7cf961cf62e12be512eccc (patch)
tree18b0ecec96ea50f178801292de9c7d28b0bfa568 /sys
parent0c8b421dcdab9f5003f1e2f336b92e61bfd706ec (diff)
downloadFreeBSD-src-df6cea827e6bb56b0b7cf961cf62e12be512eccc.zip
FreeBSD-src-df6cea827e6bb56b0b7cf961cf62e12be512eccc.tar.gz
fix jumbo frames as much as they can be fixed for re. We now cap the MTU
to 7422 since it appears that the 8169S can't transmit anything larger.. The 8169S can receive full jumbo frames, but we don't have an mru to let the upper layers know this... add fixup so that this driver should work on alignment constrained platforms (!i386 && !amd64) MFC after: 5 days
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/re/if_re.c70
-rw-r--r--sys/pci/if_rlreg.h19
2 files changed, 72 insertions, 17 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
diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h
index c8120c7..a96dc2a 100644
--- a/sys/pci/if_rlreg.h
+++ b/sys/pci/if_rlreg.h
@@ -567,6 +567,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)*/
@@ -607,7 +609,14 @@ struct rl_stats {
* Rx/Tx descriptor parameters (8139C+ and 8169 only)
*
* Tx/Rx count must be equal. Shared code like re_dma_map_desc assumes this.
+ * Buffers must be a multiple of 8 bytes. Currently limit to 64 descriptors
+ * due to the 8139C+. We need to put the number of descriptors in the ring
+ * structure and use that value instead.
*/
+#if !defined(__i386__) && !defined(__amd64__)
+#define RE_FIXUP_RX 1
+#endif
+
#define RL_TX_DESC_CNT 64
#define RL_RX_DESC_CNT RL_TX_DESC_CNT
#define RL_RX_LIST_SZ (RL_RX_DESC_CNT * sizeof(struct rl_desc))
@@ -618,11 +627,19 @@ struct rl_stats {
#define RL_OWN(x) (le32toh((x)->rl_cmdstat) & RL_RDESC_STAT_OWN)
#define RL_RXBYTES(x) (le32toh((x)->rl_cmdstat) & sc->rl_rxlenmask)
#define RL_PKTSZ(x) ((x)/* >> 3*/)
+#ifdef RE_FIXUP_RX
+#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) ((uint64_t) (y) & 0xFFFFFFFF)
#define RL_ADDR_HI(y) ((uint64_t) (y) >> 32)
-#define RL_JUMBO_FRAMELEN 9018
+/* see comment in dev/re/if_re.c */
+#define RL_JUMBO_FRAMELEN 7440
#define RL_JUMBO_MTU (RL_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
struct rl_softc;
OpenPOWER on IntegriCloud