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 HW checksum offloading.



details:   https://anonhg.NetBSD.org/src/rev/c2359e7cf383
branches:  trunk
changeset: 447994:c2359e7cf383
user:      rin <rin%NetBSD.org@localhost>
date:      Wed Jan 30 11:13:25 2019 +0000

description:
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).

diffstat:

 sys/dev/usb/if_axen.c    |  151 +++++++++++++++++++++++++++++++++-------------
 sys/dev/usb/if_axenreg.h |    4 +-
 2 files changed, 109 insertions(+), 46 deletions(-)

diffs (252 lines):

diff -r e3dddae55812 -r c2359e7cf383 sys/dev/usb/if_axen.c
--- a/sys/dev/usb/if_axen.c     Wed Jan 30 11:11:45 2019 +0000
+++ b/sys/dev/usb/if_axen.c     Wed Jan 30 11:13:25 2019 +0000
@@ -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 @@
 #define DPRINTFN(n,x)
 #endif
 
-#define AXEN_TOE       /* enable checksum offload function */
-
 /*
  * Various supported device vendors/products.
  */
@@ -98,6 +96,7 @@
 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_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 @@
 
        /* 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 @@
 #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 @@
        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 @@
                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 @@
        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 @@
                        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);
diff -r e3dddae55812 -r c2359e7cf383 sys/dev/usb/if_axenreg.h
--- a/sys/dev/usb/if_axenreg.h  Wed Jan 30 11:11:45 2019 +0000
+++ b/sys/dev/usb/if_axenreg.h  Wed Jan 30 11:13:25 2019 +0000
@@ -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



Home | Main Index | Thread Index | Old Index