Source-Changes-HG archive

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

[src/netbsd-6]: src/sys/dev/usb Pull up following revision(s) (requested by s...



details:   https://anonhg.NetBSD.org/src/rev/ace44aa2d6dc
branches:  netbsd-6
changeset: 775707:ace44aa2d6dc
user:      riz <riz%NetBSD.org@localhost>
date:      Mon Feb 18 18:13:05 2013 +0000

description:
Pull up following revision(s) (requested by skrll in ticket #827):
        sys/dev/usb/dwc_otg.c: revision 1.46
        sys/dev/usb/dwc_otgvar.h: revision 1.12
Track transfer state better to avoid races between the workqueue and
aborting.

diffstat:

 sys/dev/usb/dwc_otg.c    |  60 +++++++++++++++++++++++++++++++++--------------
 sys/dev/usb/dwc_otgvar.h |  12 +++++++--
 2 files changed, 51 insertions(+), 21 deletions(-)

diffs (177 lines):

diff -r 8268313c897a -r ace44aa2d6dc sys/dev/usb/dwc_otg.c
--- a/sys/dev/usb/dwc_otg.c     Mon Feb 18 18:10:58 2013 +0000
+++ b/sys/dev/usb/dwc_otg.c     Mon Feb 18 18:13:05 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: dwc_otg.c,v 1.45.2.3 2013/02/15 08:21:21 msaitoh Exp $ */
+/*     $NetBSD: dwc_otg.c,v 1.45.2.4 2013/02/18 18:13:05 riz 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.45.2.3 2013/02/15 08:21:21 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_otg.c,v 1.45.2.4 2013/02/18 18:13:05 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -411,13 +411,20 @@
 
        mutex_spin_enter(&sc->sc_intr_lock);
        while ((dxfer = TAILQ_FIRST(&sc->sc_complete)) != NULL) {
-               TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext);
-
+               KASSERT(dxfer->state == DXFER_COMPLETING);
+
+               /*
+                * dwc_otg_abort_xfer will remove this transfer from the
+                * sc_complete queue
+                */
                if (dxfer->xfer.hcflags & UXFER_ABORTING) {
                        wakeup(&dxfer->xfer.hcflags);
                        continue;
                }
 
+               TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext);
+               dxfer->state = DXFER_DONE;
+
                mutex_spin_exit(&sc->sc_intr_lock);
                usb_transfer_complete(&dxfer->xfer);
                mutex_spin_enter(&sc->sc_intr_lock);
@@ -616,9 +623,23 @@
        xfer->status = status;  /* make software ignore it */
        callout_stop(&xfer->timeout_handle);
 
-       if (dxfer->active) {
+       switch (dxfer->state) {
+       case DXFER_INIT:
+               dxfer->state = DXFER_ABORTING;
+               break;
+       case DXFER_WORKQ:
+               /* Give the workqueue a chance */
+               break;
+       case DXFER_ACTIVE:
                TAILQ_REMOVE(&sc->sc_active, dxfer, xnext);
-               dxfer->active = false;
+               dxfer->state = DXFER_ABORTING;
+               break;
+       case DXFER_COMPLETING:
+               TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext);
+               dxfer->state = DXFER_ABORTING;
+               break;
+       default:
+               KASSERT(false);
        }
        mutex_spin_exit(&sc->sc_intr_lock);
 
@@ -626,10 +647,11 @@
                dwc_otg_host_channel_free(dxfer->td_transfer_cache);
        }
 
-       while (dxfer->queued) {
-               wakeup(&xfer->hcflags);
+       while (dxfer->state != DXFER_ABORTING) {
+               tsleep(&xfer->hcflags, PZERO, "dotgxw", 0);
        }
 
+       dxfer->state = DXFER_DONE;
        /*
         * Step 2: Execute callback.
         */
@@ -1598,15 +1620,15 @@
                dwc_otg_timer(sc);
        } else {
                KASSERT(dwork->xfer != NULL);
-               KASSERT(dxfer->queued == true);
+               KASSERT(dxfer->state == DXFER_WORKQ);
 
                if (!(xfer->hcflags & UXFER_ABORTING)) {
                        dwc_otg_start_standard_chain(xfer);
+               } else {
+                       dxfer->state = DXFER_ABORTING;
+                       wakeup(&xfer->hcflags);
                }
-               dxfer->queued = false;
-               wakeup(&xfer->hcflags);
        }
-
 }
 
 int dwc_otg_intr(void *p)
@@ -3778,7 +3800,7 @@
 
 //     DPRINTF(("%s: xfer->length %d\n", __func__, xfer->length));
 
-       dxfer->queued = false;
+       dxfer->state = DXFER_INIT;
 
        /* get first again */
        td = dxfer->td_transfer_first;
@@ -3887,11 +3909,13 @@
 
        /* poll one time - will turn on interrupts */
        mutex_spin_enter(&sc->sc_intr_lock);
+       dxfer->state = DXFER_STARTED;
+
        if (dwc_otg_xfer_do_fifo(xfer)) {
 
                /* put transfer on interrupt queue */
 
-               dxfer->active = true;
+               dxfer->state = DXFER_ACTIVE;
                TAILQ_INSERT_TAIL(&sc->sc_active, dxfer, xnext);
 
                /* start timeout, if any */
@@ -3980,12 +4004,12 @@
                dwc_otg_host_channel_free(td);
 
        xfer->status = err;
-       if (dxfer->active) {
+       if (dxfer->state == DXFER_ACTIVE) {
                TAILQ_REMOVE(&sc->sc_active, dxfer, xnext);
-               dxfer->active = false;
        }
        callout_stop(&xfer->timeout_handle);
 
+       dxfer->state = DXFER_COMPLETING;
        TAILQ_INSERT_TAIL(&sc->sc_complete, dxfer, xnext);
 
        usb_schedsoftintr(&sc->sc_bus);
@@ -4324,8 +4348,8 @@
        if (sc->sc_bus.use_polling) {
                dwc_otg_start_standard_chain(xfer);
        } else {
-               KASSERT(dxfer->queued == false);
-               dxfer->queued = true;
+               KASSERT(dxfer->state == DXFER_INIT);
+               dxfer->state = DXFER_WORKQ;
                workqueue_enqueue(sc->sc_wq, (struct work *)&dxfer->work, NULL);
        }
 }
diff -r 8268313c897a -r ace44aa2d6dc sys/dev/usb/dwc_otgvar.h
--- a/sys/dev/usb/dwc_otgvar.h  Mon Feb 18 18:10:58 2013 +0000
+++ b/sys/dev/usb/dwc_otgvar.h  Mon Feb 18 18:13:05 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: dwc_otgvar.h,v 1.11.2.3 2013/02/14 21:50:41 riz Exp $ */
+/*     $NetBSD: dwc_otgvar.h,v 1.11.2.4 2013/02/18 18:13:05 riz Exp $ */
 
 /* $FreeBSD: src/sys/dev/usb/controller/dwc_otg.h,v 1.12 2012/09/27 15:23:38 hselasky Exp $ */
 /*-
@@ -158,8 +158,14 @@
        struct usbd_xfer xfer;                  /* Needs to be first */
        struct usb_task abort_task;
        TAILQ_ENTRY(dwc_otg_xfer) xnext;        /* list of active/complete xfers */
-       bool            queued;                 /* pending workqueue */
-       bool            active;                 /* still active */
+       int     state;
+#define DXFER_INIT             0
+#define DXFER_WORKQ            1
+#define DXFER_STARTED          2
+#define DXFER_ACTIVE           3
+#define DXFER_COMPLETING       4
+#define DXFER_ABORTING         5
+#define DXFER_DONE             6
 
        void            *td_start[1];
        dwc_otg_td_t    *td_transfer_first;



Home | Main Index | Thread Index | Old Index