Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Support added for TCP segmentation offload (TSO).



details:   https://anonhg.NetBSD.org/src/rev/d8be1f2879fc
branches:  trunk
changeset: 366502:d8be1f2879fc
user:      rin <rin%NetBSD.org@localhost>
date:      Thu Aug 30 09:00:08 2018 +0000

description:
Support added for TCP segmentation offload (TSO).
Improve TX performance around 10% if enabled.

diffstat:

 sys/dev/usb/if_mue.c    |  99 +++++++++++++++++++++++++++++++++++++++++-------
 sys/dev/usb/if_muereg.h |  23 ++++++++--
 sys/dev/usb/if_muevar.h |  12 ++++-
 3 files changed, 110 insertions(+), 24 deletions(-)

diffs (297 lines):

diff -r 9b8750459c9b -r d8be1f2879fc sys/dev/usb/if_mue.c
--- a/sys/dev/usb/if_mue.c      Thu Aug 30 05:39:21 2018 +0000
+++ b/sys/dev/usb/if_mue.c      Thu Aug 30 09:00:08 2018 +0000
@@ -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 @@
 
 #include <net/bpf.h>
 
+#include <netinet/if_inarp.h>
 #include <netinet/in.h>
-#include <netinet/if_inarp.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 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 @@
 
        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 @@
                /* 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 @@
 
        /* 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 @@
 
        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 @@
                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 @@
                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 @@
        /* 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 @@
 
        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 @@
 }
 
 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 @@
 
        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 @@
 
 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);
 }
diff -r 9b8750459c9b -r d8be1f2879fc sys/dev/usb/if_muereg.h
--- a/sys/dev/usb/if_muereg.h   Thu Aug 30 05:39:21 2018 +0000
+++ b/sys/dev/usb/if_muereg.h   Thu Aug 30 09:00:08 2018 +0000
@@ -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
diff -r 9b8750459c9b -r d8be1f2879fc sys/dev/usb/if_muevar.h
--- a/sys/dev/usb/if_muevar.h   Thu Aug 30 05:39:21 2018 +0000
+++ b/sys/dev/usb/if_muevar.h   Thu Aug 30 09:00:08 2018 +0000
@@ -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 @@
        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 @@
        krndsource_t            mue_rnd_source;
 
        int                     mue_phyno;
-       uint32_t                mue_bufsz;
+       uint32_t                mue_rxbufsz;
+       uint32_t                mue_txbufsz;
        int                     mue_link;
 };
 



Home | Main Index | Thread Index | Old Index