diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/re/if_re.c | 70 | ||||
-rw-r--r-- | sys/pci/if_rlreg.h | 19 |
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; |