Source-Changes-HG archive

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

[src/netbsd-8]: src/sys/dev/usb Pull up following revision(s) (requested by r...



details:   https://anonhg.NetBSD.org/src/rev/db9c489c16ba
branches:  netbsd-8
changeset: 449026:db9c489c16ba
user:      martin <martin%NetBSD.org@localhost>
date:      Tue Feb 19 15:05:52 2019 +0000

description:
Pull up following revision(s) (requested by rin in ticket #1191):

        sys/dev/usb/if_axen.c: revision 1.28
        sys/dev/usb/if_axen.c: revision 1.29
        sys/dev/usb/if_axenreg.h: revision 1.4
        sys/dev/usb/if_axenreg.h: revision 1.5
        sys/dev/usb/if_axen.c: revision 1.19
        sys/dev/usb/if_axenreg.h: revision 1.8
        sys/dev/usb/if_axen.c: revision 1.30
        sys/dev/usb/if_axen.c: revision 1.31
        sys/dev/usb/if_axen.c: revision 1.36
        sys/dev/usb/if_axen.c: revision 1.20
        sys/dev/usb/if_axen.c: revision 1.23
        sys/dev/usb/if_axen.c: revision 1.25

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

Fix previous:
- axen_coe() should be called from axen_init(), not axen_ax88179_init().
- Simplify logic in axen_coe(); AXEN_[RT]XCOE_OFF = 0.

Enable hash-table-based multicast filter:
- Drop AXEN_RXCTL_ACPT_PHY_MCAST bit (neither Linux nor FreeBSD sets it).
- 0x0010 bit is not AXEN_RXCTL_ACPT_BCAST ("accept broadcast") but
   AXEN_RXCTL_ACPT_MCAST ("accept multicast (hash-table-based)").

Remove useless memset.

Fix padding for a full length USB packet in TX:
- Update boundary length for SS mode, taken from OpenBSD.
- Make sure everything passed to the adapter is little endian.
- Specify padding bits in a similar manner to Linux.

XXX I wonder whether this is really necessary...

Support TSOv4 (They call it LSOv1).
The adapter does not support TSOv6 (aka LSOv2).

Fix previous.

Oops, fix previous again. Really support TSOv4.

Use unsigned variables for buffer length to avoid compiler warnings.

diffstat:

 sys/dev/usb/if_axen.c    |  254 ++++++++++++++++++++++++++++++----------------
 sys/dev/usb/if_axenreg.h |    9 +-
 2 files changed, 171 insertions(+), 92 deletions(-)

diffs (truncated from 470 to 300 lines):

diff -r a728bb746d2f -r db9c489c16ba sys/dev/usb/if_axen.c
--- a/sys/dev/usb/if_axen.c     Tue Feb 19 14:51:24 2019 +0000
+++ b/sys/dev/usb/if_axen.c     Tue Feb 19 15:05:52 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_axen.c,v 1.11.8.4 2019/02/19 14:51:24 martin Exp $  */
+/*     $NetBSD: if_axen.c,v 1.11.8.5 2019/02/19 15:05:52 martin 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.11.8.4 2019/02/19 14:51:24 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.11.8.5 2019/02/19 15:05:52 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -50,6 +50,9 @@
 
 #include <net/bpf.h>
 
+#include <netinet/in.h>                /* XXX for netinet/ip.h */
+#include <netinet/ip.h>                /* XXX for IP_MAXPACKET */
+
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
 
@@ -70,8 +73,6 @@
 #define DPRINTFN(n,x)
 #endif
 
-#define AXEN_TOE       /* enable checksum offload function */
-
 /*
  * Various supported device vendors/products.
  */
@@ -98,6 +99,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 +124,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
@@ -353,32 +356,38 @@
        axen_lock_mii(sc);
        axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
        rxmode = le16toh(wval);
-       rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST |
-                 AXEN_RXCTL_PROMISC);
+       rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_PROMISC |
+           AXEN_RXCTL_ACPT_MCAST);
        ifp->if_flags &= ~IFF_ALLMULTI;
 
-       /*
-        * Always accept broadcast frames.
-        * Always accept frames destined to our station address.
-        */
-       rxmode |= AXEN_RXCTL_ACPT_BCAST;
-
-       if (ifp->if_flags & IFF_PROMISC || ec->ec_multicnt > 0 /* XXX */) {
-               ifp->if_flags |= IFF_ALLMULTI;
-               rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
-               if (ifp->if_flags & IFF_PROMISC)
-                       rxmode |= AXEN_RXCTL_PROMISC;
+       if (ifp->if_flags & IFF_PROMISC) {
+               DPRINTF(("%s: promisc\n", device_xname(sc->axen_dev)));
+               rxmode |= AXEN_RXCTL_PROMISC;
+allmulti:      ifp->if_flags |= IFF_ALLMULTI;
+               rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST
+               /* | AXEN_RXCTL_ACPT_PHY_MCAST */;
        } else {
-               rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
-
                /* now program new ones */
+               DPRINTF(("%s: initializing hash table\n",
+                   device_xname(sc->axen_dev)));
                ETHER_FIRST_MULTI(step, ec, enm);
                while (enm != NULL) {
+                       if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
+                           ETHER_ADDR_LEN)) {
+                               DPRINTF(("%s: allmulti\n",
+                                   device_xname(sc->axen_dev)));
+                               memset(hashtbl, 0, sizeof(hashtbl));
+                               goto allmulti;
+                       }
                        h = ether_crc32_be(enm->enm_addrlo,
                            ETHER_ADDR_LEN) >> 26;
                        hashtbl[h / 8] |= 1 << (h % 8);
+                       DPRINTF(("%s: %s added\n",
+                           device_xname(sc->axen_dev),
+                           ether_sprintf(enm->enm_addrlo)));
                        ETHER_NEXT_MULTI(step, enm);
                }
+               rxmode |= AXEN_RXCTL_ACPT_MCAST;
        }
 
        axen_cmd(sc, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, hashtbl);
@@ -567,26 +576,8 @@
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val);
 
        /* 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);
-
        /* Set RX control register */
        ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB;
-       ctl |= AXEN_RXCTL_ACPT_PHY_MCAST | AXEN_RXCTL_ACPT_ALL_MCAST;
        wval = htole16(ctl);
        axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
 
@@ -631,6 +622,44 @@
 #endif
 }
 
+static void
+axen_setcoe(struct axen_softc *sc)
+{
+       struct ifnet *ifp = GET_IFP(sc);
+       uint64_t enabled = ifp->if_capenable;
+       uint8_t val;
+
+       axen_lock_mii(sc);
+
+       val = AXEN_RXCOE_OFF;
+       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;
+       axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val);
+
+       val = AXEN_TXCOE_OFF;
+       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;
+       axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val);
+
+       axen_unlock_mii(sc);
+}
+
 static int
 axen_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -692,16 +721,20 @@
        /* decide on what our bufsize will be */
        switch (sc->axen_udev->ud_speed) {
        case USB_SPEED_SUPER:
-               sc->axen_bufsz = AXEN_BUFSZ_SS * 1024;
+               sc->axen_rx_bufsz = AXEN_BUFSZ_SS * 1024;
                break;
        case USB_SPEED_HIGH:
-               sc->axen_bufsz = AXEN_BUFSZ_HS * 1024;
+               sc->axen_rx_bufsz = AXEN_BUFSZ_HS * 1024;
                break;
        default:
-               sc->axen_bufsz = AXEN_BUFSZ_LS * 1024;
+               sc->axen_rx_bufsz = AXEN_BUFSZ_LS * 1024;
                break;
        }
 
+       sc->axen_tx_bufsz = IP_MAXPACKET +
+           ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN +
+           sizeof(struct axen_sframe_hdr);
+
        /* Find endpoints. */
        for (i = 0; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(sc->axen_iface, i);
@@ -765,13 +798,14 @@
        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 |
+
+       /* Adapter does not support TSOv6 (They call it LSOv2). */
+       ifp->if_capabilities |= IFCAP_TSOv4 |
+           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;
@@ -919,7 +953,7 @@
                c->axen_idx = i;
                if (c->axen_xfer == NULL) {
                        int err = usbd_create_xfer(sc->axen_ep[AXEN_ENDPT_RX],
-                           sc->axen_bufsz, 0, 0, &c->axen_xfer);
+                           sc->axen_rx_bufsz, 0, 0, &c->axen_xfer);
                        if (err)
                                return err;
                        c->axen_buf = usbd_get_buffer(c->axen_xfer);
@@ -945,7 +979,7 @@
                c->axen_idx = i;
                if (c->axen_xfer == NULL) {
                        int err = usbd_create_xfer(sc->axen_ep[AXEN_ENDPT_TX],
-                           sc->axen_bufsz, USBD_FORCE_SHORT_XFER, 0,
+                           sc->axen_tx_bufsz, USBD_FORCE_SHORT_XFER, 0,
                            &c->axen_xfer);
                        if (err)
                                return err;
@@ -1013,7 +1047,7 @@
        hdr_offset = (uint16_t)(rx_hdr >> 16);
        pkt_count  = (uint16_t)(rx_hdr & 0xffff);
 
-       if (total_len > sc->axen_bufsz) {
+       if (total_len > sc->axen_rx_bufsz) {
                aprint_error_dev(sc->axen_dev, "rxeof: too large transfer\n");
                goto done;
        }
@@ -1077,27 +1111,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 */
@@ -1118,17 +1132,59 @@
        } while( pkt_count > 0);
 
 done:
-       /* clear buffer for next transaction */
-       memset(c->axen_buf, 0, sc->axen_bufsz);
-
        /* Setup new transfer. */
-       usbd_setup_xfer(xfer, c, c->axen_buf, sc->axen_bufsz,
+       usbd_setup_xfer(xfer, c, c->axen_buf, sc->axen_rx_bufsz,
            USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axen_rxeof);
        usbd_transfer(xfer);
 
        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;
+



Home | Main Index | Thread Index | Old Index