Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Replace the workque for status changes with an u...



details:   https://anonhg.NetBSD.org/src/rev/ead33a9520a0
branches:  trunk
changeset: 794714:ead33a9520a0
user:      martin <martin%NetBSD.org@localhost>
date:      Sat Mar 22 20:56:04 2014 +0000

description:
Replace the workque for status changes with an usb task queue (hint from
Nick Hudson) - simpler for this, and avoids some races.

diffstat:

 sys/dev/usb/umcs.c |  47 ++++++++++++++++++++---------------------------
 1 files changed, 20 insertions(+), 27 deletions(-)

diffs (157 lines):

diff -r b10d1d39a809 -r ead33a9520a0 sys/dev/usb/umcs.c
--- a/sys/dev/usb/umcs.c        Sat Mar 22 20:36:45 2014 +0000
+++ b/sys/dev/usb/umcs.c        Sat Mar 22 20:56:04 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: umcs.c,v 1.4 2014/03/17 21:21:57 martin Exp $ */
+/* $NetBSD: umcs.c,v 1.5 2014/03/22 20:56:04 martin Exp $ */
 /* $FreeBSD: head/sys/dev/usb/serial/umcs.c 260559 2014-01-12 11:44:28Z hselasky $ */
 
 /*-
@@ -41,7 +41,7 @@
  *
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umcs.c,v 1.4 2014/03/17 21:21:57 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umcs.c,v 1.5 2014/03/22 20:56:04 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -51,7 +51,6 @@
 #include <sys/tty.h>
 #include <sys/device.h>
 #include <sys/kmem.h>
-#include <sys/workqueue.h>
 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
@@ -79,7 +78,9 @@
  */
 struct umcs7840_softc_oneport {
        device_t sc_port_ucom;          /* ucom subdevice */
-       uint32_t sc_port_changed;       /* call ucom_status_change() */
+       volatile uint32_t               /* changes for this port have */
+               sc_port_changed;        /* been signaled,
+                                          call ucom_status_change() */
        unsigned int sc_port_phys;      /* physical port number */
        uint8_t sc_port_lcr;            /* local line control register */
        uint8_t sc_port_mcr;            /* local modem control register */
@@ -92,8 +93,7 @@
        usbd_pipe_handle sc_intr_pipe;  /* interrupt pipe */
        uint8_t *sc_intr_buf;           /* buffer for interrupt xfer */
        unsigned int sc_intr_buflen;    /* size of buffer */
-       struct workqueue *sc_change_wq; /* workqueue for status changes */
-       struct work sc_work;            /* work for said workqueue.  */
+       struct usb_task sc_change_task; /* async status changes */
        struct umcs7840_softc_oneport sc_ports[UMCS7840_MAX_PORTS];
                                        /* data for each port */
        uint8_t sc_numports;            /* number of ports (subunits) */
@@ -114,7 +114,7 @@
 static void umcs7840_attach(device_t, device_t, void *);
 static int umcs7840_detach(device_t, int);
 static void umcs7840_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status);
-static void umcs7840_change_worker(struct work *w, void *arg);
+static void umcs7840_change_task(void *arg);
 static int umcs7840_activate(device_t, enum devact); 
 static void umcs7840_childdet(device_t, device_t);
 
@@ -294,11 +294,8 @@
                return;
        }
 
-       if (workqueue_create(&sc->sc_change_wq, "umcsq",
-               umcs7840_change_worker, sc, PRI_NONE, IPL_USB, WQ_MPSAFE)) {
-               aprint_error_dev(self, "workqueue creation failed\n");
-               return;
-        }
+       usb_init_task(&sc->sc_change_task, umcs7840_change_task, sc,
+           USB_TASKQ_MPSAFE);
 
        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
            sc->sc_dev);
@@ -534,8 +531,7 @@
                kmem_free(sc->sc_intr_buf, sc->sc_intr_buflen);
                sc->sc_intr_pipe = NULL;
        }
-       if (sc->sc_change_wq != NULL)
-               workqueue_destroy(sc->sc_change_wq);
+       usb_rem_task(sc->sc_udev, &sc->sc_change_task);
 
        /* detach children */
        for (i = 0; i < sc->sc_numports; i++) {
@@ -856,8 +852,6 @@
        int ctrlreg = umcs7840_reg_ctrl(pn);
        uint8_t data;
 
-       atomic_swap_32(&sc->sc_ports[portno].sc_port_changed, 0);
-
        if (sc->sc_dying)
                return;
 
@@ -879,13 +873,12 @@
        struct umcs7840_softc *sc = priv;
        u_char *buf = sc->sc_intr_buf;
        int actlen;
-       int subunit, found;
+       int subunit;
 
        if (status == USBD_NOT_STARTED || status == USBD_CANCELLED
            || status == USBD_IOERROR)
                return;
 
-       found = 0;
        if (status != USBD_NORMAL_COMPLETION) {
                aprint_error_dev(sc->sc_dev,
                    "umcs7840_intr: abnormal status: %s\n",
@@ -896,6 +889,7 @@
 
        usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL);
        if (actlen == 5 || actlen == 13) {
+               usb_rem_task(sc->sc_udev, &sc->sc_change_task);
                /* Check status of all ports */
                for (subunit = 0; subunit < sc->sc_numports; subunit++) {
                        uint8_t pn = sc->sc_ports[subunit].sc_port_phys;
@@ -910,19 +904,17 @@
                        case MCS7840_UART_ISR_RXHASDATA:
                        case MCS7840_UART_ISR_RXTIMEOUT:
                        case MCS7840_UART_ISR_MSCHANGE:
-                               atomic_swap_32(
-                                   &sc->sc_ports[subunit].sc_port_changed,
-                                   1);
-                               found++;
+                               sc->sc_ports[subunit].sc_port_changed = 1;
                                break;
                        default:
                                /* Do nothing */
                                break;
                        }
                }
-               if (found)
-                       workqueue_enqueue(sc->sc_change_wq, &sc->sc_work,
-                           NULL);
+
+               membar_exit();
+               usb_add_task(sc->sc_udev, &sc->sc_change_task,
+                   USB_TASKQ_DRIVER);
        } else {
                aprint_error_dev(sc->sc_dev,
                   "Invalid interrupt data length %d", actlen);
@@ -930,16 +922,17 @@
 }
 
 static void
-umcs7840_change_worker(struct work *w, void *arg)
+umcs7840_change_task(void *arg)
 {
        struct umcs7840_softc *sc = arg;
        int i;
 
        for (i = 0; i < sc->sc_numports; i++) {
                if (sc->sc_ports[i].sc_port_changed) {
+                       sc->sc_ports[i].sc_port_changed = 0;
+                       membar_exit();
                        ucom_status_change(device_private(
                            sc->sc_ports[i].sc_port_ucom));
-                       atomic_swap_32(&sc->sc_ports[i].sc_port_changed, 0);
                }
        }
 }



Home | Main Index | Thread Index | Old Index