Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Optimize for higher speeds, e.g. when used as pa...



details:   https://anonhg.NetBSD.org/src/rev/6fdecf8e2209
branches:  trunk
changeset: 750563:6fdecf8e2209
user:      martin <martin%NetBSD.org@localhost>
date:      Wed Jan 06 20:37:56 2010 +0000

description:
Optimize for higher speeds, e.g. when used as part of a 3G modem.
Contributed anonymously.

diffstat:

 sys/dev/usb/ucom.c |  561 +++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 376 insertions(+), 185 deletions(-)

diffs (truncated from 877 to 300 lines):

diff -r 2da6612c0de5 -r 6fdecf8e2209 sys/dev/usb/ucom.c
--- a/sys/dev/usb/ucom.c        Wed Jan 06 20:16:57 2010 +0000
+++ b/sys/dev/usb/ucom.c        Wed Jan 06 20:37:56 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ucom.c,v 1.81 2009/12/06 21:40:31 dyoung Exp $ */
+/*     $NetBSD: ucom.c,v 1.82 2010/01/06 20:37:56 martin Exp $ */
 
 /*
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.81 2009/12/06 21:40:31 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.82 2010/01/06 20:37:56 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -48,6 +48,7 @@
 #include <sys/vnode.h>
 #include <sys/device.h>
 #include <sys/poll.h>
+#include <sys/queue.h>
 #include <sys/kauth.h>
 #if defined(__NetBSD__)
 #include "rnd.h"
@@ -87,6 +88,22 @@
 #define        UCOMDIALOUT(x)          (minor(x) & UCOMDIALOUT_MASK)
 #define        UCOMCALLUNIT(x)         (minor(x) & UCOMCALLUNIT_MASK)
 
+/*
+ * XXX: We can submit multiple input/output buffers to the usb stack
+ * to improve throughput, but the usb stack is too lame to deal with this
+ * in a number of places.
+ */
+#define        UCOM_IN_BUFFS   1
+#define        UCOM_OUT_BUFFS  1
+
+struct ucom_buffer {
+       SIMPLEQ_ENTRY(ucom_buffer) ub_link;
+       usbd_xfer_handle ub_xfer;
+       u_char *ub_data;
+       u_int ub_len;
+       u_int ub_index;
+};
+
 struct ucom_softc {
        USBBASEDEVICE           sc_dev;         /* base device */
 
@@ -96,18 +113,21 @@
 
        int                     sc_bulkin_no;   /* bulk in endpoint address */
        usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */
-       usbd_xfer_handle        sc_ixfer;       /* read request */
-       u_char                  *sc_ibuf;       /* read buffer */
        u_int                   sc_ibufsize;    /* read buffer size */
        u_int                   sc_ibufsizepad; /* read buffer size padded */
+       struct ucom_buffer      sc_ibuff[UCOM_IN_BUFFS];
+       SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_empty;
+       SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_full;
 
        int                     sc_bulkout_no;  /* bulk out endpoint address */
        usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */
-       usbd_xfer_handle        sc_oxfer;       /* write request */
-       u_char                  *sc_obuf;       /* write buffer */
        u_int                   sc_obufsize;    /* write buffer size */
-       u_int                   sc_opkthdrlen;  /* header length of
-                                                * output packet */
+       u_int                   sc_opkthdrlen;  /* header length of */
+       struct ucom_buffer      sc_obuff[UCOM_OUT_BUFFS];
+       SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_free;
+       SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_full;
+
+       void                    *sc_si;
 
        struct ucom_methods     *sc_methods;
        void                    *sc_parent;
@@ -117,6 +137,8 @@
        u_char                  sc_lsr;
        u_char                  sc_msr;
        u_char                  sc_mcr;
+       volatile u_char         sc_rx_stopped;
+       u_char                  sc_rx_unblock;
        u_char                  sc_tx_stopped;
        int                     sc_swflags;
 
@@ -143,21 +165,28 @@
        ucomstop, ucomtty, ucompoll, nommap, ttykqfilter, D_TTY
 };
 
-Static void    ucom_cleanup(struct ucom_softc *);
-Static void    ucom_hwiflow(struct ucom_softc *);
-Static int     ucomparam(struct tty *, struct termios *);
-Static void    ucomstart(struct tty *);
-Static void    ucom_shutdown(struct ucom_softc *);
-Static int     ucom_do_ioctl(struct ucom_softc *, u_long, void *,
+static void    ucom_cleanup(struct ucom_softc *);
+static int     ucomparam(struct tty *, struct termios *);
+static int     ucomhwiflow(struct tty *, int);
+static void    ucomstart(struct tty *);
+static void    ucom_shutdown(struct ucom_softc *);
+static int     ucom_do_ioctl(struct ucom_softc *, u_long, void *,
                              int, struct lwp *);
-Static void    ucom_dtr(struct ucom_softc *, int);
-Static void    ucom_rts(struct ucom_softc *, int);
-Static void    ucom_break(struct ucom_softc *, int);
-Static usbd_status ucomstartread(struct ucom_softc *);
-Static void    ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
-Static void    ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
-Static void    tiocm_to_ucom(struct ucom_softc *, u_long, int);
-Static int     ucom_to_tiocm(struct ucom_softc *);
+static void    ucom_dtr(struct ucom_softc *, int);
+static void    ucom_rts(struct ucom_softc *, int);
+static void    ucom_break(struct ucom_softc *, int);
+static void    tiocm_to_ucom(struct ucom_softc *, u_long, int);
+static int     ucom_to_tiocm(struct ucom_softc *);
+
+static void    ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
+static void    ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
+static void    ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
+                       usbd_status);
+
+static void    ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
+static void    ucom_read_complete(struct ucom_softc *);
+static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
+static void    ucom_softintr(void *);
 
 USB_DECLARE_DRIVER(ucom);
 
@@ -189,9 +218,21 @@
        sc->sc_parent = uca->arg;
        sc->sc_portno = uca->portno;
 
+       sc->sc_lsr = 0;
+       sc->sc_msr = 0;
+       sc->sc_mcr = 0;
+       sc->sc_tx_stopped = 0;
+       sc->sc_swflags = 0;
+       sc->sc_opening = 0;
+       sc->sc_refcnt = 0;
+       sc->sc_dying = 0;
+
+       sc->sc_si = softint_establish(SOFTINT_NET, ucom_softintr, sc);
+
        tp = ttymalloc();
        tp->t_oproc = ucomstart;
        tp->t_param = ucomparam;
+       tp->t_hwiflow = ucomhwiflow;
        sc->sc_tty = tp;
 
        DPRINTF(("ucom_attach: tty_attach %p\n", tp));
@@ -212,7 +253,7 @@
        struct ucom_softc *sc = device_private(self);
        struct tty *tp = sc->sc_tty;
        int maj, mn;
-       int s;
+       int s, i;
 
        DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
                 sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
@@ -238,6 +279,8 @@
                /* Wait for processes to go away. */
                usb_detach_wait(USBDEV(sc->sc_dev));
        }
+
+       softint_disestablish(sc->sc_si);
        splx(s);
 
        /* locate the major number */
@@ -257,6 +300,16 @@
                sc->sc_tty = NULL;
        }
 
+       for (i = 0; i < UCOM_IN_BUFFS; i++) {
+               if (sc->sc_ibuff[i].ub_xfer != NULL)
+                       usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
+       }
+
+       for (i = 0; i < UCOM_OUT_BUFFS; i++) {
+               if (sc->sc_obuff[i].ub_xfer != NULL)
+                       usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
+       }
+
        /* Detach the random source */
 #if defined(__NetBSD__) && NRND > 0
        rnd_detach_source(&sc->sc_rndsource);
@@ -303,8 +356,9 @@
        int unit = UCOMUNIT(dev);
        usbd_status err;
        struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
+       struct ucom_buffer *ub;
        struct tty *tp;
-       int s;
+       int s, i;
        int error;
 
        if (sc == NULL)
@@ -388,15 +442,12 @@
                ucom_dtr(sc, 1);
                ucom_rts(sc, 1);                
 
-               /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
-               ucom_hwiflow(sc);
-
                DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
                         sc->sc_bulkin_no, sc->sc_bulkout_no));
 
                /* Open the bulk pipes */
-               err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
-                                    &sc->sc_bulkin_pipe);
+               err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
+                                    USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
                if (err) {
                        DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
                                 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
@@ -414,35 +465,56 @@
                        goto fail_1;
                }
 
-               /* Allocate a request and an input buffer and start reading. */
-               sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
-               if (sc->sc_ixfer == NULL) {
-                       error = ENOMEM;
-                       goto fail_2;
-               }
+               sc->sc_rx_unblock = 0;
+               sc->sc_rx_stopped = 0;
+               sc->sc_tx_stopped = 0;
+
+               memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff));
+               memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff));
+
+               SIMPLEQ_INIT(&sc->sc_ibuff_empty);
+               SIMPLEQ_INIT(&sc->sc_ibuff_full);
+               SIMPLEQ_INIT(&sc->sc_obuff_free);
+               SIMPLEQ_INIT(&sc->sc_obuff_full);
 
-               sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
-                                               sc->sc_ibufsizepad);
-               if (sc->sc_ibuf == NULL) {
-                       error = ENOMEM;
-                       goto fail_3;
+               /* Allocate input buffers */
+               for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
+                   ub++) {
+                       ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
+                       if (ub->ub_xfer == NULL) {
+                               error = ENOMEM;
+                               goto fail_2;
+                       }
+                       ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
+                           sc->sc_ibufsizepad);
+                       if (ub->ub_data == NULL) {
+                               error = ENOMEM;
+                               goto fail_2;
+                       }
+
+                       if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) {
+                               error = EIO;
+                               goto fail_2;
+                       }
                }
 
-               sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
-               if (sc->sc_oxfer == NULL) {
-                       error = ENOMEM;
-                       goto fail_3;
+               for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
+                   ub++) {
+                       ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
+                       if (ub->ub_xfer == NULL) {
+                               error = ENOMEM;
+                               goto fail_2;
+                       }
+                       ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
+                           sc->sc_obufsize);
+                       if (ub->ub_data == NULL) {
+                               error = ENOMEM;
+                               goto fail_2;
+                       }
+
+                       SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
                }
 
-               sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
-                                               sc->sc_obufsize +
-                                               sc->sc_opkthdrlen);
-               if (sc->sc_obuf == NULL) {
-                       error = ENOMEM;
-                       goto fail_4;
-               }
-
-               ucomstartread(sc);
        }
        sc->sc_opening = 0;
        wakeup(&sc->sc_opening);
@@ -458,13 +530,24 @@
 
        return (0);
 



Home | Main Index | Thread Index | Old Index