Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Updates from t-hash



details:   https://anonhg.NetBSD.org/src/rev/0e7226f9fbb4
branches:  trunk
changeset: 344974:0e7226f9fbb4
user:      skrll <skrll%NetBSD.org@localhost>
date:      Sat Apr 30 14:53:06 2016 +0000

description:
Updates from t-hash
    + Change xhci_init() returns errno.
    + Fix memory leaks in error paths.
    + Add more messages for critical errors.

diffstat:

 sys/dev/usb/xhci.c |  122 +++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 95 insertions(+), 27 deletions(-)

diffs (244 lines):

diff -r 61ca9deeae40 -r 0e7226f9fbb4 sys/dev/usb/xhci.c
--- a/sys/dev/usb/xhci.c        Sat Apr 30 14:51:04 2016 +0000
+++ b/sys/dev/usb/xhci.c        Sat Apr 30 14:53:06 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: xhci.c,v 1.36 2016/04/30 14:51:04 skrll Exp $  */
+/*     $NetBSD: xhci.c,v 1.37 2016/04/30 14:53:06 skrll Exp $  */
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.36 2016/04/30 14:51:04 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.37 2016/04/30 14:53:06 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -788,8 +788,10 @@
                        break;
                usb_delay_ms(&sc->sc_bus, 1);
        }
-       if (i >= 100)
+       if (i >= 100) {
+               aprint_error_dev(sc->sc_dev, "controller not ready timeout\n");
                return EIO;
+       }
 
        usbcmd = 0;
        xhci_op_write_4(sc, XHCI_USBCMD, usbcmd);
@@ -803,8 +805,10 @@
                        break;
                usb_delay_ms(&sc->sc_bus, 1);
        }
-       if (i >= 100)
+       if (i >= 100) {
+               aprint_error_dev(sc->sc_dev, "host controller reset timeout\n");
                return EIO;
+       }
 
        for (i = 0; i < 100; i++) {
                usbsts = xhci_op_read_4(sc, XHCI_USBSTS);
@@ -812,8 +816,11 @@
                        break;
                usb_delay_ms(&sc->sc_bus, 1);
        }
-       if (i >= 100)
+       if (i >= 100) {
+               aprint_error_dev(sc->sc_dev,
+                   "controller not ready timeout after reset\n");
                return EIO;
+       }
 
        if (sc->sc_vendor_init)
                sc->sc_vendor_init(sc);
@@ -821,8 +828,10 @@
        pagesize = xhci_op_read_4(sc, XHCI_PAGESIZE);
        aprint_debug_dev(sc->sc_dev, "PAGESIZE 0x%08x\n", pagesize);
        pagesize = ffs(pagesize);
-       if (pagesize == 0)
+       if (pagesize == 0) {
+               aprint_error_dev(sc->sc_dev, "pagesize is 0\n");
                return EIO;
+       }
        sc->sc_pgsz = 1 << (12 + (pagesize - 1));
        aprint_debug_dev(sc->sc_dev, "sc_pgsz 0x%08x\n", (uint32_t)sc->sc_pgsz);
        aprint_debug_dev(sc->sc_dev, "sc_maxslots 0x%08x\n",
@@ -830,6 +839,7 @@
        aprint_debug_dev(sc->sc_dev, "sc_maxports %d\n", sc->sc_maxports);
 
        usbd_status err;
+       int rv = 0;
 
        sc->sc_maxspbuf = XHCI_HCS2_MAXSPBUF(hcs2);
        aprint_debug_dev(sc->sc_dev, "sc_maxspbuf %d\n", sc->sc_maxspbuf);
@@ -837,8 +847,11 @@
                err = usb_allocmem(&sc->sc_bus,
                    sizeof(uint64_t) * sc->sc_maxspbuf, sizeof(uint64_t),
                    &sc->sc_spbufarray_dma);
-               if (err)
-                       return err;
+               if (err) {
+                       aprint_error_dev(sc->sc_dev,
+                           "spbufarray init fail, err %d\n", err);
+                       return ENOMEM;
+               }
 
                sc->sc_spbuf_dma = kmem_zalloc(sizeof(*sc->sc_spbuf_dma) *
                    sc->sc_maxspbuf, KM_SLEEP);
@@ -848,8 +861,12 @@
                        /* allocate contexts */
                        err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz,
                            sc->sc_pgsz, dma);
-                       if (err)
-                               return err;
+                       if (err) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "spbufarray_dma init fail, err %d\n", err);
+                               rv = ENOMEM;
+                               goto bad1;
+                       }
                        spbufarray[i] = htole64(DMAADDR(dma, 0));
                        usb_syncmem(dma, 0, sc->sc_pgsz,
                            BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
@@ -867,15 +884,19 @@
        err = xhci_ring_init(sc, &sc->sc_cr, XHCI_COMMAND_RING_TRBS,
            XHCI_COMMAND_RING_SEGMENTS_ALIGN);
        if (err) {
-               aprint_error_dev(sc->sc_dev, "command ring init fail\n");
-               return err;
+               aprint_error_dev(sc->sc_dev, "command ring init fail, err %d\n",
+                   err);
+               rv = ENOMEM;
+               goto bad1;
        }
 
        err = xhci_ring_init(sc, &sc->sc_er, XHCI_EVENT_RING_TRBS,
            XHCI_EVENT_RING_SEGMENTS_ALIGN);
        if (err) {
-               aprint_error_dev(sc->sc_dev, "event ring init fail\n");
-               return err;
+               aprint_error_dev(sc->sc_dev, "event ring init fail, err %d\n",
+                   err);
+               rv = ENOMEM;
+               goto bad2;
        }
 
        usb_dma_t *dma;
@@ -885,23 +906,37 @@
        dma = &sc->sc_eventst_dma;
        size = roundup2(XHCI_EVENT_RING_SEGMENTS * XHCI_ERSTE_SIZE,
            XHCI_EVENT_RING_SEGMENT_TABLE_ALIGN);
-       KASSERT(size <= (512 * 1024));
+       KASSERTMSG(size <= (512 * 1024), "eventst size %zu too large", size);
        align = XHCI_EVENT_RING_SEGMENT_TABLE_ALIGN;
        err = usb_allocmem(&sc->sc_bus, size, align, dma);
+       if (err) {
+               aprint_error_dev(sc->sc_dev, "eventst init fail, err %d\n",
+                   err);
+               rv = ENOMEM;
+               goto bad3;
+       }
 
        memset(KERNADDR(dma, 0), 0, size);
        usb_syncmem(dma, 0, size, BUS_DMASYNC_PREWRITE);
-       aprint_debug_dev(sc->sc_dev, "eventst: %s %016jx %p %zx\n",
-           usbd_errstr(err),
+       aprint_debug_dev(sc->sc_dev, "eventst: %016jx %p %zx\n",
            (uintmax_t)DMAADDR(&sc->sc_eventst_dma, 0),
            KERNADDR(&sc->sc_eventst_dma, 0),
            sc->sc_eventst_dma.udma_block->size);
 
        dma = &sc->sc_dcbaa_dma;
        size = (1 + sc->sc_maxslots) * sizeof(uint64_t);
-       KASSERT(size <= 2048);
+       KASSERTMSG(size <= 2048, "dcbaa size %zu too large", size);
        align = XHCI_DEVICE_CONTEXT_BASE_ADDRESS_ARRAY_ALIGN;
        err = usb_allocmem(&sc->sc_bus, size, align, dma);
+       if (err) {
+               aprint_error_dev(sc->sc_dev, "dcbaa init fail, err %d\n", err);
+               rv = ENOMEM;
+               goto bad4;
+       }
+       aprint_debug_dev(sc->sc_dev, "dcbaa: %016jx %p %zx\n",
+           (uintmax_t)DMAADDR(&sc->sc_dcbaa_dma, 0),
+           KERNADDR(&sc->sc_dcbaa_dma, 0),
+           sc->sc_dcbaa_dma.udma_block->size);
 
        memset(KERNADDR(dma, 0), 0, size);
        if (sc->sc_maxspbuf != 0) {
@@ -912,23 +947,29 @@
                    htole64(DMAADDR(&sc->sc_spbufarray_dma, 0));
        }
        usb_syncmem(dma, 0, size, BUS_DMASYNC_PREWRITE);
-       aprint_debug_dev(sc->sc_dev, "dcbaa: %s %016jx %p %zx\n",
-           usbd_errstr(err),
-           (uintmax_t)DMAADDR(&sc->sc_dcbaa_dma, 0),
-           KERNADDR(&sc->sc_dcbaa_dma, 0),
-           sc->sc_dcbaa_dma.udma_block->size);
 
        sc->sc_slots = kmem_zalloc(sizeof(*sc->sc_slots) * sc->sc_maxslots,
            KM_SLEEP);
+       if (sc->sc_slots == NULL) {
+               aprint_error_dev(sc->sc_dev, "slots init fail, err %d\n", err);
+               rv = ENOMEM;
+               goto bad;
+       }
+
+       sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
+           "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
+       if (sc->sc_xferpool == NULL) {
+               aprint_error_dev(sc->sc_dev, "pool_cache init fail, err %d\n",
+                   err);
+               rv = ENOMEM;
+               goto bad;
+       }
 
        cv_init(&sc->sc_command_cv, "xhcicmd");
        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
        mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
        cv_init(&sc->sc_softwake_cv, "xhciab");
 
-       sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
-           "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
-
        /* Set up the bus struct. */
        sc->sc_bus.ub_methods = &xhci_bus_methods;
        sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);
@@ -967,7 +1008,34 @@
        aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
            xhci_op_read_4(sc, XHCI_USBCMD));
 
-       return USBD_NORMAL_COMPLETION;
+       return 0;
+
+ bad:
+       if (sc->sc_xferpool) {
+               pool_cache_destroy(sc->sc_xferpool);
+               sc->sc_xferpool = NULL;
+       }
+
+       if (sc->sc_slots) {
+               kmem_free(sc->sc_slots, sizeof(*sc->sc_slots) *
+                   sc->sc_maxslots);
+               sc->sc_slots = NULL;
+       }
+
+       usb_freemem(&sc->sc_bus, &sc->sc_dcbaa_dma);
+ bad4:
+       usb_freemem(&sc->sc_bus, &sc->sc_eventst_dma);
+ bad3:
+       xhci_ring_free(sc, &sc->sc_er);
+ bad2:
+       xhci_ring_free(sc, &sc->sc_cr);
+       i = sc->sc_maxspbuf;
+ bad1:
+       for (int j = 0; j < i; j++)
+               usb_freemem(&sc->sc_bus, &sc->sc_spbuf_dma[j]);
+       usb_freemem(&sc->sc_bus, &sc->sc_spbufarray_dma);
+
+       return rv;
 }
 
 int



Home | Main Index | Thread Index | Old Index