Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb Fix transfer aborts and bump the workqueue to IP...
details: https://anonhg.NetBSD.org/src/rev/5080105f7e5b
branches: trunk
changeset: 784642:5080105f7e5b
user: skrll <skrll%NetBSD.org@localhost>
date: Mon Feb 04 21:24:07 2013 +0000
description:
Fix transfer aborts and bump the workqueue to IPL_BIO.
diffstat:
sys/dev/usb/dwc_otg.c | 114 +++++++++++++++++++++++++++-------------------
sys/dev/usb/dwc_otgvar.h | 6 +-
2 files changed, 69 insertions(+), 51 deletions(-)
diffs (truncated from 321 to 300 lines):
diff -r 4beb3904d45b -r 5080105f7e5b sys/dev/usb/dwc_otg.c
--- a/sys/dev/usb/dwc_otg.c Mon Feb 04 20:28:24 2013 +0000
+++ b/sys/dev/usb/dwc_otg.c Mon Feb 04 21:24:07 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_otg.c,v 1.42 2013/02/03 22:25:39 skrll Exp $ */
+/* $NetBSD: dwc_otg.c,v 1.43 2013/02/04 21:24:07 skrll Exp $ */
/*-
* Copyright (c) 2012 Hans Petter Selasky. All rights reserved.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc_otg.c,v 1.42 2013/02/03 22:25:39 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_otg.c,v 1.43 2013/02/04 21:24:07 skrll Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -190,9 +190,7 @@
Static void dwc_otg_device_isoc_close(usbd_pipe_handle);
Static void dwc_otg_device_isoc_done(usbd_xfer_handle);
-#if 0
-Static void dwc_otg_close_pipe(usbd_pipe_handle, dwc_otg_soft_ed_t *);
-#endif
+Static void dwc_otg_close_pipe(usbd_pipe_handle);
Static void dwc_otg_abort_xfer(usbd_xfer_handle, usbd_status);
Static void dwc_otg_device_clear_toggle(usbd_pipe_handle pipe);
@@ -247,6 +245,7 @@
Static void dwc_otg_standard_done(usbd_xfer_handle);
Static void dwc_otg_setup_standard_chain(usbd_xfer_handle);
Static void dwc_otg_start_standard_chain(usbd_xfer_handle);
+Static void dwc_otg_host_channel_free(struct dwc_otg_td *);
Static void dwc_otg_core_reset(struct dwc_otg_softc *sc);
@@ -425,6 +424,12 @@
mutex_spin_enter(&sc->sc_intr_lock);
while ((dxfer = TAILQ_FIRST(&sc->sc_complete)) != NULL) {
TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext);
+
+ if (dxfer->xfer.hcflags & UXFER_ABORTING) {
+ cv_broadcast(&dxfer->xfer.hccv);
+ continue;
+ }
+
mutex_spin_exit(&sc->sc_intr_lock);
usb_transfer_complete(&dxfer->xfer);
mutex_spin_enter(&sc->sc_intr_lock);
@@ -577,21 +582,20 @@
mutex_spin_exit(&sc->sc_intr_lock);
}
-#if 0
/*
* Close a reqular pipe.
* Assumes that there are no pending transactions.
*/
Static void
-dwc_otg_close_pipe(usbd_pipe_handle pipe, dwc_otg_soft_ed_t *head)
+dwc_otg_close_pipe(usbd_pipe_handle pipe)
{
struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)pipe;
struct dwc_otg_softc *sc = pipe->device->bus->hci_private;
dpipe = dpipe;
- usb_delay_ms(&sc->sc_bus, 1);
+
+ KASSERT(mutex_owned(&sc->sc_lock));
}
-#endif
/*
* Abort a device request.
@@ -616,6 +620,10 @@
return;
}
+ /*
+ * If an abort is already in progress then just wait for it to
+ * complete and return.
+ */
if (xfer->hcflags & UXFER_ABORTING) {
xfer->status = status;
xfer->hcflags |= UXFER_ABORTWAIT;
@@ -623,39 +631,32 @@
cv_wait(&xfer->hccv, &sc->sc_lock);
return;
}
- xfer->hcflags |= UXFER_ABORTING;
/*
* Step 1: Make interrupt routine and hardware ignore xfer.
*/
+ mutex_spin_enter(&sc->sc_intr_lock);
+ xfer->hcflags |= UXFER_ABORTING;
+
xfer->status = status; /* make software ignore it */
callout_stop(&xfer->timeout_handle);
- if (dxfer->td_transfer_cache) {
- int ch = dxfer->td_transfer_cache->channel;
- if (ch < DWC_OTG_MAX_CHANNELS) {
-
- DPRINTF("Disabling channel %d\n", ch);
- DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(ch),
- HCINTMSK_CHHLTDMSK);
- DWC_OTG_WRITE_4(sc, DOTG_HCINT(ch),
- ~HCINTMSK_CHHLTDMSK);
-
- if ((DWC_OTG_READ_4(sc, DOTG_HCCHAR(ch)) &
- HCCHAR_CHENA) != 0) {
- DWC_OTG_MODIFY_4(sc, DOTG_HCCHAR(ch),
- HCCHAR_CHENA, HCCHAR_CHDIS);
- }
- }
+ if (dxfer->active) {
+ TAILQ_REMOVE(&sc->sc_active, dxfer, xnext);
+ dxfer->active = false;
}
-
- mutex_spin_enter(&sc->sc_intr_lock);
- dxfer->queued = false;
- TAILQ_REMOVE(&sc->sc_active, dxfer, xnext);
mutex_spin_exit(&sc->sc_intr_lock);
+ if (dxfer->td_transfer_cache != NULL) {
+ dwc_otg_host_channel_free(dxfer->td_transfer_cache);
+ }
+
+ while (dxfer->queued) {
+ cv_wait(&xfer->hccv, &sc->sc_lock);
+ }
+
/*
- * Step 4: Execute callback.
+ * Step 2: Execute callback.
*/
wake = xfer->hcflags & UXFER_ABORTWAIT;
xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
@@ -1136,9 +1137,8 @@
err = USBD_NORMAL_COMPLETION;
fail:
- xfer->status = err;
-
mutex_enter(&sc->sc_lock);
+ xfer->status = err;
usb_transfer_complete(xfer);
mutex_exit(&sc->sc_lock);
@@ -1307,7 +1307,10 @@
dpipe = dpipe;
sc = sc;
+
DPRINTF("\n");
+
+ dwc_otg_close_pipe(pipe);
}
Static void
@@ -1390,6 +1393,8 @@
dpipe = dpipe;
sc = sc;
+
+ dwc_otg_close_pipe(pipe);
}
Static void
@@ -1475,6 +1480,8 @@
dpipe = dpipe;
sc = sc;
DPRINTF("\n");
+
+ dwc_otg_close_pipe(pipe);
}
Static void
@@ -1583,6 +1590,8 @@
dpipe = dpipe;
sc = sc;
DPRINTF("\n");
+
+ dwc_otg_close_pipe(pipe);
}
void
@@ -1653,6 +1662,7 @@
struct dwc_otg_work *dwork = (struct dwc_otg_work *)wk;
struct dwc_otg_softc *sc = priv;
usbd_xfer_handle xfer = dwork->xfer;
+ struct dwc_otg_xfer *dxfer = DWC_OTG_XFER2DXFER(xfer);
DOTG_EVCNT_INCR(sc->sc_ev_work);
@@ -1661,7 +1671,13 @@
dwc_otg_timer(sc);
} else {
KASSERT(dwork->xfer != NULL);
- dwc_otg_start_standard_chain(xfer);
+ KASSERT(dxfer->queued == true);
+
+ if (!(xfer->hcflags & UXFER_ABORTING)) {
+ dwc_otg_start_standard_chain(xfer);
+ }
+ dxfer->queued = false;
+ cv_broadcast(&xfer->hccv);
}
mutex_exit(&sc->sc_lock);
}
@@ -2311,7 +2327,7 @@
}
}
-static void
+Static void
dwc_otg_host_channel_free(struct dwc_otg_td *td)
{
struct dwc_otg_softc *sc;
@@ -3332,6 +3348,9 @@
}
TAILQ_FOREACH(dxfer, &sc->sc_active, xnext) {
+ if (dxfer->xfer.hcflags & UXFER_ABORTING)
+ continue;
+
if (!dwc_otg_xfer_do_fifo(&dxfer->xfer)) {
/* queue has been modified */
goto repeat;
@@ -3834,6 +3853,8 @@
// DPRINTF(("%s: xfer->length %d\n", __func__, xfer->length));
+ dxfer->queued = false;
+
/* get first again */
td = dxfer->td_transfer_first;
td->toggle = dpipe->pipe.endpoint->datatoggle;
@@ -3946,13 +3967,8 @@
KASSERT(mutex_owned(&sc->sc_lock));
/* put transfer on interrupt queue */
- if (!dxfer->queued) {
- dxfer->queued = true;
- TAILQ_INSERT_TAIL(&sc->sc_active, dxfer, xnext);
- } else {
- printf("%s: xfer %p already queued\n", __func__,
- xfer);
- }
+ dxfer->active = true;
+ TAILQ_INSERT_TAIL(&sc->sc_active, dxfer, xnext);
/* start timeout, if any */
if (xfer->timeout != 0) {
@@ -4043,11 +4059,12 @@
dwc_otg_host_channel_free(td);
xfer->status = err;
- TAILQ_REMOVE(&sc->sc_active, dxfer, xnext);
-
+ if (dxfer->active) {
+ TAILQ_REMOVE(&sc->sc_active, dxfer, xnext);
+ dxfer->active = false;
+ }
callout_stop(&xfer->timeout_handle);
- dxfer->queued = false;
TAILQ_INSERT_TAIL(&sc->sc_complete, dxfer, xnext);
usb_schedsoftintr(&sc->sc_bus);
@@ -4097,7 +4114,7 @@
sc->sc_rhc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
dwc_otg_rhc, sc);
- workqueue_create(&sc->sc_wq, xname, dwc_otg_worker, sc, PRI_NONE,
+ workqueue_create(&sc->sc_wq, xname, dwc_otg_worker, sc, PRI_BIO,
IPL_USB, WQ_MPSAFE);
usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag,
@@ -4389,8 +4406,9 @@
if (sc->sc_bus.use_polling) {
dwc_otg_start_standard_chain(xfer);
} else {
- workqueue_enqueue(sc->sc_wq,
- (struct work *)&dxfer->work, NULL);
+ KASSERT(dxfer->queued == false);
+ dxfer->queued = true;
+ workqueue_enqueue(sc->sc_wq, (struct work *)&dxfer->work, NULL);
}
}
diff -r 4beb3904d45b -r 5080105f7e5b sys/dev/usb/dwc_otgvar.h
--- a/sys/dev/usb/dwc_otgvar.h Mon Feb 04 20:28:24 2013 +0000
+++ b/sys/dev/usb/dwc_otgvar.h Mon Feb 04 21:24:07 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_otgvar.h,v 1.9 2013/01/31 12:41:41 skrll Exp $ */
+/* $NetBSD: dwc_otgvar.h,v 1.10 2013/02/04 21:24:07 skrll Exp $ */
Home |
Main Index |
Thread Index |
Old Index