Module Name: src Committed By: rin Date: Wed Jan 30 11:13:26 UTC 2019
Modified Files: src/sys/dev/usb: if_axen.c if_axenreg.h Log Message: Fix HW checksum offloading. - Enable ones specified in if_capenable and remove AXEN_TOE macro. - Check correct bit and set appropriate csum_flags. - Pass packets of wrong checksum to upper layer instead of dropping them. - Fix value of AXEN_RXHDR_L3_TYPE_MASK. Tested on ASIX Elec. Corp. (0xb95) AX88179 (0x1790). To generate a diff of this commit: cvs rdiff -u -r1.18 -r1.19 src/sys/dev/usb/if_axen.c cvs rdiff -u -r1.3 -r1.4 src/sys/dev/usb/if_axenreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/if_axen.c diff -u src/sys/dev/usb/if_axen.c:1.18 src/sys/dev/usb/if_axen.c:1.19 --- src/sys/dev/usb/if_axen.c:1.18 Tue Jan 22 03:42:28 2019 +++ src/sys/dev/usb/if_axen.c Wed Jan 30 11:13:25 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axen.c,v 1.18 2019/01/22 03:42:28 msaitoh Exp $ */ +/* $NetBSD: if_axen.c,v 1.19 2019/01/30 11:13:25 rin Exp $ */ /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */ /* @@ -23,7 +23,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.18 2019/01/22 03:42:28 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.19 2019/01/30 11:13:25 rin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -70,8 +70,6 @@ int axendebug = 0; #define DPRINTFN(n,x) #endif -#define AXEN_TOE /* enable checksum offload function */ - /* * Various supported device vendors/products. */ @@ -98,6 +96,7 @@ static int axen_rx_list_init(struct axen static struct mbuf *axen_newbuf(void); static int axen_encap(struct axen_softc *, struct mbuf *, int); static void axen_rxeof(struct usbd_xfer *, void *, usbd_status); +static int axen_csum_flags_rx(struct ifnet *, uint32_t); static void axen_txeof(struct usbd_xfer *, void *, usbd_status); static void axen_tick(void *); static void axen_tick_task(void *); @@ -122,6 +121,7 @@ static void axen_lock_mii(struct axen_so static void axen_unlock_mii(struct axen_softc *); static void axen_ax88179_init(struct axen_softc *); +static void axen_setcoe(struct axen_softc *); /* Get exclusive access to the MII registers */ static void @@ -569,21 +569,7 @@ axen_ax88179_init(struct axen_softc *sc) /* Set RX/TX configuration. */ /* Offloadng enable */ -#ifdef AXEN_TOE - val = AXEN_RXCOE_IPv4 | AXEN_RXCOE_TCPv4 | AXEN_RXCOE_UDPv4 | - AXEN_RXCOE_TCPv6 | AXEN_RXCOE_UDPv6; -#else - val = AXEN_RXCOE_OFF; -#endif - axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); - -#ifdef AXEN_TOE - val = AXEN_TXCOE_IPv4 | AXEN_TXCOE_TCPv4 | AXEN_TXCOE_UDPv4 | - AXEN_TXCOE_TCPv6 | AXEN_TXCOE_UDPv6; -#else - val = AXEN_TXCOE_OFF; -#endif - axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val); + axen_setcoe(sc); /* Set RX control register */ ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB; @@ -633,6 +619,50 @@ axen_ax88179_init(struct axen_softc *sc) #endif } +static void +axen_setcoe(struct axen_softc *sc) +{ + struct ifnet *ifp = GET_IFP(sc); + uint64_t enabled = ifp->if_capenable; + uint8_t val; + + if (enabled & (IFCAP_CSUM_IPv4_Rx | + IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | + IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { + val = 0; + if (enabled & IFCAP_CSUM_IPv4_Rx) + val |= AXEN_RXCOE_IPv4; + if (enabled & IFCAP_CSUM_TCPv4_Rx) + val |= AXEN_RXCOE_TCPv4; + if (enabled & IFCAP_CSUM_UDPv4_Rx) + val |= AXEN_RXCOE_UDPv4; + if (enabled & IFCAP_CSUM_TCPv6_Rx) + val |= AXEN_RXCOE_TCPv6; + if (enabled & IFCAP_CSUM_UDPv6_Rx) + val |= AXEN_RXCOE_UDPv6; + } else + val = AXEN_RXCOE_OFF; + axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); + + if (enabled & (IFCAP_CSUM_IPv4_Tx | + IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | + IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx)) { + val = 0; + if (enabled & IFCAP_CSUM_IPv4_Tx) + val |= AXEN_TXCOE_IPv4; + if (enabled & IFCAP_CSUM_TCPv4_Tx) + val |= AXEN_TXCOE_TCPv4; + if (enabled & IFCAP_CSUM_UDPv4_Tx) + val |= AXEN_TXCOE_UDPv4; + if (enabled & IFCAP_CSUM_TCPv6_Tx) + val |= AXEN_TXCOE_TCPv6; + if (enabled & IFCAP_CSUM_UDPv6_Tx) + val |= AXEN_TXCOE_UDPv6; + } else + val = AXEN_TXCOE_OFF; + axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val); +} + static int axen_match(device_t parent, cfdata_t match, void *aux) { @@ -767,13 +797,11 @@ axen_attach(device_t parent, device_t se IFQ_SET_READY(&ifp->if_snd); sc->axen_ec.ec_capabilities = ETHERCAP_VLAN_MTU; -#ifdef AXEN_TOE ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx; -#endif /* Initialize MII/media info. */ mii = &sc->axen_mii; @@ -1079,27 +1107,7 @@ axen_rxeof(struct usbd_xfer *xfer, void m_set_rcvif(m, ifp); m->m_pkthdr.len = m->m_len = pkt_len - 6; -#ifdef AXEN_TOE - /* cheksum err */ - if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) || - (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) { - aprint_error_dev(sc->axen_dev, - "checksum err (pkt#%d)\n", pkt_count); - goto nextpkt; - } else { - m->m_pkthdr.csum_flags |= M_CSUM_IPv4; - } - - int l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> - AXEN_RXHDR_L4_TYPE_OFFSET; - - if ((l4_type == AXEN_RXHDR_L4_TYPE_TCP) || - (l4_type == AXEN_RXHDR_L4_TYPE_UDP)) { - m->m_pkthdr.csum_flags |= M_CSUM_TCPv4 | - M_CSUM_UDPv4; /* XXX v6? */ - } -#endif - + m->m_pkthdr.csum_flags = axen_csum_flags_rx(ifp, pkt_hdr); memcpy(mtod(m, char *), buf + 2, pkt_len - 6); /* push the packet up */ @@ -1131,6 +1139,51 @@ done: DPRINTFN(10,("%s: %s: start rx\n",device_xname(sc->axen_dev),__func__)); } +static int +axen_csum_flags_rx(struct ifnet *ifp, uint32_t pkt_hdr) +{ + int enabled_flags = ifp->if_csum_flags_rx; + int csum_flags = 0; + int l3_type, l4_type; + + if (enabled_flags == 0) + return 0; + + l3_type = (pkt_hdr & AXEN_RXHDR_L3_TYPE_MASK) >> + AXEN_RXHDR_L3_TYPE_OFFSET; + + if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) + csum_flags |= M_CSUM_IPv4; + + l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> + AXEN_RXHDR_L4_TYPE_OFFSET; + + switch (l4_type) { + case AXEN_RXHDR_L4_TYPE_TCP: + if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) + csum_flags |= M_CSUM_TCPv4; + else + csum_flags |= M_CSUM_TCPv6; + break; + case AXEN_RXHDR_L4_TYPE_UDP: + if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) + csum_flags |= M_CSUM_UDPv4; + else + csum_flags |= M_CSUM_UDPv6; + break; + default: + break; + } + + csum_flags &= enabled_flags; + if ((csum_flags & M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L3CSUM_ERR)) + csum_flags |= M_CSUM_IPv4_BAD; + if ((csum_flags & ~M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) + csum_flags |= M_CSUM_TCP_UDP_BAD; + + return csum_flags; +} + /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. @@ -1437,9 +1490,19 @@ axen_ioctl(struct ifnet *ifp, u_long cmd break; error = 0; - - if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) + switch(cmd) { + case SIOCADDMULTI: + case SIOCDELMULTI: axen_iff(sc); + break; + case SIOCSIFCAP: + axen_lock_mii(sc); + axen_setcoe(sc); + axen_unlock_mii(sc); + break; + default: + break; + } break; } splx(s); Index: src/sys/dev/usb/if_axenreg.h diff -u src/sys/dev/usb/if_axenreg.h:1.3 src/sys/dev/usb/if_axenreg.h:1.4 --- src/sys/dev/usb/if_axenreg.h:1.3 Sat Apr 23 10:15:31 2016 +++ src/sys/dev/usb/if_axenreg.h Wed Jan 30 11:13:25 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axenreg.h,v 1.3 2016/04/23 10:15:31 skrll Exp $ */ +/* $NetBSD: if_axenreg.h,v 1.4 2019/01/30 11:13:25 rin Exp $ */ /* $OpenBSD: if_axenreg.h,v 1.1 2013/10/07 05:37:41 yuo Exp $ */ /* @@ -72,7 +72,7 @@ #define AXEN_RXHDR_L4_TYPE_TCP 0x4 /* L3 packet type (2bit) */ -#define AXEN_RXHDR_L3_TYPE_MASK 0x00000600 +#define AXEN_RXHDR_L3_TYPE_MASK 0x00000060 #define AXEN_RXHDR_L3_TYPE_OFFSET 5 #define AXEN_RXHDR_L3_TYPE_UNDEF 0x0 #define AXEN_RXHDR_L3_TYPE_IPV4 0x1