Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb make cdce(4) and ure(4) usb and mpsafe:



details:   https://anonhg.NetBSD.org/src/rev/73da8cca0a69
branches:  trunk
changeset: 452232:73da8cca0a69
user:      mrg <mrg%NetBSD.org@localhost>
date:      Sun Jun 23 02:14:14 2019 +0000

description:
make cdce(4) and ure(4) usb and mpsafe:

- introduce locking ala smsc(4)/axen(4) style
- convert to mpsafe interfaces
- add tick task to cdce(4) to deal with missing watchdog, and
  actually make the watchdog do something
- convert DELAY() to usbd_delay_ms() in cdce(4) and don't increase
  the time in a potentially unbounded way
- remove spl calls

tested with network cable and usb adapter pullouts, reboots and
many many GBs of data transferred in either direction under load.

diffstat:

 sys/dev/usb/if_cdce.c   |  266 +++++++++++++++++++++++++++++++++------------
 sys/dev/usb/if_ure.c    |  275 +++++++++++++++++++++++++++++++++--------------
 sys/dev/usb/if_urevar.h |   11 +-
 3 files changed, 395 insertions(+), 157 deletions(-)

diffs (truncated from 1180 to 300 lines):

diff -r 52d9508bcb9b -r 73da8cca0a69 sys/dev/usb/if_cdce.c
--- a/sys/dev/usb/if_cdce.c     Sun Jun 23 01:46:56 2019 +0000
+++ b/sys/dev/usb/if_cdce.c     Sun Jun 23 02:14:14 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_cdce.c,v 1.49 2019/06/22 04:45:04 mrg Exp $ */
+/*     $NetBSD: if_cdce.c,v 1.50 2019/06/23 02:14:14 mrg Exp $ */
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul%windriver.com@localhost>
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.49 2019/06/22 04:45:04 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.50 2019/06/23 02:14:14 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -71,6 +71,7 @@
 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbdevs.h>
 #include <dev/usb/usbcdc.h>
@@ -116,14 +117,23 @@
        struct usbd_pipe *       cdce_bulkin_pipe;
        int                      cdce_bulkout_no;
        struct usbd_pipe *       cdce_bulkout_pipe;
-       char                     cdce_dying;
        int                      cdce_unit;
        struct cdce_cdata        cdce_cdata;
        int                      cdce_rxeof_errors;
        uint16_t                 cdce_flags;
-       char                     cdce_attached;
+       uint16_t                 cdce_timer;
+
+       bool                     cdce_attached;
+       bool                     cdce_dying;
+       bool                     cdce_stopping;
 
-       kmutex_t                 cdce_start_lock;
+       struct usb_task          cdce_tick_task;
+       struct callout           cdce_stat_ch;
+
+       kmutex_t                 cdce_lock;
+       kmutex_t                 cdce_mii_lock;
+       kmutex_t                 cdce_rxlock;
+       kmutex_t                 cdce_txlock;
 };
 
 static int      cdce_tx_list_init(struct cdce_softc *);
@@ -138,6 +148,8 @@
 static void     cdce_init(void *);
 static void     cdce_watchdog(struct ifnet *);
 static void     cdce_stop(struct cdce_softc *);
+static void     cdce_tick(void *);
+static void     cdce_tick_task(void *);
 
 static const struct cdce_type cdce_devs[] = {
   {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, CDCE_NO_UNION },
@@ -184,7 +196,6 @@
        struct cdce_softc *sc = device_private(self);
        struct usbif_attach_arg *uiaa = aux;
        char                            *devinfop;
-       int                              s;
        struct ifnet                    *ifp;
        struct usbd_device              *dev = uiaa->uiaa_device;
        const struct cdce_type          *t;
@@ -319,16 +330,20 @@
                eaddr[5] = (uint8_t)(device_unit(sc->cdce_dev));
        }
 
-       s = splnet();
+       mutex_init(&sc->cdce_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+       mutex_init(&sc->cdce_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+       mutex_init(&sc->cdce_lock, MUTEX_DEFAULT, IPL_NONE);
+
+       usb_init_task(&sc->cdce_tick_task, cdce_tick_task, sc, USB_TASKQ_MPSAFE);
 
        aprint_normal_dev(self, "address %s\n", ether_sprintf(eaddr));
 
        ifp = GET_IFP(sc);
        ifp->if_softc = sc;
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_extflags = IFEF_MPSAFE;
        ifp->if_ioctl = cdce_ioctl;
        ifp->if_start = cdce_start;
-       ifp->if_watchdog = cdce_watchdog;
        strlcpy(ifp->if_xname, device_xname(sc->cdce_dev), IFNAMSIZ);
 
        IFQ_SET_READY(&ifp->if_snd);
@@ -336,8 +351,10 @@
        if_attach(ifp);
        ether_ifattach(ifp, eaddr);
 
-       sc->cdce_attached = 1;
-       splx(s);
+       callout_init(&sc->cdce_stat_ch, CALLOUT_MPSAFE);
+       callout_setfunc(&sc->cdce_stat_ch, cdce_tick, sc);
+
+       sc->cdce_attached = true;
 
        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
            sc->cdce_dev);
@@ -353,37 +370,46 @@
 {
        struct cdce_softc *sc = device_private(self);
        struct ifnet    *ifp = GET_IFP(sc);
-       int              s;
+
+       mutex_enter(&sc->cdce_lock);
+       sc->cdce_dying = true;
+       mutex_exit(&sc->cdce_lock);
+
+       if (!sc->cdce_attached)
+               return 0;
 
        pmf_device_deregister(self);
 
-       s = splusb();
-
-       if (!sc->cdce_attached) {
-               splx(s);
-               return 0;
-       }
+       callout_halt(&sc->cdce_stat_ch, NULL);
+       usb_rem_task_wait(sc->cdce_udev, &sc->cdce_tick_task,
+           USB_TASKQ_DRIVER, NULL);
 
        if (ifp->if_flags & IFF_RUNNING)
                cdce_stop(sc);
 
+       callout_destroy(&sc->cdce_stat_ch);
        ether_ifdetach(ifp);
-
        if_detach(ifp);
+       sc->cdce_attached = false;
 
-       sc->cdce_attached = 0;
-       splx(s);
+       usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->cdce_udev,sc->cdce_dev);
+
+       mutex_destroy(&sc->cdce_lock);
+       mutex_destroy(&sc->cdce_rxlock);
+       mutex_destroy(&sc->cdce_txlock);
 
        return 0;
 }
 
 static void
-cdce_start(struct ifnet *ifp)
+cdce_start_locked(struct ifnet *ifp)
 {
        struct cdce_softc       *sc = ifp->if_softc;
        struct mbuf             *m_head = NULL;
 
-       if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
+       KASSERT(mutex_owned(&sc->cdce_txlock));
+       if (sc->cdce_dying || sc->cdce_stopping ||
+           (ifp->if_flags & IFF_OACTIVE))
                return;
 
        IFQ_POLL(&ifp->if_snd, m_head);
@@ -401,9 +427,22 @@
 
        ifp->if_flags |= IFF_OACTIVE;
 
+       /*
+        * Set a timeout in case the chip goes out to lunch.
+        */
        ifp->if_timer = 6;
 }
 
+static void
+cdce_start(struct ifnet *ifp)
+{
+       struct cdce_softc * const sc = ifp->if_softc;
+
+       mutex_enter(&sc->cdce_txlock);
+       cdce_start_locked(ifp);
+       mutex_exit(&sc->cdce_txlock);
+}
+
 static int
 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
 {
@@ -411,6 +450,8 @@
        usbd_status              err;
        int                      extra = 0;
 
+       KASSERT(mutex_owned(&sc->cdce_txlock));
+
        c = &sc->cdce_cdata.cdce_tx_chain[idx];
 
        m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
@@ -444,7 +485,16 @@
        struct ifnet    *ifp = GET_IFP(sc);
        int              i;
 
+       mutex_enter(&sc->cdce_rxlock);
+       mutex_enter(&sc->cdce_txlock);
+       sc->cdce_stopping = true;
+       mutex_exit(&sc->cdce_txlock);
+       mutex_exit(&sc->cdce_rxlock);
+
        ifp->if_timer = 0;
+       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+       callout_stop(&sc->cdce_stat_ch);
 
        if (sc->cdce_bulkin_pipe != NULL) {
                err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
@@ -499,8 +549,7 @@
                            device_xname(sc->cdce_dev), usbd_errstr(err));
                sc->cdce_bulkout_pipe = NULL;
        }
-
-       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+       mutex_exit(&sc->cdce_txlock);
 }
 
 static int
@@ -509,13 +558,11 @@
        struct cdce_softc       *sc = ifp->if_softc;
        struct ifaddr           *ifa = (struct ifaddr *)data;
        struct ifreq            *ifr = (struct ifreq *)data;
-       int                      s, error = 0;
+       int                      error = 0;
 
        if (sc->cdce_dying)
                return EIO;
 
-       s = splnet();
-
        switch(command) {
        case SIOCINITIFADDR:
                ifp->if_flags |= IFF_UP;
@@ -557,8 +604,6 @@
                break;
        }
 
-       splx(s);
-
        if (error == ENETRESET)
                error = 0;
 
@@ -569,12 +614,23 @@
 cdce_watchdog(struct ifnet *ifp)
 {
        struct cdce_softc       *sc = ifp->if_softc;
+       struct cdce_chain *c;
+       usbd_status stat;
+
+       KASSERT(mutex_owned(&sc->cdce_lock));
 
        if (sc->cdce_dying)
                return;
 
        ifp->if_oerrors++;
-       printf("%s: watchdog timeout\n", device_xname(sc->cdce_dev));
+       aprint_error_dev(sc->cdce_dev, "watchdog timeout\n");
+
+       c = &sc->cdce_cdata.cdce_rx_chain[0];
+       usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &stat);
+       cdce_txeof(c->cdce_xfer, c, stat);
+
+       if (!IFQ_IS_EMPTY(&ifp->if_snd))
+               cdce_start_locked(ifp);
 }
 
 static void
@@ -584,12 +640,11 @@
        struct ifnet            *ifp = GET_IFP(sc);
        struct cdce_chain       *c;
        usbd_status              err;
-       int                      s, i;
+       int                      i;
 
+       mutex_enter(&sc->cdce_lock);
        if (ifp->if_flags & IFF_RUNNING)
-               return;
-
-       s = splnet();
+               goto out;
 
        /* Maybe set multicast / broadcast here??? */
 
@@ -598,8 +653,7 @@
        if (err) {
                printf("%s: open rx pipe failed: %s\n", device_xname(sc->cdce_dev),
                    usbd_errstr(err));
-               splx(s);
-               return;
+               goto out;
        }
 
        err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
@@ -607,20 +661,17 @@



Home | Main Index | Thread Index | Old Index