Module Name: src
Committed By: skrll
Date: Thu Dec 29 08:15:18 UTC 2016
Modified Files:
src/sys/external/bsd/dwc2 [nick-nhusb]: dwc2.c
Log Message:
Improve the transfer abort process.
To generate a diff of this commit:
cvs rdiff -u -r1.32.2.29 -r1.32.2.30 src/sys/external/bsd/dwc2/dwc2.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/dwc2/dwc2.c
diff -u src/sys/external/bsd/dwc2/dwc2.c:1.32.2.29 src/sys/external/bsd/dwc2/dwc2.c:1.32.2.30
--- src/sys/external/bsd/dwc2/dwc2.c:1.32.2.29 Mon Dec 5 10:55:25 2016
+++ src/sys/external/bsd/dwc2/dwc2.c Thu Dec 29 08:15:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc2.c,v 1.32.2.29 2016/12/05 10:55:25 skrll Exp $ */
+/* $NetBSD: dwc2.c,v 1.32.2.30 2016/12/29 08:15:18 skrll Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.32.2.29 2016/12/05 10:55:25 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.32.2.30 2016/12/29 08:15:18 skrll Exp $");
#include "opt_usb.h"
@@ -316,24 +316,30 @@ Static void
dwc2_timeout(void *addr)
{
struct usbd_xfer *xfer = addr;
- struct dwc2_xfer *dxfer = DWC2_XFER2DXFER(xfer);
-// struct dwc2_pipe *dpipe = DWC2_XFER2DPIPE(xfer);
struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
+ bool timeout = false;
DPRINTF("dxfer=%p\n", dxfer);
-
+ mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
- mutex_enter(&sc->sc_lock);
- dwc2_abort_xfer(&dxfer->xfer, USBD_TIMEOUT);
mutex_exit(&sc->sc_lock);
return;
}
+ 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, dwc2_timeout_task, addr,
- USB_TASKQ_MPSAFE);
- usb_add_task(dxfer->xfer.ux_pipe->up_dev, &xfer->ux_aborttask,
- USB_TASKQ_HC);
+ /* Execute the abort in a process context. */
+ usb_init_task(&xfer->ux_aborttask, dwc2_timeout_task, addr,
+ USB_TASKQ_MPSAFE);
+ usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC);
+
+ }
}
Static void
@@ -345,6 +351,7 @@ dwc2_timeout_task(void *addr)
DPRINTF("xfer=%p\n", xfer);
mutex_enter(&sc->sc_lock);
+ KASSERT(xfer->ux_status == USBD_TIMEOUT);
dwc2_abort_xfer(xfer, USBD_TIMEOUT);
mutex_exit(&sc->sc_lock);
}
@@ -455,11 +462,12 @@ dwc2_abort_xfer(struct usbd_xfer *xfer,
DPRINTF("xfer=%p\n", xfer);
KASSERT(mutex_owned(&sc->sc_lock));
- KASSERT(!cpu_intr_p() && !cpu_softintr_p());
+ ASSERT_SLEEPABLE();
if (sc->sc_dying) {
xfer->ux_status = status;
- callout_stop(&xfer->ux_callout);
+ callout_halt(&xfer->ux_callout, &sc->sc_lock);
+ KASSERT(xfer->ux_status == status);
usb_transfer_complete(xfer);
return;
}
@@ -479,16 +487,26 @@ dwc2_abort_xfer(struct usbd_xfer *xfer,
/*
* Step 1: Make the stack ignore it and stop the callout.
*/
- mutex_spin_enter(&hsotg->lock);
xfer->ux_hcflags |= UXFER_ABORTING;
- xfer->ux_status = status; /* make software ignore it */
- callout_stop(&xfer->ux_callout);
+ /*
+ * 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.
+ */
+ if (status == USBD_CANCELLED) {
+ xfer->ux_status = status;
+ callout_halt(&xfer->ux_callout, &sc->sc_lock);
+ } else {
+ KASSERT(xfer->ux_status == USBD_TIMEOUT);
+ }
+ mutex_spin_enter(&hsotg->lock);
/* XXXNH suboptimal */
TAILQ_FOREACH_SAFE(d, &sc->sc_complete, xnext, tmp) {
if (d == dxfer) {
TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext);
+ break;
}
}