Module Name: src Committed By: rin Date: Thu Aug 30 09:00:08 UTC 2018
Modified Files: src/sys/dev/usb: if_mue.c if_muereg.h if_muevar.h Log Message: Support added for TCP segmentation offload (TSO). Improve TX performance around 10% if enabled. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/dev/usb/if_mue.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/usb/if_muereg.h \ src/sys/dev/usb/if_muevar.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_mue.c diff -u src/sys/dev/usb/if_mue.c:1.2 src/sys/dev/usb/if_mue.c:1.3 --- src/sys/dev/usb/if_mue.c:1.2 Mon Aug 27 14:59:04 2018 +++ src/sys/dev/usb/if_mue.c Thu Aug 30 09:00:08 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_mue.c,v 1.2 2018/08/27 14:59:04 rin Exp $ */ +/* $NetBSD: if_mue.c,v 1.3 2018/08/30 09:00:08 rin Exp $ */ /* $OpenBSD: if_mue.c,v 1.3 2018/08/04 16:42:46 jsg Exp $ */ /* @@ -20,7 +20,7 @@ /* Driver for Microchip LAN7500/LAN7800 chipsets. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.2 2018/08/27 14:59:04 rin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.3 2018/08/30 09:00:08 rin Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -49,8 +49,11 @@ __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1 #include <net/bpf.h> -#include <netinet/in.h> #include <netinet/if_inarp.h> +#include <netinet/in.h> +#include <netinet/ip.h> /* XXX for struct ip */ +#include <netinet/ip6.h> /* XXX for struct ip6_hdr */ +#include <netinet/tcp.h> /* XXX for struct tcphdr */ #include <dev/mii/mii.h> #include <dev/mii/miivar.h> @@ -145,6 +148,7 @@ static int mue_open_pipes(struct mue_sof static void mue_start_rx(struct mue_softc *); static int mue_encap(struct mue_softc *, struct mbuf *, int); +static void mue_tx_offload(struct mue_softc *, struct mbuf *); static void mue_setmulti(struct mue_softc *); static void mue_sethwcsum(struct mue_softc *); @@ -689,10 +693,10 @@ mue_chip_init(struct mue_softc *sc) if (sc->mue_flags & LAN7500) { if (sc->mue_udev->ud_speed == USB_SPEED_HIGH) - val = MUE_7500_HS_BUFSIZE / + val = MUE_7500_HS_RX_BUFSIZE / MUE_HS_USB_PKT_SIZE; else - val = MUE_7500_FS_BUFSIZE / + val = MUE_7500_FS_RX_BUFSIZE / MUE_FS_USB_PKT_SIZE; mue_csr_write(sc, MUE_7500_BURST_CAP, val); mue_csr_write(sc, MUE_7500_BULKIN_DELAY, @@ -709,7 +713,7 @@ mue_chip_init(struct mue_softc *sc) /* Init LTM. */ mue_init_ltm(sc); - val = MUE_7800_BUFSIZE; + val = MUE_7800_RX_BUFSIZE; switch (sc->mue_udev->ud_speed) { case USB_SPEED_SUPER: val /= MUE_SS_USB_PKT_SIZE; @@ -936,10 +940,11 @@ mue_attach(device_t parent, device_t sel /* Decide on what our bufsize will be. */ if (sc->mue_flags & LAN7500) - sc->mue_bufsz = (sc->mue_udev->ud_speed == USB_SPEED_HIGH) ? - MUE_7500_HS_BUFSIZE : MUE_7500_FS_BUFSIZE; + sc->mue_rxbufsz = (sc->mue_udev->ud_speed == USB_SPEED_HIGH) ? + MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; else - sc->mue_bufsz = MUE_7800_BUFSIZE; + sc->mue_rxbufsz = MUE_7800_RX_BUFSIZE; + sc->mue_txbufsz = MUE_TX_BUFSIZE; /* Find endpoints. */ id = usbd_get_interface_descriptor(sc->mue_iface); @@ -1003,6 +1008,8 @@ mue_attach(device_t parent, device_t sel IFQ_SET_READY(&ifp->if_snd); + ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6; + sc->mue_ec.ec_capabilities = ETHERCAP_VLAN_MTU; /* Initialize MII/media info. */ @@ -1120,7 +1127,7 @@ mue_rx_list_init(struct mue_softc *sc) c->mue_idx = i; if (c->mue_xfer == NULL) { err = usbd_create_xfer(sc->mue_ep[MUE_ENDPT_RX], - sc->mue_bufsz, 0, 0, &c->mue_xfer); + sc->mue_rxbufsz, 0, 0, &c->mue_xfer); if (err) return err; c->mue_buf = usbd_get_buffer(c->mue_xfer); @@ -1145,7 +1152,7 @@ mue_tx_list_init(struct mue_softc *sc) c->mue_idx = i; if (c->mue_xfer == NULL) { err = usbd_create_xfer(sc->mue_ep[MUE_ENDPT_TX], - sc->mue_bufsz, USBD_FORCE_SHORT_XFER, 0, + sc->mue_txbufsz, USBD_FORCE_SHORT_XFER, 0, &c->mue_xfer); if (err) return err; @@ -1186,7 +1193,7 @@ mue_start_rx(struct mue_softc *sc) /* Start up the receive pipe. */ for (i = 0; i < __arraycount(sc->mue_cdata.mue_rx_chain); i++) { c = &sc->mue_cdata.mue_rx_chain[i]; - usbd_setup_xfer(c->mue_xfer, c, c->mue_buf, sc->mue_bufsz, + usbd_setup_xfer(c->mue_xfer, c, c->mue_buf, sc->mue_rxbufsz, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, mue_rxeof); usbd_transfer(c->mue_xfer); } @@ -1205,14 +1212,28 @@ mue_encap(struct mue_softc *sc, struct m hdr.tx_cmd_a = htole32((m->m_pkthdr.len & MUE_TX_CMD_A_LEN_MASK) | MUE_TX_CMD_A_FCS); - /* Disable segmentation offload. */ - hdr.tx_cmd_b = htole32(0); + + if (m->m_pkthdr.csum_flags & (M_CSUM_TSOv4 | M_CSUM_TSOv6)) { + hdr.tx_cmd_a |= htole32(MUE_TX_CMD_A_LSO); + if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) + hdr.tx_cmd_b = htole32(m->m_pkthdr.segsz << + MUE_TX_CMD_B_MSS_SHIFT); + else + hdr.tx_cmd_b = htole32(MUE_TX_MSS_MIN << + MUE_TX_CMD_B_MSS_SHIFT); + hdr.tx_cmd_b &= htole32(MUE_TX_CMD_B_MSS_MASK); + mue_tx_offload(sc, m); + } else + hdr.tx_cmd_b = 0; + memcpy(c->mue_buf, &hdr, sizeof(hdr)); len = sizeof(hdr); m_copydata(m, 0, m->m_pkthdr.len, c->mue_buf + len); len += m->m_pkthdr.len; + KASSERT(len <= sc->mue_txbufsz); + usbd_setup_xfer(c->mue_xfer, c, c->mue_buf, len, USBD_FORCE_SHORT_XFER, 10000, mue_txeof); @@ -1230,6 +1251,52 @@ mue_encap(struct mue_softc *sc, struct m } static void +mue_tx_offload(struct mue_softc *sc, struct mbuf *m) +{ + struct ether_header *eh; + struct ip *ip; + struct ip6_hdr *ip6; + int offset; + bool v4; + + eh = mtod(m, struct ether_header *); + switch (htons(eh->ether_type)) { + case ETHERTYPE_IP: + case ETHERTYPE_IPV6: + offset = ETHER_HDR_LEN; + break; + case ETHERTYPE_VLAN: + /* XXX not yet supported */ + offset = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + break; + default: + /* XXX */ + panic("%s: unsupported ethertype\n", __func__); + /* NOTREACHED */ + } + + v4 = (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) != 0; + +#ifdef DIAGNOSTIC /* XXX */ + int hlen = offset; + if (v4) + hlen += M_CSUM_DATA_IPv4_IPHL(m->m_pkthdr.csum_data); + else + hlen += M_CSUM_DATA_IPv6_IPHL(m->m_pkthdr.csum_data); + KASSERT(m->m_len >= hlen + sizeof(struct tcphdr)); +#endif + + /* Packet length should be cleared. */ + if (v4) { + ip = (void *)(mtod(m, char *) + offset); + ip->ip_len = 0; + } else { + ip6 = (void *)(mtod(m, char *) + offset); + ip6->ip6_plen = 0; + } +} + +static void mue_setmulti(struct mue_softc *sc) { struct ifnet *ifp = GET_IFP(sc); @@ -1380,7 +1447,7 @@ mue_rxeof(struct usbd_xfer *xfer, void * usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); - if (__predict_false(total_len > sc->mue_bufsz)) { + if (__predict_false(total_len > sc->mue_rxbufsz)) { DPRINTF(sc, "too large transfer\n"); goto done; } @@ -1442,7 +1509,7 @@ mue_rxeof(struct usbd_xfer *xfer, void * done: /* Setup new transfer. */ - usbd_setup_xfer(xfer, c, c->mue_buf, sc->mue_bufsz, + usbd_setup_xfer(xfer, c, c->mue_buf, sc->mue_rxbufsz, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, mue_rxeof); usbd_transfer(xfer); } Index: src/sys/dev/usb/if_muereg.h diff -u src/sys/dev/usb/if_muereg.h:1.1 src/sys/dev/usb/if_muereg.h:1.2 --- src/sys/dev/usb/if_muereg.h:1.1 Sat Aug 25 20:12:22 2018 +++ src/sys/dev/usb/if_muereg.h Thu Aug 30 09:00:08 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_muereg.h,v 1.1 2018/08/25 20:12:22 rin Exp $ */ +/* $NetBSD: if_muereg.h,v 1.2 2018/08/30 09:00:08 rin Exp $ */ /* $OpenBSD: if_muereg.h,v 1.1 2018/08/03 01:50:15 kevlo Exp $ */ /* @@ -20,6 +20,15 @@ #ifndef _IF_MUEREG_H_ #define _IF_MUEREG_H_ +/* XXX for ETHER_HDR_LEN and ETHER_VLAN_ENCAP_LEN */ +#include <net/if_ether.h> + +/* XXX for IP_MAXPACKET */ +#include <netinet/ip.h> + +/* XXX for struct mue_txbuf_hdr */ +#include <dev/usb/if_muevar.h> + /* USB vendor requests */ #define MUE_UR_WRITEREG 0xa0 #define MUE_UR_READREG 0xa1 @@ -104,15 +113,17 @@ #define MUE_SS_USB_PKT_SIZE 1024 #define MUE_HS_USB_PKT_SIZE 512 #define MUE_FS_USB_PKT_SIZE 64 -#define MUE_7500_HS_BUFSIZE \ +#define MUE_7500_HS_RX_BUFSIZE \ (16 * 1024 + 5 * MUE_HS_USB_PKT_SIZE) -#define MUE_7500_FS_BUFSIZE \ +#define MUE_7500_FS_RX_BUFSIZE \ (6 * 1024 + 33 * MUE_FS_USB_PKT_SIZE) #define MUE_7500_MAX_RX_FIFO_SIZE (20 * 1024) #define MUE_7500_MAX_TX_FIFO_SIZE (12 * 1024) -#define MUE_7800_BUFSIZE (12 * 1024) -#define MUE_7800_MAX_RX_FIFO_SIZE MUE_7800_BUFSIZE -#define MUE_7800_MAX_TX_FIFO_SIZE MUE_7800_BUFSIZE +#define MUE_7800_RX_BUFSIZE (12 * 1024) +#define MUE_7800_MAX_RX_FIFO_SIZE MUE_7800_RX_BUFSIZE +#define MUE_7800_MAX_TX_FIFO_SIZE MUE_7800_RX_BUFSIZE +#define MUE_TX_BUFSIZE (sizeof(struct mue_txbuf_hdr) + \ + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + IP_MAXPACKET) /* interrupt endpoint control register */ #define MUE_INT_EP_CTL_PHY_INT 0x20000 Index: src/sys/dev/usb/if_muevar.h diff -u src/sys/dev/usb/if_muevar.h:1.1 src/sys/dev/usb/if_muevar.h:1.2 --- src/sys/dev/usb/if_muevar.h:1.1 Sat Aug 25 20:12:22 2018 +++ src/sys/dev/usb/if_muevar.h Thu Aug 30 09:00:08 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_muevar.h,v 1.1 2018/08/25 20:12:22 rin Exp $ */ +/* $NetBSD: if_muevar.h,v 1.2 2018/08/30 09:00:08 rin Exp $ */ /* $OpenBSD: if_muereg.h,v 1.1 2018/08/03 01:50:15 kevlo Exp $ */ /* @@ -55,8 +55,15 @@ struct mue_txbuf_hdr { uint32_t tx_cmd_a; #define MUE_TX_CMD_A_LEN_MASK 0x000fffff #define MUE_TX_CMD_A_FCS 0x00400000 +#define MUE_TX_CMD_A_TPE 0x02000000 +#define MUE_TX_CMD_A_IPE 0x04000000 +#define MUE_TX_CMD_A_LSO 0x08000000 uint32_t tx_cmd_b; +#define MUE_TX_MSS_MIN 8 +#define MUE_TX_CMD_B_MSS_SHIFT 16 +#define MUE_TX_CMD_B_MSS_MASK 0x3fff0000 + } __packed; struct mue_softc { @@ -99,7 +106,8 @@ struct mue_softc { krndsource_t mue_rnd_source; int mue_phyno; - uint32_t mue_bufsz; + uint32_t mue_rxbufsz; + uint32_t mue_txbufsz; int mue_link; };