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;
 		}
 	}
 

Reply via email to