Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Fix receive loop, enable turbo mode, checksum of...



details:   https://anonhg.NetBSD.org/src/rev/3652bc7c1871
branches:  trunk
changeset: 796550:3652bc7c1871
user:      mlelstv <mlelstv%NetBSD.org@localhost>
date:      Mon Jun 09 14:18:28 2014 +0000

description:
Fix receive loop, enable turbo mode, checksum offloading still needs
correct handling of pseudo headers.

The Raspberry PI now copies at 2MByte/s with scp and 4MByte/s with NFS.

Based on work from nick@.

diffstat:

 sys/dev/usb/if_smsc.c    |  124 +++++++++++++++++++++++++++++++++++-----------
 sys/dev/usb/if_smscreg.h |    5 +-
 sys/dev/usb/if_smscvar.h |    4 +-
 3 files changed, 100 insertions(+), 33 deletions(-)

diffs (299 lines):

diff -r aa38f66f3556 -r 3652bc7c1871 sys/dev/usb/if_smsc.c
--- a/sys/dev/usb/if_smsc.c     Mon Jun 09 13:03:16 2014 +0000
+++ b/sys/dev/usb/if_smsc.c     Mon Jun 09 14:18:28 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_smsc.c,v 1.12 2013/11/01 14:24:03 skrll Exp $       */
+/*     $NetBSD: if_smsc.c,v 1.13 2014/06/09 14:18:28 mlelstv Exp $     */
 
 /*     $OpenBSD: if_smsc.c,v 1.4 2012/09/27 12:38:11 jsg Exp $ */
 /* $FreeBSD: src/sys/dev/usb/net/if_smsc.c,v 1.1 2012/08/15 04:03:55 gonzo Exp $ */
@@ -108,6 +108,7 @@
 int smsc_debug = 0;
 #endif
 
+#define ETHER_ALIGN 2
 /*
  * Various supported device vendors/products.
  */
@@ -481,17 +482,19 @@
        }
 
        /* Enable/disable the Rx checksum */
-       if (ifp->if_capabilities & IFCAP_CSUM_IPv4_Rx)
-               val |= SMSC_COE_CTRL_RX_EN;
+       if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx|IFCAP_CSUM_UDPv4_Rx))
+               val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE);
        else
-               val &= ~SMSC_COE_CTRL_RX_EN;
+               val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE);
 
        /* Enable/disable the Tx checksum (currently not supported) */
-       if (ifp->if_capabilities & IFCAP_CSUM_IPv4_Tx)
+       if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_UDPv4_Tx))
                val |= SMSC_COE_CTRL_TX_EN;
        else
                val &= ~SMSC_COE_CTRL_TX_EN;
 
+       sc->sc_coe_ctrl = val;
+
        err = smsc_write_reg(sc, SMSC_COE_CTRL, val);
        if (err != 0) {
                smsc_warn_printf(sc, "failed to write SMSC_COE_CTRL (err=%d)\n",
@@ -573,6 +576,9 @@
        /* Load the multicast filter. */
        smsc_setmulti(sc);
 
+       /* TCP/UDP checksum offload engines. */
+       smsc_sethwcsum(sc);
+
        /* Open RX and TX pipes. */
        err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[SMSC_ENDPT_RX],
            USBD_EXCLUSIVE_USE, &sc->sc_ep[SMSC_ENDPT_RX]);
@@ -602,9 +608,6 @@
                usbd_transfer(c->sc_xfer);
        }
 
-       /* TCP/UDP checksum offload engines. */
-       smsc_sethwcsum(sc);
-
        /* Indicate we are up and running. */
        ifp->if_flags |= IFF_RUNNING;
        ifp->if_flags &= ~IFF_OACTIVE;
@@ -808,14 +811,11 @@
         * Burst capability is the number of URBs that can be in a burst of
         * data/ethernet frames.
         */
-#ifdef SMSC_TURBO
+
        if (sc->sc_udev->speed == USB_SPEED_HIGH)
                burst_cap = 37;
        else
                burst_cap = 128;
-#else
-       burst_cap = 0;
-#endif
 
        smsc_write_reg(sc, SMSC_BURST_CAP, burst_cap);
 
@@ -835,9 +835,14 @@
         * The following settings are used for 'turbo mode', a.k.a multiple
         * frames per Rx transaction (again info taken form Linux driver).
         */
-#ifdef SMSC_TURBO
-       reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE);
-#endif
+       if (burst_cap)
+               reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE);
+
+       /*               
+        * set Rx data offset to ETHER_ALIGN which will make the IP header
+        * align on a word boundary.
+       */              
+       reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT;
 
        smsc_write_reg(sc, SMSC_HW_CFG, reg_val);
 
@@ -868,6 +873,9 @@
                goto init_failed;
        }
 
+       /* disable pad stripping, collides with checksum offload */
+       sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR;
+
        /* Vlan */
        smsc_write_reg(sc, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN);
 
@@ -1043,6 +1051,15 @@
        ifp->if_start = smsc_start;
        ifp->if_stop = smsc_stop;
 
+#ifdef notyet
+       /*
+        * We can do TCPv4, and UDPv4 checksums in hardware.
+        */
+       ifp->if_capabilities |=
+           /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx |
+           /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx;
+#endif
+
         sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU;
 
        /* Setup some of the basics */
@@ -1238,10 +1255,10 @@
        struct ifnet            *ifp = &sc->sc_ec.ec_if;
        u_char                  *buf = c->sc_buf;
        uint32_t                total_len;
-       uint16_t                pktlen = 0;
+       uint32_t                rxhdr;
+       uint16_t                pktlen;
        struct mbuf             *m;
        int                     s;
-       uint32_t                rxhdr;
 
        if (sc->sc_dying)
                return;
@@ -1264,7 +1281,7 @@
        usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
        smsc_dbg_printf(sc, "xfer status total_len %d\n", total_len);
 
-       do {
+       while (total_len != 0) {
                if (total_len < sizeof(rxhdr)) {
                        smsc_dbg_printf(sc, "total_len %d < sizeof(rxhdr) %zu\n",
                            total_len, sizeof(rxhdr));
@@ -1272,10 +1289,9 @@
                        goto done;
                }
 
-               buf += pktlen;
-
                memcpy(&rxhdr, buf, sizeof(rxhdr));
                rxhdr = le32toh(rxhdr);
+               buf += sizeof(rxhdr);
                total_len -= sizeof(rxhdr);
 
                if (rxhdr & SMSC_RX_STAT_ERROR) {
@@ -1287,6 +1303,9 @@
                pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr);
                smsc_dbg_printf(sc, "rxeof total_len %d pktlen %d rxhdr "
                    "0x%08x\n", total_len, pktlen, rxhdr);
+
+               pktlen += ETHER_ALIGN;
+
                if (pktlen > total_len) {
                        smsc_dbg_printf(sc, "pktlen %d > total_len %d\n",
                            pktlen, total_len);
@@ -1294,9 +1313,6 @@
                        goto done;
                }
 
-               buf += sizeof(rxhdr);
-               total_len -= pktlen;
-
                m = smsc_newbuf();
                if (m == NULL) {
                        smsc_dbg_printf(sc, "smc_newbuf returned NULL\n");
@@ -1306,25 +1322,71 @@
 
                ifp->if_ipackets++;
                m->m_pkthdr.rcvif = ifp;
+               m->m_pkthdr.len = m->m_len = pktlen;
+               m->m_flags |= M_HASFCS;
+               m_adj(m, ETHER_ALIGN);
+               memcpy(mtod(m, char *), buf + ETHER_ALIGN, m->m_len);
 
-               pktlen -= 2;    // JDM
+               /* Check if RX TCP/UDP checksumming is being offloaded */
+               if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) {
+                       smsc_dbg_printf(sc,"RX checksum offload checking\n");
+                       struct ether_header *eh;
+
+                       eh = mtod(m, struct ether_header *);
+
+                       /* Remove the extra 2 bytes of the csum */
+                       m_adj(m, -2);
 
-               m->m_pkthdr.len = m->m_len = pktlen;
-#define ETHER_ALIGN 2
-               m_adj(m, ETHER_ALIGN);
+                       /*
+                        * The checksum appears to be simplistically calculated
+                        * over the udp/tcp header and data up to the end of the
+                        * eth frame.  Which means if the eth frame is padded
+                        * the csum calculation is incorrectly performed over
+                        * the padding bytes as well. Therefore to be safe we
+                        * ignore the H/W csum on frames less than or equal to
+                        * 64 bytes.
+                        *
+                        * Ignore H/W csum for non-IPv4 packets.
+                        */
+                       smsc_dbg_printf(sc,"Ethertype %02x pktlen %02x\n",
+                          be16toh(eh->ether_type), pktlen);
+                       if (be16toh(eh->ether_type) == ETHERTYPE_IP &&
+                          pktlen > ETHER_MIN_LEN) {
+
+                               m->m_pkthdr.csum_flags |=
+                                  (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA);
 
-               memcpy(mtod(m, char *), buf, pktlen);
+                               /*
+                                * Copy the TCP/UDP checksum from the last 2
+                                * bytes of the transfer and put in the
+                                * csum_data field.
+                                */
+                               memcpy(&m->m_pkthdr.csum_data,
+                                  buf + pktlen - 2, 2);
+                               /*
+                                * The data is copied in network order, but the
+                                * csum algorithm in the kernel expects it to be
+                                * in host network order.
+                                */
+                               m->m_pkthdr.csum_data =
+                                  ntohs(m->m_pkthdr.csum_data);
+                               smsc_dbg_printf(sc,
+                                  "RX checksum offloaded (0x%04x)\n",
+                                  m->m_pkthdr.csum_data);
+                       }
+               }
+
+               buf += pktlen;
+               total_len -= pktlen;
 
                /* push the packet up */
                s = splnet();
                bpf_mtap(ifp, m);
                ifp->if_input(ifp, m);
                splx(s);
-       } while (total_len > 0);
+       }
 
 done:
-       memset(c->sc_buf, 0, sc->sc_bufsz);
-
        /* Setup new transfer. */
        usbd_setup_xfer(xfer, sc->sc_ep[SMSC_ENDPT_RX],
            c, c->sc_buf, sc->sc_bufsz,
diff -r aa38f66f3556 -r 3652bc7c1871 sys/dev/usb/if_smscreg.h
--- a/sys/dev/usb/if_smscreg.h  Mon Jun 09 13:03:16 2014 +0000
+++ b/sys/dev/usb/if_smscreg.h  Mon Jun 09 14:18:28 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_smscreg.h,v 1.3 2013/04/03 15:57:44 skrll Exp $     */
+/*     $NetBSD: if_smscreg.h,v 1.4 2014/06/09 14:18:28 mlelstv Exp $   */
 
 /*     $OpenBSD: if_smscreg.h,v 1.2 2012/09/27 12:38:11 jsg Exp $      */
 /*-
@@ -161,6 +161,7 @@
 
 #define SMSC_HW_CFG_BIR                        (0x1UL << 12)
 #define SMSC_HW_CFG_LEDB               (0x1UL << 11)
+#define SMSC_HW_CFG_RXDOFF_SHIFT       (9)
 #define SMSC_HW_CFG_RXDOFF             (0x3UL << 9)    /* RX pkt alignment */
 #define SMSC_HW_CFG_DRP                        (0x1UL << 6)
 #define SMSC_HW_CFG_MEF                        (0x1UL << 5)
@@ -200,6 +201,8 @@
 #define SMSC_MAC_CSR_PASSBAD           (0x1UL << 16)  /* Pass on bad frames */
 #define SMSC_MAC_CSR_HPFILT            (0x1UL << 13)  /* Hash filtering */
 #define SMSC_MAC_CSR_BCAST             (0x1UL << 11)  /* Broadcast */
+#define SMSC_MAC_CSR_DISRTY            (0x1UL << 10)  /* Disable Retry */
+#define SMSC_MAC_CSR_PADSTR            (0x1UL << 8)   /* PAD stripping */
 #define SMSC_MAC_CSR_TXEN              (0x1UL << 3)   /* TX enable */
 #define SMSC_MAC_CSR_RXEN              (0x1UL << 2)   /* RX enable */
 
diff -r aa38f66f3556 -r 3652bc7c1871 sys/dev/usb/if_smscvar.h
--- a/sys/dev/usb/if_smscvar.h  Mon Jun 09 13:03:16 2014 +0000
+++ b/sys/dev/usb/if_smscvar.h  Mon Jun 09 14:18:28 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_smscvar.h,v 1.2 2013/02/09 16:42:45 skrll Exp $     */
+/*     $NetBSD: if_smscvar.h,v 1.3 2014/06/09 14:18:28 mlelstv Exp $   */
 
 /*     $OpenBSD: if_smscreg.h,v 1.2 2012/09/27 12:38:11 jsg Exp $      */
 /*-
@@ -69,6 +69,8 @@
        uint32_t                sc_mac_csr;
        uint32_t                sc_rev_id;
 
+       uint32_t                sc_coe_ctrl;
+
        int                     sc_if_flags;
        int                     sc_refcnt;
 



Home | Main Index | Thread Index | Old Index