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 Improve transfer abort
details: https://anonhg.NetBSD.org/src/rev/9c9ae5579cfe
branches: nick-nhusb
changeset: 334587:9c9ae5579cfe
user: skrll <skrll%NetBSD.org@localhost>
date: Wed Dec 28 10:25:06 2016 +0000
description:
Improve transfer abort
diffstat:
sys/dev/usb/uhci.c | 108 ++++++++++++++++++++++++++++---------------------
sys/dev/usb/uhcivar.h | 5 +-
2 files changed, 63 insertions(+), 50 deletions(-)
diffs (244 lines):
diff -r 5b5245efd868 -r 9c9ae5579cfe sys/dev/usb/uhci.c
--- a/sys/dev/usb/uhci.c Wed Dec 28 09:45:16 2016 +0000
+++ b/sys/dev/usb/uhci.c Wed Dec 28 10:25:06 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.264.4.78 2016/12/05 10:55:18 skrll Exp $ */
+/* $NetBSD: uhci.c,v 1.264.4.79 2016/12/28 10:25:06 skrll Exp $ */
/*
* Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.78 2016/12/05 10:55:18 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.79 2016/12/28 10:25:06 skrll Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -574,8 +574,6 @@
callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE);
- cv_init(&sc->sc_softwake_cv, "uhciab");
-
/* Set up the bus struct. */
sc->sc_bus.ub_methods = &uhci_bus_methods;
sc->sc_bus.ub_pipesize = sizeof(struct uhci_pipe);
@@ -639,8 +637,6 @@
callout_halt(&sc->sc_poll_handle, NULL);
callout_destroy(&sc->sc_poll_handle);
- cv_destroy(&sc->sc_softwake_cv);
-
mutex_destroy(&sc->sc_lock);
mutex_destroy(&sc->sc_intr_lock);
@@ -1422,11 +1418,6 @@
DPRINTF("ux %p", ux, 0, 0, 0);
usb_transfer_complete(&ux->ux_xfer);
}
-
- if (sc->sc_softwake) {
- sc->sc_softwake = 0;
- cv_broadcast(&sc->sc_softwake_cv);
- }
}
/* Check for an interrupt. */
@@ -1482,8 +1473,6 @@
if (!(status & UHCI_TD_ACTIVE)) {
done:
DPRINTFN(12, "ux=%p done", ux, 0, 0, 0);
-
- callout_stop(&xfer->ux_callout);
uhci_idone(ux, cqp);
return;
}
@@ -1554,18 +1543,30 @@
void
uhci_idone(struct uhci_xfer *ux, ux_completeq_t *cqp)
{
+ UHCIHIST_FUNC(); UHCIHIST_CALLED();
struct usbd_xfer *xfer = &ux->ux_xfer;
uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer);
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
uhci_soft_td_t *std;
uint32_t status = 0, nstatus;
+ bool polling = sc->sc_bus.ub_usepolling;
int actlen;
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
- UHCIHIST_FUNC(); UHCIHIST_CALLED();
DPRINTFN(12, "ux=%p", ux, 0, 0, 0);
+ /*
+ * Make sure the timeout handler didn't run or ran to the end
+ * and set the transfer status.
+ */
+ callout_halt(&xfer->ux_callout, polling ? NULL : &sc->sc_lock);
+ if (xfer->ux_status == USBD_CANCELLED ||
+ xfer->ux_status == USBD_TIMEOUT) {
+ DPRINTF("aborted xfer=%p", xfer, 0, 0, 0);
+ return;
+ }
+
#ifdef DIAGNOSTIC
#ifdef UHCI_DEBUG
if (ux->ux_isdone) {
@@ -1699,26 +1700,32 @@
void
uhci_timeout(void *addr)
{
+ UHCIHIST_FUNC(); UHCIHIST_CALLED();
struct usbd_xfer *xfer = addr;
- struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-
- UHCIHIST_FUNC(); UHCIHIST_CALLED();
-
- DPRINTF("uxfer %p", uxfer, 0, 0, 0);
-
+ bool timeout = false;
+
+ DPRINTF("xfer %p", xfer, 0, 0, 0);
+
+ mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
- mutex_enter(&sc->sc_lock);
- uhci_abort_xfer(xfer, USBD_TIMEOUT);
mutex_exit(&sc->sc_lock);
return;
}
-
- /* Execute the abort in a process context. */
- usb_init_task(&xfer->ux_aborttask, uhci_timeout_task, xfer,
- USB_TASKQ_MPSAFE);
- usb_add_task(uxfer->ux_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, uhci_timeout_task, xfer,
+ USB_TASKQ_MPSAFE);
+ usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC);
+ }
}
void
@@ -1732,6 +1739,7 @@
DPRINTF("xfer=%p", xfer, 0, 0, 0);
mutex_enter(&sc->sc_lock);
+ KASSERT(xfer->ux_status == USBD_TIMEOUT);
uhci_abort_xfer(xfer, USBD_TIMEOUT);
mutex_exit(&sc->sc_lock);
}
@@ -2323,16 +2331,18 @@
}
/*
- * Abort a device request.
- * If this routine is called at splusb() it guarantees that the request
- * will be removed from the hardware scheduling and that the callback
- * for it will be called with USBD_CANCELLED status.
+ * Cancel or timeout a device request. We have two cases to deal with
+ *
+ * 1) A driver wants to stop scheduled or inflight transfers
+ * 2) A transfer has timed out
+ *
* It's impossible to guarantee that the requested transfer will not
- * have happened since the hardware runs concurrently.
- * If the transaction has already happened we rely on the ordinary
- * interrupt processing to process it.
- * XXX This is most probably wrong.
- * XXXMRG this doesn't make sense anymore.
+ * have (partially) happened since the hardware runs concurrently.
+ *
+ * Transfer state is protected by the bus lock and we set the transfer status
+ * as soon as either of the above happens (with bus lock held).
+ *
+ * To allow the hardware time to notice we simply wait.
*/
void
uhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
@@ -2378,10 +2388,20 @@
xfer->ux_hcflags |= UXFER_ABORTING;
/*
- * Step 1: Make interrupt routine and hardware ignore xfer.
+ * 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; /* make software ignore it */
- 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: Make interrupt routine and hardware ignore xfer.
+ */
uhci_del_intr_list(sc, ux);
DPRINTF("stop ux=%p", ux, 0, 0, 0);
@@ -2398,19 +2418,15 @@
}
/*
- * Step 2: Wait until we know hardware has finished any possible
+ * Step 3: Wait until we know hardware has finished any possible
* use of the xfer. Also make sure the soft interrupt routine
* has run.
*/
/* Hardware finishes in 1ms */
usb_delay_ms_locked(upipe->pipe.up_dev->ud_bus, 2, &sc->sc_lock);
- sc->sc_softwake = 1;
- usb_schedsoftintr(&sc->sc_bus);
- DPRINTF("cv_wait", 0, 0, 0, 0);
- cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
/*
- * Step 3: Execute callback.
+ * Step 4: Execute callback.
*/
DPRINTF("callback", 0, 0, 0, 0);
#ifdef DIAGNOSTIC
diff -r 5b5245efd868 -r 9c9ae5579cfe sys/dev/usb/uhcivar.h
--- a/sys/dev/usb/uhcivar.h Wed Dec 28 09:45:16 2016 +0000
+++ b/sys/dev/usb/uhcivar.h Wed Dec 28 10:25:06 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uhcivar.h,v 1.52.14.18 2016/04/30 10:34:14 skrll Exp $ */
+/* $NetBSD: uhcivar.h,v 1.52.14.19 2016/12/28 10:25:06 skrll Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -151,7 +151,6 @@
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
- kcondvar_t sc_softwake_cv;
uhci_physaddr_t *sc_pframes;
usb_dma_t sc_dma;
@@ -174,8 +173,6 @@
uint8_t sc_saved_sof;
uint16_t sc_saved_frnum;
- char sc_softwake;
-
char sc_isreset;
char sc_suspend;
char sc_dying;
Home |
Main Index |
Thread Index |
Old Index