Source-Changes-HG archive

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

[src/nick-nhusb]: src/sys/dev/usb Mark device transfers as USBD_IN_PROGRESS a...



details:   https://anonhg.NetBSD.org/src/rev/2188e53affa7
branches:  nick-nhusb
changeset: 334598:2188e53affa7
user:      skrll <skrll%NetBSD.org@localhost>
date:      Thu Dec 29 09:52:00 2016 +0000

description:
Mark device transfers as USBD_IN_PROGRESS appropriately and improve
abort handling

diffstat:

 sys/dev/usb/xhci.c |  85 +++++++++++++++++++++++++++++++++--------------------
 1 files changed, 53 insertions(+), 32 deletions(-)

diffs (187 lines):

diff -r 3eb44c43061a -r 2188e53affa7 sys/dev/usb/xhci.c
--- a/sys/dev/usb/xhci.c        Thu Dec 29 08:40:27 2016 +0000
+++ b/sys/dev/usb/xhci.c        Thu Dec 29 09:52:00 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: xhci.c,v 1.28.2.77 2016/10/05 20:55:59 skrll Exp $     */
+/*     $NetBSD: xhci.c,v 1.28.2.78 2016/12/29 09:52:00 skrll Exp $     */
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.77 2016/10/05 20:55:59 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.78 2016/12/29 09:52:00 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -1560,12 +1560,13 @@
            xfer, xfer->ux_pipe, status, 0);
 
        KASSERT(mutex_owned(&sc->sc_lock));
+       ASSERT_SLEEPABLE();
 
        if (sc->sc_dying) {
                /* If we're dying, just do the software part. */
                DPRINTFN(4, "xfer %p dying %u", xfer, xfer->ux_status, 0, 0);
                xfer->ux_status = status;
-               callout_stop(&xfer->ux_callout);
+               callout_halt(&xfer->ux_callout, &sc->sc_lock);
                usb_transfer_complete(xfer);
                return;
        }
@@ -1592,10 +1593,16 @@
        xfer->ux_hcflags |= UXFER_ABORTING;
 
        /*
-        * Step 1: Stop xfer timeout timer.
+        * Step 1: When cancelling a transfer make sure the timeout handler
+        * didn't run or ran to the end and saw the USBD_CANCELLED status.
+        * Otherwise we must have got here via a timeout.
         */
-       xfer->ux_status = status;
-       callout_stop(&xfer->ux_callout);
+       if (status == USBD_CANCELLED) {
+               xfer->ux_status = status;
+               callout_halt(&xfer->ux_callout, &sc->sc_lock);
+       } else {
+               KASSERT(xfer->ux_status == USBD_TIMEOUT);
+       }
 
        /*
         * Step 2: Stop execution of TD on the ring.
@@ -1879,7 +1886,7 @@
                 * UF_ENDPOINT_HALT).
                 */
                xfer->ux_status = err;
-               callout_stop(&xfer->ux_callout);
+               callout_halt(&xfer->ux_callout, &sc->sc_lock);
                xhci_clear_endpoint_stall_async(xfer);
                return;
        default:
@@ -3629,17 +3636,18 @@
            XHCI_TRB_3_IOC_BIT;
        xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
 
+       if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
+               callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
+                   xhci_timeout, xfer);
+       }
+       xfer->ux_status = USBD_IN_PROGRESS;
+
        mutex_enter(&tr->xr_lock);
        xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);
        mutex_exit(&tr->xr_lock);
 
        xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
 
-       if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
-               callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
-                   xhci_timeout, xfer);
-       }
-
        return USBD_IN_PROGRESS;
 }
 
@@ -3745,17 +3753,18 @@
            XHCI_TRB_3_IOC_BIT;
        xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
 
+       if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
+               callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
+                   xhci_timeout, xfer);
+       }
+       xfer->ux_status = USBD_IN_PROGRESS;
+
        mutex_enter(&tr->xr_lock);
        xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);
        mutex_exit(&tr->xr_lock);
 
        xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
 
-       if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
-               callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
-                   xhci_timeout, xfer);
-       }
-
        return USBD_IN_PROGRESS;
 }
 
@@ -3851,17 +3860,18 @@
            XHCI_TRB_3_IOC_BIT;
        xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
 
+       if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
+               callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
+                   xhci_timeout, xfer);
+       }
+       xfer->ux_status = USBD_IN_PROGRESS;
+
        mutex_enter(&tr->xr_lock);
        xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);
        mutex_exit(&tr->xr_lock);
 
        xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
 
-       if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
-               callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
-                   xhci_timeout, xfer);
-       }
-
        return USBD_IN_PROGRESS;
 }
 
@@ -3914,31 +3924,42 @@
 static void
 xhci_timeout(void *addr)
 {
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
        struct xhci_xfer * const xx = addr;
        struct usbd_xfer * const xfer = &xx->xx_xfer;
        struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-
-       XHCIHIST_FUNC(); XHCIHIST_CALLED();
-
+       bool timeout = false;
+
+       mutex_enter(&sc->sc_lock);
        if (sc->sc_dying) {
+               mutex_exit(&sc->sc_lock);
                return;
        }
-
-       usb_init_task(&xfer->ux_aborttask, xhci_timeout_task, addr,
-           USB_TASKQ_MPSAFE);
-       usb_add_task(xx->xx_xfer.ux_pipe->up_dev, &xfer->ux_aborttask,
-           USB_TASKQ_HC);
+       if (xfer->ux_status != USBD_CANCELLED) {
+               xfer->ux_status = USBD_TIMEOUT;
+               timeout = true;
+       }
+       mutex_exit(&sc->sc_lock);
+
+       if (timeout) {
+               struct usbd_device *dev = xfer->ux_pipe->up_dev;
+
+               /* Execute the abort in a process context. */
+               usb_init_task(&xfer->ux_aborttask, xhci_timeout_task, xfer,
+                   USB_TASKQ_MPSAFE);
+               usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC);
+       }
 }
 
 static void
 xhci_timeout_task(void *addr)
 {
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
        struct usbd_xfer * const xfer = addr;
        struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
 
-       XHCIHIST_FUNC(); XHCIHIST_CALLED();
-
        mutex_enter(&sc->sc_lock);
+       KASSERT(xfer->ux_status == USBD_TIMEOUT);
        xhci_abort_xfer(xfer, USBD_TIMEOUT);
        mutex_exit(&sc->sc_lock);
 }



Home | Main Index | Thread Index | Old Index