Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb uhub(4): Allow only one explore/rescan at a time.



details:   https://anonhg.NetBSD.org/src/rev/d0557febee84
branches:  trunk
changeset: 379605:d0557febee84
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sat Jun 12 12:11:01 2021 +0000

description:
uhub(4): Allow only one explore/rescan at a time.

Otherwise we might simultaneously attach two autoconf instances of
the same device, which leads to no good.

diffstat:

 sys/dev/usb/uhub.c |  55 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 53 insertions(+), 2 deletions(-)

diffs (138 lines):

diff -r 9289827c7371 -r d0557febee84 sys/dev/usb/uhub.c
--- a/sys/dev/usb/uhub.c        Sat Jun 12 00:04:46 2021 +0000
+++ b/sys/dev/usb/uhub.c        Sat Jun 12 12:11:01 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uhub.c,v 1.147 2020/06/05 17:20:56 maxv Exp $  */
+/*     $NetBSD: uhub.c,v 1.148 2021/06/12 12:11:01 riastradh Exp $     */
 /*     $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $       */
 /*     $OpenBSD: uhub.c,v 1.86 2015/06/29 18:27:40 mpi Exp $ */
 
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.147 2020/06/05 17:20:56 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.148 2021/06/12 12:11:01 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -110,6 +110,7 @@ struct uhub_softc {
        struct usbd_pipe        *sc_ipipe;      /* interrupt pipe */
 
        kmutex_t                 sc_lock;
+       kcondvar_t               sc_cv;
 
        uint8_t                 *sc_statusbuf;
        uint8_t                 *sc_statuspend;
@@ -118,6 +119,8 @@ struct uhub_softc {
        bool                     sc_explorepending;
        bool                     sc_first_explore;
        bool                     sc_running;
+
+       struct lwp              *sc_exploring;
 };
 
 #define UHUB_IS_HIGH_SPEED(sc) \
@@ -127,6 +130,8 @@ struct uhub_softc {
 #define PORTSTAT_ISSET(sc, port) \
        ((sc)->sc_status[(port) / 8] & (1 << ((port) % 8)))
 
+Static usbd_status uhub_explore_enter(struct uhub_softc *);
+Static void uhub_explore_exit(struct uhub_softc *);
 Static usbd_status uhub_explore(struct usbd_device *);
 Static void uhub_intr(struct usbd_xfer *, void *, usbd_status);
 
@@ -365,6 +370,7 @@ uhub_attach(device_t parent, device_t se
        sc->sc_statuspend = kmem_zalloc(sc->sc_statuslen, KM_SLEEP);
        sc->sc_status = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
+       cv_init(&sc->sc_cv, "uhubex");
 
        /* force initial scan */
        memset(sc->sc_status, 0xff, sc->sc_statuslen);
@@ -476,6 +482,41 @@ uhub_attach(device_t parent, device_t se
        config_pending_decr(self);
 }
 
+Static usbd_status
+uhub_explore_enter(struct uhub_softc *sc)
+{
+       usbd_status err;
+
+       mutex_enter(&sc->sc_lock);
+       for (;;) {
+               if (sc->sc_exploring == NULL) {
+                       sc->sc_exploring = curlwp;
+                       err = 0;
+                       break;
+               }
+               KASSERT(sc->sc_exploring != curlwp);
+               if (cv_wait_sig(&sc->sc_cv, &sc->sc_lock)) {
+                       err = USBD_INTERRUPTED;
+                       break;
+               }
+       }
+       mutex_exit(&sc->sc_lock);
+
+       return err;
+}
+
+Static void
+uhub_explore_exit(struct uhub_softc *sc)
+{
+
+       mutex_enter(&sc->sc_lock);
+       KASSERTMSG(sc->sc_exploring == curlwp, "lwp %p exploring %s",
+           sc->sc_exploring, device_xname(sc->sc_dev));
+       sc->sc_exploring = NULL;
+       cv_broadcast(&sc->sc_cv);
+       mutex_exit(&sc->sc_lock);
+}
+
 usbd_status
 uhub_explore(struct usbd_device *dev)
 {
@@ -499,6 +540,11 @@ uhub_explore(struct usbd_device *dev)
        if (dev->ud_depth > USB_HUB_MAX_DEPTH)
                return USBD_TOO_DEEP;
 
+       /* Only one explore at a time, please.  */
+       err = uhub_explore_enter(sc);
+       if (err)
+               return err;
+
        if (PORTSTAT_ISSET(sc, 0)) { /* hub status change */
                usb_hub_status_t hs;
 
@@ -803,6 +849,7 @@ uhub_explore(struct usbd_device *dev)
                }
        }
        mutex_exit(&sc->sc_lock);
+       uhub_explore_exit(sc);
        if (sc->sc_first_explore) {
                config_pending_decr(sc->sc_dev);
                sc->sc_first_explore = false;
@@ -866,6 +913,7 @@ uhub_detach(device_t self, int flags)
        if (sc->sc_statusbuf)
                kmem_free(sc->sc_statusbuf, sc->sc_statuslen);
 
+       cv_destroy(&sc->sc_cv);
        mutex_destroy(&sc->sc_lock);
 
        /* XXXSMP usb */
@@ -882,12 +930,15 @@ uhub_rescan(device_t self, const char *i
        struct usbd_device *dev;
        int port;
 
+       if (uhub_explore_enter(sc) != 0)
+               return EBUSY;
        for (port = 1; port <= hub->uh_hubdesc.bNbrPorts; port++) {
                dev = hub->uh_ports[port - 1].up_dev;
                if (dev == NULL)
                        continue;
                usbd_reattach_device(sc->sc_dev, dev, port, locators);
        }
+       uhub_explore_exit(sc);
        return 0;
 }
 



Home | Main Index | Thread Index | Old Index