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;
 };
 

Reply via email to