Reduce the number of intermediate buffers by pre-allocating DMA buffers
authormpi <mpi@openbsd.org>
Thu, 22 Jan 2015 10:27:47 +0000 (10:27 +0000)
committermpi <mpi@openbsd.org>
Thu, 22 Jan 2015 10:27:47 +0000 (10:27 +0000)
in the report functions instead of letting the stack do it magically for
us.

Reviewed and tested by David Higgs, thanks!

sys/dev/usb/uhidev.c
sys/dev/usb/usbdi.c
sys/dev/usb/usbdi.h

index 46ca3e5..27e1e60 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhidev.c,v 1.68 2015/01/09 12:09:51 mpi Exp $ */
+/*     $OpenBSD: uhidev.c,v 1.69 2015/01/22 10:27:47 mpi Exp $ */
 /*     $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $     */
 
 /*
@@ -671,18 +671,30 @@ int
 uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data,
     int len)
 {
+       struct usbd_xfer *xfer;
        usb_device_request_t req;
-       char *buf = data;
        int actlen = len;
+       char *buf;
+
+       xfer = usbd_alloc_xfer(sc->sc_udev);
+       if (xfer == NULL)
+               return (-1);
+
+       if (id > 0)
+               len++;
+
+       buf = usbd_alloc_buffer(xfer, len);
+       if (buf == NULL) {
+               usbd_free_xfer(xfer);
+               return (-1);
+       }
 
        /* Prepend the reportID. */
        if (id > 0) {
-               len++;
-               buf = malloc(len, M_TEMP, M_NOWAIT);
-               if (buf == NULL)
-                       return (-1);
                buf[0] = id;
                memcpy(buf + 1, data, len - 1);
+       } else {
+               memcpy(buf, data, len);
        }
 
        req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
@@ -691,17 +703,9 @@ uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data,
        USETW(req.wIndex, sc->sc_ifaceno);
        USETW(req.wLength, len);
 
-       if (usbd_do_request_async(sc->sc_udev, &req, buf, NULL, NULL))
+       if (usbd_request_async(xfer, &req, NULL, NULL))
                actlen = -1;
 
-       /*
-        * Since report requests are write-only it is safe to free
-        * the buffer right after submitting the transfer because
-        * it won't be used afterward.
-        */
-       if (id > 0)
-               free(buf, M_TEMP, len);
-
        return (actlen);
 }
 
@@ -750,11 +754,11 @@ uhidev_get_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err)
                if (info->id > 0) {
                        len--;
                        memcpy(info->data, xfer->buffer + 1, len);
+               } else {
+                       memcpy(info->data, xfer->buffer, len);
                }
        }
        info->callback(info->priv, info->id, info->data, len);
-       if (info->id > 0)
-               free(xfer->buffer, M_TEMP, xfer->length);
        free(info, M_TEMP, sizeof(*info));
        usbd_free_xfer(xfer);
 }
@@ -763,42 +767,47 @@ int
 uhidev_get_report_async(struct uhidev_softc *sc, int type, int id, void *data,
     int len, void *priv, void (*callback)(void *, int, void *, int))
 {
+       struct usbd_xfer *xfer;
        usb_device_request_t req;
        struct uhidev_async_info *info;
-       char *buf = data;
        int actlen = len;
+       char *buf;
+
+       xfer = usbd_alloc_xfer(sc->sc_udev);
+       if (xfer == NULL)
+               return (-1);
+
+       if (id > 0)
+               len++;
+
+       buf = usbd_alloc_buffer(xfer, len);
+       if (buf == NULL) {
+               usbd_free_xfer(xfer);
+               return (-1);
+       }
 
        info = malloc(sizeof(*info), M_TEMP, M_NOWAIT);
-       if (info == NULL)
+       if (info == NULL) {
+               usbd_free_xfer(xfer);
                return (-1);
+       }
 
        info->callback = callback;
        info->priv = priv;
        info->data = data;
        info->id = id;
 
-       if (id > 0) {
-               len++;
-               buf = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
-               if (buf == NULL) {
-                       free(info, M_TEMP, sizeof(*info));
-                       return (-1);
-               }
-       }
-
        req.bmRequestType = UT_READ_CLASS_INTERFACE;
        req.bRequest = UR_GET_REPORT;
        USETW2(req.wValue, type, id);
        USETW(req.wIndex, sc->sc_ifaceno);
        USETW(req.wLength, len);
 
-       if (usbd_do_request_async(sc->sc_udev, &req, buf, priv,
-           uhidev_get_report_async_cb)) {
+       if (usbd_request_async(xfer, &req, priv, uhidev_get_report_async_cb)) {
                free(info, M_TEMP, sizeof(*info));
-               if (id > 0)
-                       free(buf, M_TEMP, len);
                actlen = -1;
        }
+
        return (actlen);
 }
 
index 7db61f2..e203b7e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: usbdi.c,v 1.78 2015/01/11 15:41:16 mpi Exp $ */
+/*     $OpenBSD: usbdi.c,v 1.79 2015/01/22 10:27:47 mpi Exp $ */
 /*     $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $       */
 /*     $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $      */
 
@@ -55,8 +55,7 @@ extern int usbdebug;
 #define DPRINTFN(n,x)
 #endif
 
-void usbd_do_request_async_cb(struct usbd_xfer *, void *,
-    usbd_status);
+void usbd_request_async_cb(struct usbd_xfer *, void *, usbd_status);
 void usbd_start_next(struct usbd_pipe *pipe);
 usbd_status usbd_open_pipe_ival(struct usbd_interface *, u_int8_t, u_int8_t,
     struct usbd_pipe **, int);
@@ -586,6 +585,7 @@ usbd_status
 usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe)
 {
        struct usbd_device *dev = pipe->device;
+       struct usbd_xfer *xfer;
        usb_device_request_t req;
        usbd_status err;
 
@@ -596,7 +596,12 @@ usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe)
        USETW(req.wValue, UF_ENDPOINT_HALT);
        USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
        USETW(req.wLength, 0);
-       err = usbd_do_request_async(dev, &req, 0, 0, 0);
+
+       xfer = usbd_alloc_xfer(dev);
+       if (xfer == NULL)
+               return (USBD_NOMEM);
+
+       err = usbd_request_async(xfer, &req, NULL, NULL);
        return (err);
 }
 
@@ -949,8 +954,7 @@ usbd_do_request_flags(struct usbd_device *dev, usb_device_request_t *req,
 }
 
 void
-usbd_do_request_async_cb(struct usbd_xfer *xfer, void *priv,
-    usbd_status status)
+usbd_request_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
        usbd_free_xfer(xfer);
 }
@@ -960,19 +964,17 @@ usbd_do_request_async_cb(struct usbd_xfer *xfer, void *priv,
  * Can be used from interrupt context.
  */
 usbd_status
-usbd_do_request_async(struct usbd_device *dev, usb_device_request_t *req,
-    void *data, void *priv, usbd_callback callback)
+usbd_request_async(struct usbd_xfer *xfer, usb_device_request_t *req,
+    void *priv, usbd_callback callback)
 {
-       struct usbd_xfer *xfer;
        usbd_status err;
 
-       xfer = usbd_alloc_xfer(dev);
-       if (xfer == NULL)
-               return (USBD_NOMEM);
        if (callback == NULL)
-               callback = usbd_do_request_async_cb;
-       usbd_setup_default_xfer(xfer, dev, priv, USBD_DEFAULT_TIMEOUT, req,
-           data, UGETW(req->wLength), 0, callback);
+               callback = usbd_request_async_cb;
+
+       usbd_setup_default_xfer(xfer, xfer->device, priv,
+           USBD_DEFAULT_TIMEOUT, req, NULL, UGETW(req->wLength),
+           USBD_NO_COPY, callback);
        err = usbd_transfer(xfer);
        if (err != USBD_IN_PROGRESS) {
                usbd_free_xfer(xfer);
index b91697b..336191d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: usbdi.h,v 1.64 2015/01/09 12:07:50 mpi Exp $ */
+/*     $OpenBSD: usbdi.h,v 1.65 2015/01/22 10:27:47 mpi Exp $ */
 /*     $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $      */
 /*     $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $      */
 
@@ -121,8 +121,8 @@ usbd_status usbd_open_pipe_intr(struct usbd_interface *iface, u_int8_t address,
     void *buffer, u_int32_t length, usbd_callback, int);
 usbd_status usbd_do_request(struct usbd_device *pipe, usb_device_request_t *req,
     void *data);
-usbd_status usbd_do_request_async(struct usbd_device *pipe,
-    usb_device_request_t *req, void *data, void *priv, usbd_callback callback);
+usbd_status usbd_request_async(struct usbd_xfer *xfer,
+    usb_device_request_t *req, void *priv, usbd_callback callback);
 usbd_status usbd_do_request_flags(struct usbd_device *pipe,
     usb_device_request_t *req, void *data, u_int16_t flags, int*, u_int32_t);
 usb_interface_descriptor_t *usbd_get_interface_descriptor(