Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Pull across various locking and reference counti...



details:   https://anonhg.NetBSD.org/src/rev/4bf56cdcc9e0
branches:  trunk
changeset: 348993:4bf56cdcc9e0
user:      skrll <skrll%NetBSD.org@localhost>
date:      Sat Nov 19 09:49:20 2016 +0000

description:
Pull across various locking and reference counting fixes from nick-nhusb.

diffstat:

 sys/dev/usb/ucom.c |  515 ++++++++++++++++++++++++++++++++++------------------
 1 files changed, 335 insertions(+), 180 deletions(-)

diffs (truncated from 1112 to 300 lines):

diff -r 0843f5d02493 -r 4bf56cdcc9e0 sys/dev/usb/ucom.c
--- a/sys/dev/usb/ucom.c        Sat Nov 19 09:46:58 2016 +0000
+++ b/sys/dev/usb/ucom.c        Sat Nov 19 09:49:20 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ucom.c,v 1.114 2016/10/03 13:36:33 skrll Exp $ */
+/*     $NetBSD: ucom.c,v 1.115 2016/11/19 09:49:20 skrll Exp $ */
 
 /*
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.114 2016/10/03 13:36:33 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.115 2016/11/19 09:49:20 skrll Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_usb.h"
+#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -139,11 +143,10 @@
        device_t                sc_dev;         /* base device */
 
        struct usbd_device *    sc_udev;        /* USB device */
-
        struct usbd_interface * sc_iface;       /* data interface */
 
        int                     sc_bulkin_no;   /* bulk in endpoint address */
-       struct usbd_pipe *      sc_bulkin_pipe; /* bulk in pipe */
+       struct usbd_pipe *      sc_bulkin_pipe;/* bulk in pipe */
        u_int                   sc_ibufsize;    /* read buffer size */
        u_int                   sc_ibufsizepad; /* read buffer size padded */
        struct ucom_buffer      sc_ibuff[UCOM_IN_BUFFS];
@@ -173,17 +176,22 @@
        u_char                  sc_tx_stopped;
        int                     sc_swflags;
 
-       u_char                  sc_opening;     /* lock during open */
-       u_char                  sc_closing;     /* lock during close */
+       enum ucom_state {
+           UCOM_DEAD,
+           UCOM_ATTACHED,
+           UCOM_OPENING,
+           UCOM_CLOSING,
+           UCOM_OPEN
+       }                       sc_state;
        int                     sc_refcnt;
-       u_char                  sc_dying;       /* disconnecting */
+       bool                    sc_dying;       /* disconnecting */
 
        struct pps_state        sc_pps_state;   /* pps state */
 
        krndsource_t            sc_rndsource;   /* random source */
 
        kmutex_t                sc_lock;
-       kcondvar_t              sc_opencv;
+       kcondvar_t              sc_statecv;
        kcondvar_t              sc_detachcv;
 };
 
@@ -227,11 +235,11 @@
 static void    ucomreadcb(struct usbd_xfer *, void *, usbd_status);
 static void    ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
 static void    ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
-                       usbd_status);
+                   usbd_status);
 
 static void    ucomwritecb(struct usbd_xfer *, void *, usbd_status);
 static void    ucom_read_complete(struct ucom_softc *);
-static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
+static int     ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
 static void    ucom_softintr(void *);
 
 int ucom_match(device_t, cfdata_t, void *);
@@ -253,7 +261,6 @@
 {
        struct ucom_softc *sc = device_private(self);
        struct ucom_attach_args *ucaa = aux;
-       struct tty *tp;
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
@@ -282,14 +289,13 @@
        sc->sc_mcr = 0;
        sc->sc_tx_stopped = 0;
        sc->sc_swflags = 0;
-       sc->sc_opening = 0;
-       sc->sc_closing = 0;
        sc->sc_refcnt = 0;
-       sc->sc_dying = 0;
+       sc->sc_dying = false;
+       sc->sc_state = UCOM_DEAD;
 
        sc->sc_si = softint_establish(SOFTINT_USB, ucom_softintr, sc);
        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
-       cv_init(&sc->sc_opencv, "ucomopen");
+       cv_init(&sc->sc_statecv, "ucomstate");
        cv_init(&sc->sc_detachcv, "ucomdtch");
 
        SIMPLEQ_INIT(&sc->sc_ibuff_empty);
@@ -316,6 +322,17 @@
                error = EIO;
                goto fail_0;
        }
+       /* Allocate input buffers */
+       for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
+           ub++) {
+               error = usbd_create_xfer(sc->sc_bulkin_pipe,
+                   sc->sc_ibufsizepad, USBD_SHORT_XFER_OK, 0,
+                   &ub->ub_xfer);
+               if (error)
+                       goto fail_1;
+               ub->ub_data = usbd_get_buffer(ub->ub_xfer);
+       }
+
        err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
            USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
        if (err) {
@@ -324,28 +341,17 @@
                error = EIO;
                goto fail_1;
        }
-
-       /* Allocate input buffers */
-       for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
-           ub++) {
-               error = usbd_create_xfer(sc->sc_bulkin_pipe, sc->sc_ibufsizepad,
-                   USBD_SHORT_XFER_OK, 0, &ub->ub_xfer);
-               if (error)
-                       goto fail_2;
-               ub->ub_data = usbd_get_buffer(ub->ub_xfer);
-       }
-
        for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
            ub++) {
-               error = usbd_create_xfer(sc->sc_bulkout_pipe, sc->sc_obufsize,
-                   0, 0, &ub->ub_xfer);
+               error = usbd_create_xfer(sc->sc_bulkout_pipe,
+                   sc->sc_obufsize, 0, 0, &ub->ub_xfer);
                if (error)
                        goto fail_2;
                ub->ub_data = usbd_get_buffer(ub->ub_xfer);
                SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
        }
 
-       tp = tty_alloc();
+       struct tty *tp = tty_alloc();
        tp->t_oproc = ucomstart;
        tp->t_param = ucomparam;
        tp->t_hwiflow = ucomhwiflow;
@@ -359,21 +365,26 @@
 
        if (!pmf_device_register(self, NULL, NULL))
                aprint_error_dev(self, "couldn't establish power handler\n");
+
+       sc->sc_state = UCOM_ATTACHED;
+
        return;
 
 fail_2:
-       for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
-           ub++) {
-               if (ub->ub_xfer)
-                       usbd_destroy_xfer(ub->ub_xfer);
-       }
        for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
            ub++) {
                if (ub->ub_xfer)
                        usbd_destroy_xfer(ub->ub_xfer);
        }
 
+       usbd_close_pipe(sc->sc_bulkout_pipe);
+
 fail_1:
+       for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
+           ub++) {
+               if (ub->ub_xfer)
+                       usbd_destroy_xfer(ub->ub_xfer);
+       }
        usbd_close_pipe(sc->sc_bulkin_pipe);
 
 fail_0:
@@ -393,10 +404,10 @@
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
        DPRINTF("sc=%p flags=%d tp=%p", sc, flags, tp, 0);
-       DPRINTF("... pipe=%d,%d",sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
+       DPRINTF("... pipe=%d,%d", sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
 
        mutex_enter(&sc->sc_lock);
-       sc->sc_dying = 1;
+       sc->sc_dying = true;
        mutex_exit(&sc->sc_lock);
 
        pmf_device_deregister(self);
@@ -407,6 +418,18 @@
                usbd_abort_pipe(sc->sc_bulkout_pipe);
 
        mutex_enter(&sc->sc_lock);
+
+       /* wait for open/close to finish */
+       while (sc->sc_state == UCOM_OPENING || sc->sc_state == UCOM_CLOSING) {
+               int error = cv_wait_sig(&sc->sc_statecv, &sc->sc_lock);
+
+               if (error) {
+                       mutex_exit(&sc->sc_lock);
+                       return error;
+               }
+       }
+
+       sc->sc_refcnt--;
        while (sc->sc_refcnt > 0) {
                /* Wake up anyone waiting */
                if (tp != NULL) {
@@ -417,7 +440,10 @@
                        mutex_spin_exit(&tty_lock);
                }
                /* Wait for processes to go away. */
-               usb_detach_wait(sc->sc_dev, &sc->sc_detachcv, &sc->sc_lock);
+               if (cv_timedwait(&sc->sc_detachcv, &sc->sc_lock, hz * 60)) {
+                       printf("%s: %s didn't detach\n", __func__,
+                           device_xname(sc->sc_dev));
+               }
        }
 
        softint_disestablish(sc->sc_si);
@@ -428,7 +454,7 @@
 
        /* Nuke the vnodes for any open instances. */
        mn = device_unit(self);
-       DPRINTF("maj=%d mn=%d\n", maj, mn, 0, 0);
+       DPRINTF("maj=%d mn=%d", maj, mn, 0, 0);
        vdevgone(maj, mn, mn, VCHR);
        vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
        vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
@@ -464,7 +490,7 @@
        rnd_detach_source(&sc->sc_rndsource);
 
        mutex_destroy(&sc->sc_lock);
-       cv_destroy(&sc->sc_opencv);
+       cv_destroy(&sc->sc_statecv);
        cv_destroy(&sc->sc_detachcv);
 
        return 0;
@@ -482,7 +508,7 @@
        switch (act) {
        case DVACT_DEACTIVATE:
                mutex_enter(&sc->sc_lock);
-               sc->sc_dying = 1;
+               sc->sc_dying = true;
                mutex_exit(&sc->sc_lock);
                return 0;
        default:
@@ -512,11 +538,9 @@
 int
 ucomopen(dev_t dev, int flag, int mode, struct lwp *l)
 {
-       int unit = UCOMUNIT(dev);
-       struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
-       struct ucom_buffer *ub;
-       struct tty *tp;
-       int error;
+       const int unit = UCOMUNIT(dev);
+       struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
+       int error = 0;
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
@@ -525,6 +549,7 @@
 
        mutex_enter(&sc->sc_lock);
        if (sc->sc_dying) {
+               DPRINTF("... dying", 0, 0, 0, 0);
                mutex_exit(&sc->sc_lock);
                return EIO;
        }
@@ -534,9 +559,9 @@
                return ENXIO;
        }
 
-       tp = sc->sc_tty;
+       struct tty *tp = sc->sc_tty;
 
-       DPRINTF("unit=%d, tp=%p\n", unit, tp, 0, 0);
+       DPRINTF("unit=%d, tp=%p", unit, tp, 0, 0);
 
        if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
                mutex_exit(&sc->sc_lock);
@@ -547,31 +572,36 @@
         * Wait while the device is initialized by the
         * first opener or cleaned up by the last closer.
         */
-       while (sc->sc_opening || sc->sc_closing) {
-               error = cv_wait_sig(&sc->sc_opencv, &sc->sc_lock);
+       while (sc->sc_state == UCOM_OPENING || sc->sc_state == UCOM_CLOSING) {
+               error = cv_wait_sig(&sc->sc_statecv, &sc->sc_lock);
+
+               if (sc->sc_dying)



Home | Main Index | Thread Index | Old Index