On Fri, Jan 23, 2015 at 11:26:53AM +1000, David Gwynne wrote: > a compromise could be to advertise checksum offload to the stack, > pass it on to the hardware for small frames but have the driver do > it in software for the big ones?
greetings, below are two diffs. the first allows re(4) chips to handle checksums in software for large packets. this allows the chip to advertise hardware checksums for regular packets and do it manually for jumbos, which the the hardware cannot do properly (at least for 8168D and 8168E chips, which i've tested). the second diff is the same as the previous jumbo diff i sent through, but does not disable hw csums for the 8168D and 8168E chips. the first will do nothing without the second, but the diff's goals are different enough that two make sense. thanks dlg@ for the original concept and for hammering square pegs into my round brain. feedback appreciated. Index: re.c =================================================================== RCS file: /cvs/src/sys/dev/ic/re.c,v retrieving revision 1.175 diff -u -p -r1.175 re.c --- re.c 9 Feb 2015 03:09:57 -0000 1.175 +++ re.c 18 Feb 2015 01:35:32 -0000 @@ -128,6 +128,8 @@ #include <net/if_media.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> #include <netinet/if_ether.h> #if NVLAN > 0 @@ -194,6 +196,8 @@ void re_setup_intr(struct rl_softc *, in int re_wol(struct ifnet*, int); #endif +void in_delayed_cksum(struct mbuf *); + struct cfdriver re_cd = { 0, "re", DV_IFNET }; @@ -1601,7 +1605,10 @@ int re_encap(struct rl_softc *sc, struct mbuf *m, int *idx) { bus_dmamap_t map; + struct mbuf *mp, mh; int error, seg, nsegs, uidx, startidx, curidx, lastidx, pad; + int off; + struct ip *ip; struct rl_desc *d; u_int32_t cmdstat, vlanctl = 0, csum_flags = 0; struct rl_txq *txq; @@ -1618,6 +1625,27 @@ re_encap(struct rl_softc *sc, struct mbu * is requested. Otherwise, RL_TDESC_CMD_TCPCSUM/ * RL_TDESC_CMD_UDPCSUM does not take affect. */ + + if ((sc->rl_flags & RL_FLAG_JUMBOV2) && + m->m_pkthdr.len > RL_MTU && + (m->m_pkthdr.csum_flags & + (M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) != 0) { + mp = m_getptr(m, ETHER_HDR_LEN, &off); + mh.m_flags = 0; + mh.m_data = mtod(mp, caddr_t) + off; + mh.m_next = mp->m_next; + mh.m_pkthdr.len = mp->m_pkthdr.len - ETHER_HDR_LEN; + mh.m_len = mp->m_len - off; + ip = (struct ip *)mh.m_data; + + if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) + ip->ip_sum = in_cksum(&mh, sizeof(struct ip)); + if (m->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) + in_delayed_cksum(&mh); + + m->m_pkthdr.csum_flags &= + ~(M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT); + } if ((m->m_pkthdr.csum_flags & (M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) != 0) { Index: re.c =================================================================== RCS file: /cvs/src/sys/dev/ic/re.c,v retrieving revision 1.175 diff -u -p -r1.175 re.c --- re.c 9 Feb 2015 03:09:57 -0000 1.175 +++ re.c 18 Feb 2015 01:41:03 -0000 @@ -171,6 +171,8 @@ void re_watchdog(struct ifnet *); int re_ifmedia_upd(struct ifnet *); void re_ifmedia_sts(struct ifnet *, struct ifmediareq *); +void re_set_jumbo(struct rl_softc *); + void re_eeprom_putbyte(struct rl_softc *, int); void re_eeprom_getword(struct rl_softc *, int, u_int16_t *); void re_read_eeprom(struct rl_softc *, caddr_t, int, int); @@ -206,6 +208,10 @@ struct cfdriver re_cd = { CSR_WRITE_1(sc, RL_EECMD, \ CSR_READ_1(sc, RL_EECMD) & ~x) +#define RL_FRAMELEN(mtu) \ + (mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + \ + ETHER_VLAN_ENCAP_LEN) + static const struct re_revision { u_int32_t re_chipid; const char *re_name; @@ -1022,8 +1028,10 @@ re_attach(struct rl_softc *sc, const cha /* Create DMA maps for RX buffers */ for (i = 0; i < RL_RX_DESC_CNT; i++) { - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, - 0, 0, &sc->rl_ldata.rl_rxsoft[i].rxs_dmamap); + error = bus_dmamap_create(sc->sc_dmat, + RL_FRAMELEN(sc->rl_max_mtu), 1, + RL_FRAMELEN(sc->rl_max_mtu), 0, 0, + &sc->rl_ldata.rl_rxsoft[i].rxs_dmamap); if (error) { printf("%s: can't create DMA map for RX\n", sc->sc_dev.dv_xname); @@ -1038,8 +1046,7 @@ re_attach(struct rl_softc *sc, const cha ifp->if_ioctl = re_ioctl; ifp->if_start = re_start; ifp->if_watchdog = re_watchdog; - if ((sc->rl_flags & RL_FLAG_JUMBOV2) == 0) - ifp->if_hardmtu = sc->rl_max_mtu; + ifp->if_hardmtu = sc->rl_max_mtu; IFQ_SET_MAXLEN(&ifp->if_snd, RL_TX_QLEN); IFQ_SET_READY(&ifp->if_snd); @@ -1159,7 +1166,7 @@ re_newbuf(struct rl_softc *sc) u_int32_t cmdstat; int error, idx; - m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES); + m = MCLGETI(NULL, M_DONTWAIT, NULL, RL_FRAMELEN(sc->rl_max_mtu)); if (!m) return (ENOBUFS); @@ -1168,7 +1175,7 @@ re_newbuf(struct rl_softc *sc) * alignment so that the frame payload is * longword aligned on strict alignment archs. */ - m->m_len = m->m_pkthdr.len = RE_RX_DESC_BUFLEN; + m->m_len = m->m_pkthdr.len = RL_FRAMELEN(sc->rl_max_mtu); m->m_data += RE_ETHER_ALIGN; idx = sc->rl_ldata.rl_rx_prodidx; @@ -1307,8 +1314,12 @@ re_rxeof(struct rl_softc *sc) BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap); - if (!(rxstat & RL_RDESC_STAT_EOF)) { - m->m_len = RE_RX_DESC_BUFLEN; + if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 && + (rxstat & (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) != + (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) { + continue; + } else if (!(rxstat & RL_RDESC_STAT_EOF)) { + m->m_len = RL_FRAMELEN(sc->rl_max_mtu); if (sc->rl_head == NULL) sc->rl_head = sc->rl_tail = m; else { @@ -1342,8 +1353,9 @@ re_rxeof(struct rl_softc *sc) * 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)) { + if ((rxstat & RL_RDESC_STAT_RXERRSUM) != 0 && + !(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, @@ -1357,9 +1369,9 @@ re_rxeof(struct rl_softc *sc) } if (sc->rl_head != NULL) { - m->m_len = total_len % RE_RX_DESC_BUFLEN; + m->m_len = total_len % RL_FRAMELEN(sc->rl_max_mtu); if (m->m_len == 0) - m->m_len = RE_RX_DESC_BUFLEN; + m->m_len = RL_FRAMELEN(sc->rl_max_mtu); /* * Special case: if there's 4 bytes or less * in this buffer, the mbuf can be discarded: @@ -1914,6 +1926,9 @@ re_init(struct ifnet *ifp) htole32(*(u_int32_t *)(&eaddr.eaddr[0]))); CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); + if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) + re_set_jumbo(sc); + /* * For C+ mode, initialize the RX descriptors and mbufs. */ @@ -1977,7 +1992,8 @@ re_init(struct ifnet *ifp) * size so we can receive jumbo frames. */ if (sc->sc_hwrev != RL_HWREV_8139CPLUS) { - if (sc->rl_flags & RL_FLAG_PCIE) + if (sc->rl_flags & RL_FLAG_PCIE && + (sc->rl_flags & RL_FLAG_JUMBOV2) == 0) CSR_WRITE_2(sc, RL_MAXRXPKTLEN, RE_RX_DESC_BUFLEN); else CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383); @@ -2062,7 +2078,7 @@ re_ioctl(struct ifnet *ifp, u_long comma break; case SIOCGIFRXR: error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, - NULL, MCLBYTES, &sc->rl_ldata.rl_rx_ring); + NULL, RL_FRAMELEN(sc->rl_max_mtu), &sc->rl_ldata.rl_rx_ring); break; default: error = ether_ioctl(ifp, &sc->sc_arpcom, command, data); @@ -2280,6 +2296,29 @@ re_config_imtype(struct rl_softc *sc, in panic("%s: unknown imtype %d", sc->sc_dev.dv_xname, imtype); } +} + +void +re_set_jumbo(struct rl_softc *sc) +{ + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG); + CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) | + RL_CFG3_JUMBO_EN0); + + switch (sc->sc_hwrev) { + case RL_HWREV_8168DP: + break; + case RL_HWREV_8168E: + CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) | + RL_CFG4_8168E_JUMBO_EN1); + break; + default: + CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) | + RL_CFG4_JUMBO_EN1); + break; + } + + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); } void Index: rtl81x9reg.h =================================================================== RCS file: /cvs/src/sys/dev/ic/rtl81x9reg.h,v retrieving revision 1.91 diff -u -p -r1.91 rtl81x9reg.h --- rtl81x9reg.h 26 Jan 2015 09:58:47 -0000 1.91 +++ rtl81x9reg.h 18 Feb 2015 01:41:03 -0000 @@ -442,6 +442,7 @@ #define RL_CFG3_GRANTSEL 0x80 #define RL_CFG3_WOL_MAGIC 0x20 #define RL_CFG3_WOL_LINK 0x10 +#define RL_CFG3_JUMBO_EN0 0x04 #define RL_CFG3_FAST_B2B 0x01 /* @@ -449,6 +450,8 @@ */ #define RL_CFG4_LWPTN 0x04 #define RL_CFG4_LWPME 0x10 +#define RL_CFG4_JUMBO_EN1 0x02 +#define RL_CFG4_8168E_JUMBO_EN1 0x01 /* * Config 5 register @@ -742,8 +745,7 @@ struct rl_stats { #define RL_ADDR_LO(y) ((u_int64_t) (y) & 0xFFFFFFFF) #define RL_ADDR_HI(y) ((u_int64_t) (y) >> 32) -/* see comment in dev/ic/re.c */ -#define RL_JUMBO_FRAMELEN 7440 +#define RL_JUMBO_FRAMELEN (9 * 1024) #define RL_JUMBO_MTU_4K \ ((4 * 1024) - ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) #define RL_JUMBO_MTU_6K \