Hello,

These are usb 3.0 patches for nick-nhusb branch.
Mostly same as patches I posted previously for current.


nh-xhci-cosmetic.diff
        whitespace

nh-xhci-fixtypo.diff
        fix typo in comment

nh-xhci-main.diff
        main patch
        (mostly same as I posted previously for -current)

nh-xhci-comments.diff
        sprinkle comments

nh-xhci-compat.diff
        share sources with other branches

nh-uhub-usbhistify.diff
        convert to use usbhist

nh-uhub-usb3.diff
        add support for usb3 hub

nh-misc.diff
+ usb.h
        fix SS and LS speed definition was swapped
        rename usb_usb2ext_descriptor_t to usb_devcap_usb2ext_descriptor_t
        add SS current definition
        add comments

+ usb_subr.c
        add UPS_PORT_POWER_SS treatment

+ xhcireg.h
        add definitions of port routing and capability ids

+ xhcivar.h
        add sc_quirks and definitions for it


--
t-hash
--- src/sys/dev/usb/xhci.c.orig 2015-03-27 15:05:03.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-04-04 16:43:18.000000000 +0900
@@ -62,7 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #ifdef USB_DEBUG
 #ifndef XHCI_DEBUG
 #define xhcidebug 0
-#else
+#else /* !XHCI_DEBUG */
 static int xhcidebug = 0;
 
 SYSCTL_SETUP(sysctl_hw_xhci_setup, "sysctl hw.xhci setup")
@@ -92,7 +92,7 @@ fail:
        aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
 }
 
-#endif /* XHCI_DEBUG */
+#endif /* !XHCI_DEBUG */
 #endif /* USB_DEBUG */
 
 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)
@@ -1109,7 +1109,7 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
 static usbd_status
 xhci_open(struct usbd_pipe *pipe)
 {
-       struct usbd_device *const dev = pipe->up_dev;
+       struct usbd_device * const dev = pipe->up_dev;
        struct xhci_softc * const sc = dev->ud_bus->ub_hcpriv;
        usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
        const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
@@ -1168,7 +1168,7 @@ xhci_open(struct usbd_pipe *pipe)
 static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {
-       struct usbd_xfer *const xfer = sc->sc_intrxfer;
+       struct usbd_xfer * const xfer = sc->sc_intrxfer;
        uint8_t *p;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -1303,7 +1303,7 @@ xhci_handle_event(struct xhci_softc * co
 static void
 xhci_softintr(void *v)
 {
-       struct usbd_bus *const bus = v;
+       struct usbd_bus * const bus = v;
        struct xhci_softc * const sc = bus->ub_hcpriv;
        struct xhci_ring * const er = &sc->sc_er;
        struct xhci_trb *trb;
@@ -1983,7 +1983,8 @@ xhci_noop(struct usbd_pipe *pipe)
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }
 
-static int xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+static int
+xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
     void *buf, int buflen)
 {
        struct xhci_softc * const sc = bus->ub_hcpriv;
@@ -2666,7 +2667,7 @@ static void
 xhci_timeout(void *addr)
 {
        struct xhci_xfer * const xx = addr;
-       struct usbd_xfer *const xfer = &xx->xx_xfer;
+       struct usbd_xfer * const xfer = &xx->xx_xfer;
        struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -2684,7 +2685,7 @@ xhci_timeout(void *addr)
 static void
 xhci_timeout_task(void *addr)
 {
-       struct usbd_xfer *const xfer = addr;
+       struct usbd_xfer * const xfer = addr;
        struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
--- src/sys/dev/usb/xhci.c.orig 2015-04-04 16:43:18.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-04-04 16:47:39.000000000 +0900
@@ -2189,7 +2189,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
        return totlen;
 }
 
-/* root hub intrerrupt */
+/* root hub interrupt */
 
 static usbd_status
 xhci_root_intr_transfer(struct usbd_xfer *xfer)
--- src/sys/dev/usb/xhci.c.orig 2015-04-04 17:01:37.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-04-05 05:53:30.000000000 +0900
@@ -50,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdivar.h>
+#include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbhist.h>
 #include <dev/usb/usb_mem.h>
 #include <dev/usb/usb_quirks.h>
@@ -126,18 +127,22 @@ static int xhci_roothub_ctrl(struct usbd
     void *, int);
 
 static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
-static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
+//static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
 static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
-//static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
+static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
 
 static usbd_status xhci_set_dequeue(struct usbd_pipe *);
 
 static usbd_status xhci_do_command(struct xhci_softc * const,
     struct xhci_trb * const, int);
-static usbd_status xhci_init_slot(struct xhci_softc * const, uint32_t,
-    int, int, int, int);
+static usbd_status xhci_do_command1(struct xhci_softc * const,
+    struct xhci_trb * const, int, int);
+static usbd_status xhci_do_command_locked(struct xhci_softc * const,
+    struct xhci_trb * const, int);
+static usbd_status xhci_init_slot(struct usbd_device *, uint32_t, int, int);
 static usbd_status xhci_enable_slot(struct xhci_softc * const,
     uint8_t * const);
+static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t);
 static usbd_status xhci_address_device(struct xhci_softc * const,
     uint64_t, uint8_t, bool);
 static usbd_status xhci_update_ep0_mps(struct xhci_softc * const,
@@ -228,11 +233,24 @@ static const struct usbd_pipe_methods xh
 };
 
 static inline uint32_t
+xhci_read_1(const struct xhci_softc * const sc, bus_size_t offset)
+{
+       return bus_space_read_1(sc->sc_iot, sc->sc_ioh, offset);
+}
+
+static inline uint32_t
 xhci_read_4(const struct xhci_softc * const sc, bus_size_t offset)
 {
        return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
 }
 
+static inline void
+xhci_write_1(const struct xhci_softc * const sc, bus_size_t offset,
+    uint32_t value)
+{
+       bus_space_write_1(sc->sc_iot, sc->sc_ioh, offset, value);
+}
+
 #if 0 /* unused */
 static inline void
 xhci_write_4(const struct xhci_softc * const sc, bus_size_t offset,
@@ -374,7 +392,7 @@ xhci_db_write_4(const struct xhci_softc 
 static inline uint8_t
 xhci_ep_get_type(usb_endpoint_descriptor_t * const ed)
 {
-       u_int eptype;
+       u_int eptype = 0;
 
        switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
        case UE_CONTROL:
@@ -517,6 +535,7 @@ xhci_detach(struct xhci_softc *sc, int f
 
        mutex_destroy(&sc->sc_lock);
        mutex_destroy(&sc->sc_intr_lock);
+       cv_destroy(&sc->sc_softwake_cv);
 
        pool_cache_destroy(sc->sc_xferpool);
 
@@ -658,6 +677,28 @@ xhci_init(struct xhci_softc *sc)
                        }
                        break;
                }
+               case XHCI_ID_USB_LEGACY: {
+                       uint8_t bios_sem;
+
+                       /* Take host controller from BIOS */
+                       bios_sem = xhci_read_1(sc, ecp + XHCI_XECP_BIOS_SEM);
+                       if (bios_sem) {
+                               /* sets xHCI to be owned by OS */
+                               xhci_write_1(sc, ecp + XHCI_XECP_OS_SEM, 1);
+                               aprint_debug(
+                                   "waiting for BIOS to give up control\n");
+                               for (i = 0; i < 5000; i++) {
+                                       bios_sem = xhci_read_1(sc, ecp +
+                                           XHCI_XECP_BIOS_SEM);
+                                       if (bios_sem == 0)
+                                               break;
+                                       DELAY(1000);
+                               }
+                               if (bios_sem)
+                                       printf("timed out waiting for BIOS\n");
+                       }
+                       break;
+               }
                default:
                        break;
                }
@@ -732,6 +773,7 @@ xhci_init(struct xhci_softc *sc)
        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",
            (uint32_t)sc->sc_maxslots);
+       aprint_debug_dev(sc->sc_dev, "sc_maxports %d\n", sc->sc_maxports);
 
        usbd_status err;
 
@@ -825,6 +867,16 @@ xhci_init(struct xhci_softc *sc)
            KM_SLEEP);
 
        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_SCHED);
+       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);
 
        struct xhci_erste *erst;
        erst = KERNADDR(&sc->sc_eventst_dma, 0);
@@ -848,23 +900,18 @@ xhci_init(struct xhci_softc *sc)
 #endif
 
        xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);
-       xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
+#ifdef XHCI_QUIRK_INTEL
+       if ((sc->sc_quirks & XHCI_QUIRK_INTEL) != 0)
+               /* Intel xhci needs interrupt rate moderated. */
+               xhci_rt_write_4(sc, XHCI_IMOD(0), XHCI_IMOD_DEFAULT_LP);
+       else
+#endif /* XHCI_QUIRK_INTEL */
+               xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
 
        xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
        aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
            xhci_op_read_4(sc, XHCI_USBCMD));
 
-       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
-       mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
-       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);
-
        return USBD_NORMAL_COMPLETION;
 }
 
@@ -920,9 +967,19 @@ xhci_intr1(struct xhci_softc * const sc)
 
        iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
        DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);
+#ifdef XHCI_QUIRK_FORCE_INTR
+
+       if (!(sc->sc_quirks & XHCI_QUIRK_FORCE_INTR)) {
+               if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
+                       return 0;
+               }
+       }
+
+#else
        if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
                return 0;
        }
+#endif /* XHCI_QUIRK_FORCE_INTR */
        xhci_rt_write_4(sc, XHCI_IMAN(0), iman);
        iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
        DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);
@@ -934,6 +991,138 @@ xhci_intr1(struct xhci_softc * const sc)
        return 1;
 }
 
+/*
+ * 3 port speed types used in USB stack
+ *
+ * usbdi speed
+ *     definition: USB_SPEED_* in usb.h
+ *     They are used in struct usbd_device in USB stack.
+ *     ioctl interface uses these values too.
+ * port_status speed
+ *     definition: UPS_*_SPEED in usb.h
+ *     They are used in usb_port_status_t.
+ *     Some 3.0 values overlap with 2.0 values.
+ *     (e.g. 0x200 means UPS_POER_POWER_SS in SS and
+ *                 means UPS_LOW_SPEED in HS.)
+ *     port status sent from hub also uses these values.
+ *     (but I've never seen UPS_SUPER_SPEED in port_status from hub.)
+ * xspeed:
+ *     definition: Protocol Speed ID (PSI) (xHCI 1.1 7.2.1)
+ *     They are used in only slot context and PORTSC reg of xhci.
+ *     The difference between usbdi speed and them are that
+ *     FS and LS values are swapped.
+ */
+
+static int
+xhci_speed2xspeed(int speed)
+{
+       switch (speed) {
+       case USB_SPEED_LOW:     return 2;
+       case USB_SPEED_FULL:    return 1;
+       case USB_SPEED_HIGH:    return 3;
+       case USB_SPEED_SUPER:   return 4;
+       default:
+               break;
+       }
+       return 0;
+}
+
+/* construct slot context */
+static void
+xhci_setup_sctx(struct usbd_device *dev, uint32_t *cp)
+{
+       usb_device_descriptor_t * const dd = &dev->ud_ddesc;
+       int speed = dev->ud_speed;
+       int tthubslot, ttportnum;
+       bool ishub;
+       bool usemtt;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       /* 6.2.2 */
+       /*
+        * tthubslot:
+        *   This is the slot ID of parent HS hub
+        *   if LS/FS device is connected && connected through HS hub.
+        *   This is 0 if device is not LS/FS device ||
+        *   parent hub is not HS hub ||
+        *   attached to root hub.
+        * ttportnum:
+        *   This is the downstream facing port of parent HS hub
+        *   if LS/FS device is connected.
+        *   This is 0 if device is not LS/FS device ||
+        *   parent hub is not HS hub ||
+        *   attached to root hub.
+        */
+       if (dev->ud_myhsport != NULL &&
+           dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+           (dev->ud_myhub != NULL &&
+            dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+           (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
+               ttportnum = dev->ud_myhsport->up_portno;
+               /* XXX addr == slot ? */
+               tthubslot = dev->ud_myhsport->up_parent->ud_addr;
+       } else {
+               ttportnum = 0;
+               tthubslot = 0;
+       }
+       DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
+           dev->ud_myhsport, ttportnum, tthubslot, 0);
+
+       /* ishub is valid after reading UDESC_DEVICE */
+       ishub = (dd->bDeviceClass == UDCLASS_HUB);
+
+       /* dev->ud_hub is valid after reading UDESC_HUB */
+       if (ishub && dev->ud_hub) {
+               usb_hub_descriptor_t *hd = &dev->ud_hub->uh_hubdesc;
+
+               cp[1] |= htole32(XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts));
+               cp[2] |= htole32(XHCI_SCTX_2_TT_THINK_TIME_SET(
+                   __SHIFTOUT(UGETW(hd->wHubCharacteristics), UHD_TT_THINK)));
+               DPRINTFN(4, "nports=%d ttt=%d",
+                   hd->bNbrPorts, XHCI_SCTX_2_TT_THINK_TIME_GET(cp[2]), 0, 0);
+       }
+
+#define IS_TTHUB(dd) \
+    ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \
+     (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT)
+
+       /*
+        * MTT flag is set if
+        * 1. this is HS hub && MTT is enabled
+        *  or
+        * 2. this is not hub && this is LS or FS device &&
+        *    MTT of parent HS hub (and its parent, too) is enabled
+        */
+       if (ishub && speed == USB_SPEED_HIGH && IS_TTHUB(dd))
+               usemtt = true;
+       else if (!ishub &&
+            (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) &&
+            dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+            (dev->ud_myhub != NULL &&
+             dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+            dev->ud_myhsport != NULL &&
+            IS_TTHUB(&dev->ud_myhsport->up_parent->ud_ddesc))
+               usemtt = true;
+       else
+               usemtt = false;
+       DPRINTFN(4, "class %u proto %u ishub %d usemtt %d",
+           dd->bDeviceClass, dd->bDeviceProtocol, ishub, usemtt);
+
+       cp[0] |= htole32(
+           XHCI_SCTX_0_SPEED_SET(xhci_speed2xspeed(speed)) |
+           XHCI_SCTX_0_HUB_SET(ishub ? 1 : 0) |
+           XHCI_SCTX_0_MTT_SET(usemtt ? 1 : 0)
+           );
+       cp[1] |= htole32(0);
+       cp[2] |= htole32(
+           XHCI_SCTX_2_IRQ_TARGET_SET(0) |
+           XHCI_SCTX_2_TT_HUB_SID_SET(tthubslot) |
+           XHCI_SCTX_2_TT_PORT_NUM_SET(ttportnum)
+           );
+       cp[3] |= htole32(0);
+}
+
 static usbd_status
 xhci_configure_endpoint(struct usbd_pipe *pipe)
 {
@@ -945,10 +1134,14 @@ xhci_configure_endpoint(struct usbd_pipe
        struct xhci_trb trb;
        usbd_status err;
        uint32_t *cp;
+       uint32_t mps = UGETW(ed->wMaxPacketSize);
+       uint32_t maxb = 0;
+       int speed = pipe->up_dev->ud_speed;
+       uint32_t ival = ed->bInterval;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
-       DPRINTFN(4, "dci %u epaddr 0x%02x attr 0x%02x",
-           dci, ed->bEndpointAddress, ed->bmAttributes, 0);
+       DPRINTFN(4, "slot %u dci %u epaddr 0x%02x attr 0x%02x",
+           xs->xs_idx, dci, ed->bEndpointAddress, ed->bmAttributes);
 
        /* XXX ensure input context is available? */
 
@@ -960,34 +1153,121 @@ xhci_configure_endpoint(struct usbd_pipe
 
        /* set up input slot context */
        cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
-       cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
-       cp[1] = htole32(0);
-       cp[2] = htole32(0);
-       cp[3] = htole32(0);
+       xhci_setup_sctx(pipe->up_dev, cp);
+       cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
 
-       uint8_t eptype = xhci_ep_get_type(pipe->up_endpoint->ue_edesc);
        cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
-       if (xfertype == UE_INTERRUPT) {
-               cp[0] = htole32(
-                   XHCI_EPCTX_0_IVAL_SET(3) /* XXX */
-                   );
-               cp[1] = htole32(
-                   XHCI_EPCTX_1_CERR_SET(3) |
-                   XHCI_EPCTX_1_EPTYPE_SET(eptype) |
-                   XHCI_EPCTX_1_MAXB_SET(0) |
-                   XHCI_EPCTX_1_MAXP_SIZE_SET(8) /* XXX */
-                   );
+       cp[0] = htole32(
+           XHCI_EPCTX_0_EPSTATE_SET(0) |
+           XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
+           XHCI_EPCTX_0_LSA_SET(0)
+           );
+       cp[1] = htole32(
+           XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(ed)) |
+           XHCI_EPCTX_1_MAXB_SET(0)
+           );
+       if (xfertype != UE_ISOCHRONOUS)
+               cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
+
+       if (speed == USB_SPEED_SUPER) {
+               usbd_desc_iter_t iter;
+               const usb_cdc_descriptor_t *cdcd;
+               const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
+               uint8_t ep;
+
+               cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(
+                   pipe->up_dev, UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
+               usb_desc_iter_init(pipe->up_dev, &iter);
+               iter.cur = (const void *)cdcd;
+
+               /* find endpoint_ss_comp desc for ep of this pipe */
+               for(ep = 0;;) {
+                       cdcd = (const usb_cdc_descriptor_t *)
+                           usb_desc_iter_next(&iter);
+                       if (cdcd == NULL)
+                               break;
+                       if (ep == 0 &&
+                           cdcd->bDescriptorType == UDESC_ENDPOINT) {
+                               ep = ((const usb_endpoint_descriptor_t *)cdcd)->
+                                   bEndpointAddress;
+                               if (UE_GET_ADDR(ep) ==
+                                   UE_GET_ADDR(ed->bEndpointAddress)) {
+                                       cdcd = (const usb_cdc_descriptor_t *)
+                                           usb_desc_iter_next(&iter);
+                                       break;
+                               }
+                               ep = 0;
+                       }
+               }
+               if (cdcd != NULL &&
+                   cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
+                       esscd = (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
+                       maxb = esscd->bMaxBurst;
+                       cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+                       DPRINTFN(4, "setting SS MaxBurst %u", maxb, 0, 0, 0);
+               }
+       }
+       if (speed == USB_SPEED_HIGH &&
+           (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
+               maxb = UE_GET_TRANS(UGETW(ed->wMaxPacketSize));
+               cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+               DPRINTFN(4, "setting HS MaxBurst %u", maxb, 0, 0, 0);
+       }
+
+       switch (xfertype) {
+       case UE_INTERRUPT:
+               /* 6.2.3.6  */
+               if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
+                       ival = ival > 10 ? 10 : ival;
+                       ival = ival < 3 ? 3 : ival;
+               } else {
+                       ival = ival > 15 ? 15 : ival;
+               }
+               if (speed == USB_SPEED_SUPER) {
+                       if (maxb > 0)
+                               mps = 1024;
+               } else {
+                       mps = mps ? mps : 8;
+               }
+               cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
+               cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
                cp[4] = htole32(
-                   XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)
-                   );
-       } else {
-               cp[0] = htole32(0);
-               cp[1] = htole32(
-                   XHCI_EPCTX_1_CERR_SET(3) |
-                   XHCI_EPCTX_1_EPTYPE_SET(eptype) |
-                   XHCI_EPCTX_1_MAXB_SET(0) |
-                   XHCI_EPCTX_1_MAXP_SIZE_SET(512) /* XXX */
+                   XHCI_EPCTX_4_AVG_TRB_LEN_SET(8) /* XXX */
                    );
+               break;
+       case UE_CONTROL:
+               if (speed == USB_SPEED_SUPER)
+                       mps = 512;
+               else
+                       mps = mps ? mps : 8;
+               cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+               cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)); /* XXX */
+               break;
+#ifdef notyet
+       case UE_ISOCHRONOUS:
+               if (speed == USB_SPEED_FULL) {
+                       ival = ival > 18 ? 18 : ival;
+                       ival = ival < 3 ? 3 : ival;
+               } else {
+                       ival = ival > 15 ? 15 : ival;
+               }
+               if (speed == USB_SPEED_SUPER) {
+                       mps = 1024;
+               } else {
+                       mps = mps ? mps : 1024;
+               }
+               cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+               cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
+               break;
+#endif
+       default:
+               if (speed == USB_SPEED_SUPER)
+                       mps = 1024;
+               else
+                       mps = mps ? mps : 512;
+               cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+               cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
+               break;
        }
        *(uint64_t *)(&cp[2]) = htole64(
            xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
@@ -1014,6 +1294,7 @@ xhci_configure_endpoint(struct usbd_pipe
        return err;
 }
 
+#if 0
 static usbd_status
 xhci_unconfigure_endpoint(struct usbd_pipe *pipe)
 {
@@ -1026,6 +1307,7 @@ xhci_unconfigure_endpoint(struct usbd_pi
 
        return USBD_NORMAL_COMPLETION;
 }
+#endif
 
 static usbd_status
 xhci_reset_endpoint(struct usbd_pipe *pipe)
@@ -1037,7 +1319,9 @@ xhci_reset_endpoint(struct usbd_pipe *pi
        usbd_status err;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
-       DPRINTFN(4, "dci %u", dci, 0, 0, 0);
+       DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+
+       KASSERT(!mutex_owned(&sc->sc_lock));
 
        trb.trb_0 = 0;
        trb.trb_2 = 0;
@@ -1050,7 +1334,6 @@ xhci_reset_endpoint(struct usbd_pipe *pi
        return err;
 }
 
-#if 0
 static usbd_status
 xhci_stop_endpoint(struct usbd_pipe *pipe)
 {
@@ -1061,7 +1344,9 @@ xhci_stop_endpoint(struct usbd_pipe *pip
        const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
-       DPRINTFN(4, "dci %u", dci, 0, 0, 0);
+       DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+
+       KASSERT(mutex_owned(&sc->sc_lock));
 
        trb.trb_0 = 0;
        trb.trb_2 = 0;
@@ -1069,11 +1354,10 @@ xhci_stop_endpoint(struct usbd_pipe *pip
            XHCI_TRB_3_EP_SET(dci) |
            XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP);
 
-       err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+       err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
 
        return err;
 }
-#endif
 
 static usbd_status
 xhci_set_dequeue(struct usbd_pipe *pipe)
@@ -1116,14 +1400,14 @@ xhci_open(struct usbd_pipe *pipe)
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
        DPRINTFN(1, "addr %d depth %d port %d speed %d",
-           dev->ud_addr, dev->ud_depth, dev->ud_powersrc->up_portno, 
dev->ud_speed);
+           dev->ud_addr, dev->ud_depth, dev->ud_powersrc->up_portno,
+           dev->ud_speed);
 
        if (sc->sc_dying)
                return USBD_IOERROR;
 
        /* Root Hub */
-       if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0 &&
-           dev->ud_speed != USB_SPEED_SUPER) {
+       if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0) {
                switch (ed->bEndpointAddress) {
                case USB_CONTROL_ENDPOINT:
                        pipe->up_methods = &roothub_ctrl_methods;
@@ -1160,11 +1444,146 @@ xhci_open(struct usbd_pipe *pipe)
        }
 
        if (ed->bEndpointAddress != USB_CONTROL_ENDPOINT)
-               xhci_configure_endpoint(pipe);
+               return xhci_configure_endpoint(pipe);
+
+       return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+xhci_close_pipe(struct usbd_pipe *pipe)
+{
+       struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
+       struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
+       usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+       const u_int dci = xhci_ep_get_dci(ed);
+       struct xhci_trb trb;
+       usbd_status err;
+       uint32_t *cp;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       if (sc->sc_dying)
+               return USBD_IOERROR;
+
+       if (xs == NULL || xs->xs_idx == 0)
+               /* xs is uninitialized before xhci_init_slot */
+               return USBD_IOERROR;
+
+       DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+
+       KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
+       KASSERT(mutex_owned(&sc->sc_lock));
+
+       if (pipe->up_dev->ud_depth == 0)
+               return USBD_NORMAL_COMPLETION;
+
+       if (dci == XHCI_DCI_EP_CONTROL) {
+               DPRINTFN(4, "closing ep0", 0, 0, 0, 0);
+               return xhci_disable_slot(sc, xs->xs_idx);
+       }
+
+       (void)xhci_stop_endpoint(pipe);
+
+       /*
+        * set appropriate bit to be dropped.
+        * don't set DC bit to 1, otherwise all endpoints
+        * would be deconfigured.
+        */
+       cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
+       cp[0] = htole32(XHCI_INCTX_0_DROP_MASK(dci));
+       cp[1] = htole32(0);
+
+       /* XXX should be most significant one, not dci? */
+       cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
+       cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+
+       /* sync input contexts before they are read from memory */
+       usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
+
+       trb.trb_0 = xhci_slot_get_icp(sc, xs, 0);
+       trb.trb_2 = 0;
+       trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
+           XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
+
+       err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+       usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
+
+       return err;
+}
+
+static void
+xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
+{
+       struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+       DPRINTFN(4, "xfer %p pipe %p status %d",
+           xfer, xfer->ux_pipe, status, 0);
+
+       KASSERT(mutex_owned(&sc->sc_lock));
+
+       if (sc->sc_dying) {
+               /* If we're dying, just do the software part. */
+               DPRINTFN(4, "dying", 0, 0, 0, 0);
+               xfer->ux_status = status;  /* make software ignore it */
+               callout_stop(&xfer->ux_callout);
+               usb_transfer_complete(xfer);
+               return;
+       }
+
+       /* XXX need more stuff */
+       xfer->ux_status = status;
+       callout_stop(&xfer->ux_callout);
+       usb_transfer_complete(xfer);
+
+       KASSERT(mutex_owned(&sc->sc_lock));
+}
+
+#if 1 /* XXX experimental */
+static void
+xhci_clear_endpoint_stall_async_task(void *cookie)
+{
+       struct usbd_xfer * const xfer = cookie;
+       struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+       struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
+       const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
+       struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+       DPRINTFN(4, "xfer %p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
+
+       xhci_reset_endpoint(xfer->ux_pipe);
+       xhci_set_dequeue(xfer->ux_pipe);
+
+       mutex_enter(&sc->sc_lock);
+       tr->is_halted = false;
+       usb_transfer_complete(xfer);
+       mutex_exit(&sc->sc_lock);
+       DPRINTFN(4, "ends", 0, 0, 0, 0);
+}
+
+static usbd_status
+xhci_clear_endpoint_stall_async(struct usbd_xfer *xfer)
+{
+       struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+       DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
+
+       if (sc->sc_dying) {
+               return USBD_IOERROR;
+       }
+
+       usb_init_task(&xfer->ux_pipe->up_async_task,
+           xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
+       usb_add_task(xfer->ux_pipe->up_dev, &xfer->ux_pipe->up_async_task,
+           USB_TASKQ_HC);
+       DPRINTFN(4, "ends", 0, 0, 0, 0);
 
        return USBD_NORMAL_COMPLETION;
 }
 
+#endif /* XXX experimental */
 static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {
@@ -1177,14 +1596,6 @@ xhci_rhpsc(struct xhci_softc * const sc,
        if (xfer == NULL)
                return;
 
-       if (!(port >= sc->sc_hs_port_start &&
-           port < sc->sc_hs_port_start + sc->sc_hs_port_count))
-               return;
-
-       port -= sc->sc_hs_port_start;
-       port += 1;
-       DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);
-
        p = xfer->ux_buf;
        memset(p, 0, xfer->ux_length);
        p[port/NBBY] |= 1 << (port%NBBY);
@@ -1199,17 +1610,19 @@ xhci_handle_event(struct xhci_softc * co
 {
        uint64_t trb_0;
        uint32_t trb_2, trb_3;
+       uint8_t trberr;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
        trb_0 = le64toh(trb->trb_0);
        trb_2 = le32toh(trb->trb_2);
        trb_3 = le32toh(trb->trb_3);
+       trberr = XHCI_TRB_2_ERROR_GET(trb_2);
 
        DPRINTFN(14, "event: %p 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
            trb, trb_0, trb_2, trb_3);
 
-       switch (XHCI_TRB_3_TYPE_GET(trb_3)){
+       switch (XHCI_TRB_3_TYPE_GET(trb_3)) {
        case XHCI_TRB_EVENT_TRANSFER: {
                u_int slot, dci;
                struct xhci_slot *xs;
@@ -1223,10 +1636,24 @@ xhci_handle_event(struct xhci_softc * co
 
                xs = &sc->sc_slots[slot];
                xr = &xs->xs_ep[dci].xe_tr;
+               /* sanity check */
+               KASSERT(xs->xs_idx != 0);
 
                if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
-                       xx = xr->xr_cookies[(trb_0 - xhci_ring_trbp(xr, 0))/
-                           sizeof(struct xhci_trb)];
+                       bus_addr_t trbp = xhci_ring_trbp(xr, 0);
+
+                       /* trb_0 range sanity check */
+                       if (trb_0 < trbp ||
+                           (trb_0 - trbp) % sizeof(struct xhci_trb) != 0 ||
+                           (trb_0 - trbp) / sizeof(struct xhci_trb) >=
+                            xr->xr_ntrb) {
+                               DPRINTFN(1,
+                                   "invalid trb_0 0x%"PRIx64" trbp 0x%"PRIx64,
+                                   trb_0, trbp, 0, 0);
+                               break;
+                       }
+                       int idx = (trb_0 - trbp) / sizeof(struct xhci_trb);
+                       xx = xr->xr_cookies[idx];
                } else {
                        xx = (void *)(uintptr_t)(trb_0 & ~0x3);
                }
@@ -1243,21 +1670,38 @@ xhci_handle_event(struct xhci_softc * co
                        }
                }
 
-               if (XHCI_TRB_2_ERROR_GET(trb_2) ==
-                   XHCI_TRB_ERROR_SUCCESS) {
-                       xfer->ux_actlen = xfer->ux_length - 
XHCI_TRB_2_REM_GET(trb_2);
-                       err = USBD_NORMAL_COMPLETION;
-               } else if (XHCI_TRB_2_ERROR_GET(trb_2) ==
-                   XHCI_TRB_ERROR_SHORT_PKT) {
-                       xfer->ux_actlen = xfer->ux_length - 
XHCI_TRB_2_REM_GET(trb_2);
+               if (trberr == XHCI_TRB_ERROR_SUCCESS ||
+                   trberr == XHCI_TRB_ERROR_SHORT_PKT) {
+                       xfer->ux_actlen =
+                           xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
                        err = USBD_NORMAL_COMPLETION;
-               } else if (XHCI_TRB_2_ERROR_GET(trb_2) ==
-                   XHCI_TRB_ERROR_STALL) {
+               } else if (trberr == XHCI_TRB_ERROR_STALL ||
+                          trberr == XHCI_TRB_ERROR_BABBLE) {
                        err = USBD_STALLED;
                        xr->is_halted = true;
-                       DPRINTFN(1, "ev: xfer done: err %u slot %u dci %u",
-                           XHCI_TRB_2_ERROR_GET(trb_2), slot, dci, 0);
+                       DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
+                           trberr, slot, dci, 0);
+#if 1 /* XXX experimental */
+                       /*
+                        * Stalled endpoints can be recoverd by issuing
+                        * command TRB TYPE_RESET_EP on xHCI instead of
+                        * issuing request CLEAR_PORT_FEATURE UF_ENDPOINT_HALT
+                        * on the endpoint. However, this function may be
+                        * called from softint context (e.g. from umass),
+                        * in that case driver gets KASSERT in cv_timedwait
+                        * in xhci_do_command.
+                        * To avoid this, this runs reset_endpoint and
+                        * usb_transfer_complete in usb task thread
+                        * asynchronously (and then umass issues clear
+                        * UF_ENDPOINT_HALT).
+                        */
+                       xfer->ux_status = err;
+                       xhci_clear_endpoint_stall_async(xfer);
+                       break;
+#endif
                } else {
+                       DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
+                           trberr, slot, dci, 0);
                        err = USBD_IOERROR;
                }
                xfer->ux_status = err;
@@ -1287,7 +1731,7 @@ xhci_handle_event(struct xhci_softc * co
                        }
                        cv_signal(&sc->sc_command_cv);
                } else {
-                       DPRINTFN(1, "event: %p 0x%016"PRIx64" "
+                       DPRINTFN(1, "spurious event: %p 0x%016"PRIx64" "
                            "0x%08"PRIx32" 0x%08"PRIx32, trb, trb_0,
                            trb_2, trb_3);
                }
@@ -1418,7 +1862,8 @@ xhci_new_device(device_t parent, struct 
        int rhport = 0;
        struct xhci_slot *xs;
        uint32_t *cp;
-       uint8_t slot;
+       uint32_t route = 0;
+       uint8_t slot = 0;
        uint8_t addr;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -1439,11 +1884,21 @@ xhci_new_device(device_t parent, struct 
        dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT;
        dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
        dev->ud_ep0desc.bmAttributes = UE_CONTROL;
-       /* XXX */
-       if (speed == USB_SPEED_LOW)
+       /* 4.3,  4.8.2.1 */
+       switch (speed) {
+       case USB_SPEED_SUPER:
+               USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET);
+               break;
+       case USB_SPEED_FULL:
+               /* XXX using 64 as initial mps of ep0 in FS */
+       case USB_SPEED_HIGH:
+               USETW(dev->ud_ep0desc.wMaxPacketSize, USB_2_MAX_CTRL_PACKET);
+               break;
+       case USB_SPEED_LOW:
+       default:
                USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET);
-       else
-               USETW(dev->ud_ep0desc.wMaxPacketSize, 64);
+               break;
+       }
        dev->ud_ep0desc.bInterval = 0;
 
        /* doesn't matter, just don't let it uninitialized */
@@ -1461,28 +1916,48 @@ xhci_new_device(device_t parent, struct 
        up->up_dev = dev;
 
        /* Locate root hub port */
-       for (adev = dev, hub = dev;
-           hub != NULL;
-           adev = hub, hub = hub->ud_myhub) {
-               DPRINTFN(4, "hub %p", hub, 0, 0, 0);
-       }
-       DPRINTFN(4, "hub %p", hub, 0, 0, 0);
+       for (hub = dev; hub != NULL; hub = hub->ud_myhub) {
+               uint32_t dep;
+
+               DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
+                   hub, hub->ud_depth, hub->ud_powersrc,
+                   hub->ud_powersrc ? hub->ud_powersrc->up_portno : -1);
+
+               if (hub->ud_powersrc == NULL)
+                       break;
+               dep = hub->ud_depth;
+               if (dep == 0)
+                       break;
+               rhport = hub->ud_powersrc->up_portno;
+               if (dep > USB_HUB_MAX_DEPTH)
+                       continue;
 
-       if (hub != NULL) {
-               for (int p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
+               route |=
+                   (rhport > UHD_SS_NPORTS_MAX ? UHD_SS_NPORTS_MAX : rhport)
+                   << ((dep - 1) * 4);
+       }
+       route = route >> 4;
+       DPRINTFN(4, "rhport %d Route %05x hub %p", rhport, route, hub, 0);
+
+       /* Locate port on upstream high speed hub */
+       for (adev = dev, hub = up->up_parent;
+            hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
+            adev = hub, hub = hub->ud_myhub)
+               ;
+       if (hub) {
+               int p;
+               for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
                        if (hub->ud_hub->uh_ports[p].up_dev == adev) {
-                               rhport = p;
+                               dev->ud_myhsport = &hub->ud_hub->uh_ports[p];
+                               goto found;
                        }
                }
+               panic("xhci_new_device: cannot find HS port");
+       found:
+               DPRINTFN(4, "high speed port %d", p, 0, 0, 0);
        } else {
-               rhport = port;
+               dev->ud_myhsport = NULL;
        }
-       if (speed == USB_SPEED_SUPER) {
-               rhport += sc->sc_ss_port_start - 1;
-       } else {
-               rhport += sc->sc_hs_port_start - 1;
-       }
-       DPRINTFN(4, "rhport %d", rhport, 0, 0, 0);
 
        dev->ud_speed = speed;
        dev->ud_langid = USBD_NOLANG;
@@ -1492,8 +1967,7 @@ xhci_new_device(device_t parent, struct 
        err = usbd_setup_pipe(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
            &dev->ud_pipe0);
        if (err) {
-               usbd_remove_device(dev, up);
-               return err;
+               goto bad;
        }
 
        dd = &dev->ud_ddesc;
@@ -1503,19 +1977,24 @@ xhci_new_device(device_t parent, struct 
                bus->ub_devices[dev->ud_addr] = dev;
                err = usbd_get_initial_ddesc(dev, dd);
                if (err)
-                       return err;
+                       goto bad;
                err = usbd_reload_device_desc(dev);
                if (err)
-                       return err;
+                       goto bad;
        } else {
                err = xhci_enable_slot(sc, &slot);
                if (err)
-                       return err;
-               err = xhci_init_slot(sc, slot, depth, speed, port, rhport);
-               if (err)
-                       return err;
+                       goto bad;
                xs = &sc->sc_slots[slot];
                dev->ud_hcpriv = xs;
+               err = xhci_init_slot(dev, slot, route, rhport);
+               if (err) {
+                       dev->ud_hcpriv = NULL;
+                       goto bad;
+               }
+
+               /* Allow device time to set new address */
+               usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
                cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT);
                //hexdump("slot context", cp, sc->sc_ctxsz);
                addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]);
@@ -1530,12 +2009,19 @@ xhci_new_device(device_t parent, struct 
 
                err = usbd_get_initial_ddesc(dev, dd);
                if (err)
-                       return err;
+                       goto bad;
                /* 4.8.2.1 */
-               if (speed == USB_SPEED_SUPER)
+               if (speed == USB_SPEED_SUPER) {
+                       if (dd->bMaxPacketSize != 9) {
+                               printf("%s: invalid mps 2^%u for SS ep0,"
+                                   " using 512\n",
+                                   device_xname(sc->sc_dev),
+                                   dd->bMaxPacketSize);
+                               dd->bMaxPacketSize = 9;
+                       }
                        USETW(dev->ud_ep0desc.wMaxPacketSize,
                            (1 << dd->bMaxPacketSize));
-               else
+               } else
                        USETW(dev->ud_ep0desc.wMaxPacketSize,
                            dd->bMaxPacketSize);
                DPRINTFN(4, "bMaxPacketSize %u", dd->bMaxPacketSize, 0, 0, 0);
@@ -1543,11 +2029,15 @@ xhci_new_device(device_t parent, struct 
                    UGETW(dev->ud_ep0desc.wMaxPacketSize));
                err = usbd_reload_device_desc(dev);
                if (err)
-                       return err;
+                       goto bad;
 
+#if 0
+               /* Re-establish the default pipe with the new MPS. */
+               /* In xhci this is done by xhci_update_ep0_mps. */
                usbd_kill_pipe(dev->ud_pipe0);
                err = usbd_setup_pipe(dev, 0, &dev->ud_ep0,
                    USBD_DEFAULT_INTERVAL, &dev->ud_pipe0);
+#endif
        }
 
        DPRINTFN(1, "adding unit addr=%d, rev=%02x,",
@@ -1569,12 +2059,12 @@ xhci_new_device(device_t parent, struct 
 
 
        err = usbd_probe_and_attach(parent, dev, port, dev->ud_addr);
-       if (err) {
+ bad:
+       if (err != USBD_NORMAL_COMPLETION) {
                usbd_remove_device(dev, up);
-               return err;
        }
 
-       return USBD_NORMAL_COMPLETION;
+       return err;
 }
 
 static usbd_status
@@ -1713,8 +2203,8 @@ xhci_ring_put(struct xhci_softc * const 
 }
 
 static usbd_status
-xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
-    int timeout)
+xhci_do_command1(struct xhci_softc * const sc, struct xhci_trb * const trb,
+    int timeout, int locked)
 {
        struct xhci_ring * const cr = &sc->sc_cr;
        usbd_status err;
@@ -1723,7 +2213,10 @@ xhci_do_command(struct xhci_softc * cons
        DPRINTFN(12, "input: 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
            trb->trb_0, trb->trb_2, trb->trb_3, 0);
 
-       mutex_enter(&sc->sc_lock);
+       KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
+
+       if (!locked)
+               mutex_enter(&sc->sc_lock);
 
        KASSERT(sc->sc_command_addr == 0);
        sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
@@ -1762,11 +2255,26 @@ xhci_do_command(struct xhci_softc * cons
 
 timedout:
        sc->sc_command_addr = 0;
-       mutex_exit(&sc->sc_lock);
+       if (!locked)
+               mutex_exit(&sc->sc_lock);
        return err;
 }
 
 static usbd_status
+xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
+    int timeout)
+{
+       return xhci_do_command1(sc, trb, timeout, 0);
+}
+
+static usbd_status
+xhci_do_command_locked(struct xhci_softc * const sc,
+    struct xhci_trb * const trb, int timeout)
+{
+       return xhci_do_command1(sc, trb, timeout, 1);
+}
+
+static usbd_status
 xhci_enable_slot(struct xhci_softc * const sc, uint8_t * const slotp)
 {
        struct xhci_trb trb;
@@ -1789,6 +2297,36 @@ xhci_enable_slot(struct xhci_softc * con
 }
 
 static usbd_status
+xhci_disable_slot(struct xhci_softc * const sc, uint8_t slot)
+{
+       struct xhci_trb trb;
+       struct xhci_slot *xs;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       if (sc->sc_dying)
+               return USBD_IOERROR;
+
+       xs = &sc->sc_slots[slot];
+       if (xs->xs_idx != 0) {
+               for (int i = XHCI_DCI_SLOT + 1; i < 32; i++) {
+                       xhci_ring_free(sc, &xs->xs_ep[i].xe_tr);
+                       memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i]));
+               }
+               usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
+               usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
+       }
+
+       trb.trb_0 = 0;
+       trb.trb_2 = 0;
+       trb.trb_3 = htole32(
+               XHCI_TRB_3_SLOT_SET(slot) |
+               XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT));
+
+       return xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+}
+
+static usbd_status
 xhci_address_device(struct xhci_softc * const sc,
     uint64_t icp, uint8_t slot_id, bool bsr)
 {
@@ -1855,46 +2393,20 @@ xhci_set_dcba(struct xhci_softc * const 
 }
 
 static usbd_status
-xhci_init_slot(struct xhci_softc * const sc, uint32_t slot, int depth,
-    int speed, int port, int rhport)
+xhci_init_slot(struct usbd_device *dev, uint32_t slot, int route, int rhport)
 {
+       struct xhci_softc * const sc = dev->ud_bus->ub_hcpriv;
        struct xhci_slot *xs;
        usbd_status err;
        u_int dci;
        uint32_t *cp;
-       uint32_t mps;
-       uint32_t xspeed;
+       uint32_t mps = UGETW(dev->ud_ep0desc.wMaxPacketSize);
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
-       DPRINTFN(4, "slot %u depth %d speed %d",
-           slot, depth, speed, 0);
-       DPRINTFN(4, " port %d rhport %d",
-           port, rhport, 0, 0);
-
-       switch (speed) {
-       case USB_SPEED_LOW:
-               xspeed = 2;
-               mps = USB_MAX_IPACKET;
-               break;
-       case USB_SPEED_FULL:
-               xspeed = 1;
-               mps = 64;
-               break;
-       case USB_SPEED_HIGH:
-               xspeed = 3;
-               mps = USB_2_MAX_CTRL_PACKET;
-               break;
-       case USB_SPEED_SUPER:
-               xspeed = 4;
-               mps = USB_3_MAX_CTRL_PACKET;
-               break;
-       default:
-               DPRINTFN(0, "impossible speed: %x", speed, 0, 0, 0);
-               return USBD_INVAL;
-       }
+       DPRINTFN(4, "slot %u speed %d rhport %d route %05x",
+           slot, dev->ud_speed, route, rhport);
 
        xs = &sc->sc_slots[slot];
-       xs->xs_idx = slot;
 
        /* allocate contexts */
        err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
@@ -1906,7 +2418,7 @@ xhci_init_slot(struct xhci_softc * const
        err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
            &xs->xs_ic_dma);
        if (err)
-               return err;
+               goto bad1;
        memset(KERNADDR(&xs->xs_ic_dma, 0), 0, sc->sc_pgsz);
 
        for (dci = 0; dci < 32; dci++) {
@@ -1918,7 +2430,7 @@ xhci_init_slot(struct xhci_softc * const
                    XHCI_TRANSFER_RING_TRBS, XHCI_TRB_ALIGN);
                if (err) {
                        DPRINTFN(0, "ring init failure", 0, 0, 0, 0);
-                       return err;
+                       goto bad2;
                }
        }
 
@@ -1930,17 +2442,10 @@ xhci_init_slot(struct xhci_softc * const
 
        /* set up input slot context */
        cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
-       cp[0] = htole32(
-               XHCI_SCTX_0_CTX_NUM_SET(1) |
-               XHCI_SCTX_0_SPEED_SET(xspeed)
-               );
-       cp[1] = htole32(
-               XHCI_SCTX_1_RH_PORT_SET(rhport)
-               );
-       cp[2] = htole32(
-               XHCI_SCTX_2_IRQ_TARGET_SET(0)
-               );
-       cp[3] = htole32(0);
+       xhci_setup_sctx(dev, cp);
+       cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(1));
+       cp[0] |= htole32(XHCI_SCTX_0_ROUTE_SET(route));
+       cp[1] |= htole32(XHCI_SCTX_1_RH_PORT_SET(rhport));
 
        /* set up input EP0 context */
        cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_EP_CONTROL));
@@ -1972,6 +2477,20 @@ xhci_init_slot(struct xhci_softc * const
        hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),
            sc->sc_ctxsz * 2);
 
+ bad2:
+       if (err == USBD_NORMAL_COMPLETION) {
+               xs->xs_idx = slot;
+       } else {
+               for (int i = 1; i < dci; i++) {
+                       xhci_ring_free(sc, &xs->xs_ep[i].xe_tr);
+                       memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i]));
+               }
+               usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
+ bad1:
+               usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
+               xs->xs_idx = 0;
+       }
+
        return err;
 }
 
@@ -2031,10 +2550,10 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
        case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
                DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",
                             index, value, 0, 0);
-               if (index < 1 || index > sc->sc_hs_port_count) {
+               if (index < 1 || index > sc->sc_maxports) {
                        return -1;
                }
-               port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+               port = XHCI_PORTSC(index);
                v = xhci_op_read_4(sc, port);
                DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
                v &= ~XHCI_PS_CLEAR;
@@ -2056,9 +2575,18 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                case UHF_C_PORT_SUSPEND:
                case UHF_C_PORT_OVER_CURRENT:
                        return -1;
+               case UHF_C_BH_PORT_RESET:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_WRC);
+                       break;
                case UHF_C_PORT_RESET:
                        xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
                        break;
+               case UHF_C_PORT_LINK_STATE:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_PLC);
+                       break;
+               case UHF_C_PORT_CONFIG_ERROR:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_CEC);
+                       break;
                default:
                        return -1;
                }
@@ -2073,7 +2601,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 
                totlen = min(buflen, sizeof(hubd));
                memcpy(&hubd, buf, totlen);
-               hubd.bNbrPorts = sc->sc_hs_port_count;
+               hubd.bNbrPorts = sc->sc_maxports;
                USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
                hubd.bPwrOn2PwrGood = 200;
                for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)
@@ -2097,10 +2625,8 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                if (len != 4) {
                        return -1;
                }
-               v = xhci_op_read_4(sc, XHCI_PORTSC(sc->sc_hs_port_start - 1 +
-                   index));
-               DPRINTFN(4, "READ_CLASS_OTHER GET_STATUS PORTSC %d (%d) %08x",
-                   index, sc->sc_hs_port_start - 1 + index, v, 0);
+               v = xhci_op_read_4(sc, XHCI_PORTSC(index));
+               DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
                switch (XHCI_PS_SPEED_GET(v)) {
                case 1:
                        i = UPS_FULL_SPEED;
@@ -2111,6 +2637,9 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                case 3:
                        i = UPS_HIGH_SPEED;
                        break;
+               case 4:
+                       i = UPS_SUPER_SPEED;
+                       break;
                default:
                        i = 0;
                        break;
@@ -2120,26 +2649,39 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                if (v & XHCI_PS_OCA)    i |= UPS_OVERCURRENT_INDICATOR;
                //if (v & XHCI_PS_SUSP) i |= UPS_SUSPEND;
                if (v & XHCI_PS_PR)     i |= UPS_RESET;
-               if (v & XHCI_PS_PP)     i |= UPS_PORT_POWER;
+               if (v & XHCI_PS_PP) {
+                       if (i & UPS_SUPER_SPEED)
+                                       i |= UPS_PORT_POWER_SS;
+                       else
+                                       i |= UPS_PORT_POWER;
+               }
                USETW(ps.wPortStatus, i);
                i = 0;
                if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
                if (v & XHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;
                if (v & XHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;
                if (v & XHCI_PS_PRC)    i |= UPS_C_PORT_RESET;
+               if (v & XHCI_PS_WRC)    i |= UPS_C_BH_PORT_RESET;
+               if (v & XHCI_PS_PLC)    i |= UPS_C_PORT_LINK_STATE;
+               if (v & XHCI_PS_CEC)    i |= UPS_C_PORT_CONFIG_ERROR;
                USETW(ps.wPortChange, i);
                totlen = min(len, sizeof(ps));
                memcpy(buf, &ps, totlen);
                break;
        case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
                return -1;
+       case C(UR_SET_HUB_DEPTH, UT_WRITE_CLASS_DEVICE):
+               break;
        case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
                break;
        case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
-               if (index < 1 || index > sc->sc_hs_port_count) {
+       {
+               int optval = (index >> 8) & 0xff;
+               index &= 0xff;
+               if (index < 1 || index > sc->sc_maxports) {
                        return -1;
                }
-               port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+               port = XHCI_PORTSC(index);
                v = xhci_op_read_4(sc, port);
                DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
                v &= ~XHCI_PS_CLEAR;
@@ -2172,9 +2714,30 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                case UHF_C_PORT_RESET:
                        xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
                        break;
+               case UHF_PORT_U1_TIMEOUT:
+                       if (XHCI_PS_SPEED_GET(v) != 4) {
+                               return -1;
+                       }
+                       port = XHCI_PORTPMSC(index);
+                       v = xhci_op_read_4(sc, port);
+                       v &= ~XHCI_PM3_U1TO_SET(0xff);
+                       v |= XHCI_PM3_U1TO_SET(optval);
+                       xhci_op_write_4(sc, port, v);
+                       break;
+               case UHF_PORT_U2_TIMEOUT:
+                       if (XHCI_PS_SPEED_GET(v) != 4) {
+                               return -1;
+                       }
+                       port = XHCI_PORTPMSC(index);
+                       v = xhci_op_read_4(sc, port);
+                       v &= ~XHCI_PM3_U2TO_SET(0xff);
+                       v |= XHCI_PM3_U2TO_SET(optval);
+                       xhci_op_write_4(sc, port, v);
+                       break;
                default:
                        return -1;
                }
+       }
                break;
        case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
        case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
@@ -2237,8 +2800,6 @@ xhci_root_intr_abort(struct usbd_xfer *x
        KASSERT(mutex_owned(&sc->sc_lock));
        KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
 
-       DPRINTFN(1, "remove", 0, 0, 0, 0);
-
        sc->sc_intrxfer = NULL;
 
        xfer->ux_status = USBD_CANCELLED;
@@ -2311,6 +2872,8 @@ xhci_device_ctrl_start(struct usbd_xfer 
 
        /* XXX */
        if (tr->is_halted) {
+               DPRINTFN(1, "ctrl xfer %p halted: slot %u dci %u",
+                   xfer, xs->xs_idx, dci, 0);
                xhci_reset_endpoint(xfer->ux_pipe);
                tr->is_halted = false;
                xhci_set_dequeue(xfer->ux_pipe);
@@ -2400,12 +2963,16 @@ static void
 xhci_device_ctrl_abort(struct usbd_xfer *xfer)
 {
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       xhci_abort_xfer(xfer, USBD_CANCELLED);
 }
 
 static void
 xhci_device_ctrl_close(struct usbd_pipe *pipe)
 {
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       (void)xhci_close_pipe(pipe);
 }
 
 /* ------------------ */
@@ -2518,12 +3085,16 @@ static void
 xhci_device_bulk_abort(struct usbd_xfer *xfer)
 {
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       xhci_abort_xfer(xfer, USBD_CANCELLED);
 }
 
 static void
 xhci_device_bulk_close(struct usbd_pipe *pipe)
 {
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       (void)xhci_close_pipe(pipe);
 }
 
 /* ---------------- */
@@ -2646,8 +3217,7 @@ xhci_device_intr_abort(struct usbd_xfer 
        KASSERT(mutex_owned(&sc->sc_lock));
        DPRINTFN(15, "%p", xfer, 0, 0, 0);
        KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
-       xfer->ux_status = USBD_CANCELLED;
-       usb_transfer_complete(xfer);
+       xhci_abort_xfer(xfer, USBD_CANCELLED);
 }
 
 static void
@@ -2658,7 +3228,7 @@ xhci_device_intr_close(struct usbd_pipe 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
        DPRINTFN(15, "%p", pipe, 0, 0, 0);
 
-       xhci_unconfigure_endpoint(pipe);
+       (void)xhci_close_pipe(pipe);
 }
 
 /* ------------ */
--- src/sys/dev/usb/xhci.c.orig 2015-04-05 05:53:30.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-04-05 07:10:10.000000000 +0900
@@ -1123,6 +1123,12 @@ xhci_setup_sctx(struct usbd_device *dev,
        cp[3] |= htole32(0);
 }
 
+/*
+ * called
+ *  from xhci_open
+ *  from usbd_setup_pipe_flags
+ *  from usbd_open_pipe_ival
+ */
 static usbd_status
 xhci_configure_endpoint(struct usbd_pipe *pipe)
 {
@@ -1309,6 +1315,7 @@ xhci_unconfigure_endpoint(struct usbd_pi
 }
 #endif
 
+/* 4.6.8, 6.4.3.7 */
 static usbd_status
 xhci_reset_endpoint(struct usbd_pipe *pipe)
 {
@@ -1334,6 +1341,11 @@ xhci_reset_endpoint(struct usbd_pipe *pi
        return err;
 }
 
+/*
+ * 4.6.9, 6.4.3.8
+ * Stop execution of TDs on xfer ring.
+ * Should be called with sc_lock held.
+ */
 static usbd_status
 xhci_stop_endpoint(struct usbd_pipe *pipe)
 {
@@ -1359,6 +1371,12 @@ xhci_stop_endpoint(struct usbd_pipe *pip
        return err;
 }
 
+/*
+ * Set TR Dequeue Pointer.
+ * xCHI 1.1  4.6.10  6.4.3.9
+ * Purge all of transfer requests in ring.
+ * EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
+ */
 static usbd_status
 xhci_set_dequeue(struct usbd_pipe *pipe)
 {
@@ -1379,6 +1397,7 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
        xr->xr_ep = 0;
        xr->xr_cs = 1;
 
+       /* set DCS */
        trb.trb_0 = xhci_ring_trbp(xr, 0) | 1; /* XXX */
        trb.trb_2 = 0;
        trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
@@ -1390,6 +1409,11 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
        return err;
 }
 
+/*
+ * Open new pipe: called from usbd_setup_pipe_flags.
+ * Fills methods of pipe.
+ * If pipe is not for ep0, calls configure_endpoint.
+ */
 static usbd_status
 xhci_open(struct usbd_pipe *pipe)
 {
@@ -1449,6 +1473,11 @@ xhci_open(struct usbd_pipe *pipe)
        return USBD_NORMAL_COMPLETION;
 }
 
+/*
+ * Closes pipe, called from usbd_kill_pipe via close methods.
+ * If the endpoint to be closed is ep0, disable_slot.
+ * Should be called with sc_lock held.
+ */
 static usbd_status
 xhci_close_pipe(struct usbd_pipe *pipe)
 {
@@ -1482,6 +1511,10 @@ xhci_close_pipe(struct usbd_pipe *pipe)
                return xhci_disable_slot(sc, xs->xs_idx);
        }
 
+       /*
+        * This may fail in the case that xhci_close_pipe is called after
+        * xhci_abort_xfer e.g. usbd_kill_pipe.
+        */
        (void)xhci_stop_endpoint(pipe);
 
        /*
@@ -1511,6 +1544,11 @@ xhci_close_pipe(struct usbd_pipe *pipe)
        return err;
 }
 
+/*
+ * Abort transfer.
+ * Called with sc_lock held.
+ * May be called from softintr context.
+ */
 static void
 xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
 {
@@ -1540,6 +1578,7 @@ xhci_abort_xfer(struct usbd_xfer *xfer, 
 }
 
 #if 1 /* XXX experimental */
+/* issue reset_ep and set_dequeue in thread context */
 static void
 xhci_clear_endpoint_stall_async_task(void *cookie)
 {
@@ -1574,6 +1613,7 @@ xhci_clear_endpoint_stall_async(struct u
                return USBD_IOERROR;
        }
 
+       /* XXX never use up_async_task for incompatible type of function */
        usb_init_task(&xfer->ux_pipe->up_async_task,
            xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
        usb_add_task(xfer->ux_pipe->up_dev, &xfer->ux_pipe->up_async_task,
@@ -1584,6 +1624,9 @@ xhci_clear_endpoint_stall_async(struct u
 }
 
 #endif /* XXX experimental */
+/*
+ * Notify roothub port status/change to uhub_intr.
+ */
 static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {
@@ -1604,6 +1647,12 @@ xhci_rhpsc(struct xhci_softc * const sc,
        usb_transfer_complete(xfer);
 }
 
+/*
+ * Process events:
+ * + Transfer comeplete
+ * + Command complete
+ * + Roothub Port status/change
+ */
 static void
 xhci_handle_event(struct xhci_softc * const sc,
     const struct xhci_trb * const trb)
@@ -1849,6 +1898,16 @@ xhci_get_lock(struct usbd_bus *bus, kmut
 
 extern uint32_t usb_cookie_no;
 
+/*
+ * Called if uhub_explore find new device (via usbd_new_device).
+ * Allocate and construct dev structure of default endpoint (ep0).
+ *   Determine initial MaxPacketSize (mps) by speed.
+ *   Determine route string and roothub port for slot of dev.
+ * Allocate pipe of ep0.
+ * Enable and initialize slot and Set Address.
+ * Read device descriptor.
+ * Register this device.
+ */
 static usbd_status
 xhci_new_device(device_t parent, struct usbd_bus *bus, int depth,
     int speed, int port, struct usbd_port *up)
@@ -2202,6 +2261,13 @@ xhci_ring_put(struct xhci_softc * const 
        DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);
 }
 
+/*
+ * Put a command on command ring, ring bell, set timer, and cv_timedwait.
+ * Command completion is notified by cv_signal from xhci_handle_event
+ * (called from interrupt from xHCI), or timed-out.
+ * Command validation is performed in xhci_handle_event by checking if
+ * trb_0 in CMD_COMPLETE TRB and sc->sc_command_addr are identical.
+ */
 static usbd_status
 xhci_do_command1(struct xhci_softc * const sc, struct xhci_trb * const trb,
     int timeout, int locked)
@@ -2218,6 +2284,7 @@ xhci_do_command1(struct xhci_softc * con
        if (!locked)
                mutex_enter(&sc->sc_lock);
 
+       /* XXX KASSERT may fire when cv_timedwait unlocks sc_lock */
        KASSERT(sc->sc_command_addr == 0);
        sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
 
@@ -2267,6 +2334,11 @@ xhci_do_command(struct xhci_softc * cons
        return xhci_do_command1(sc, trb, timeout, 0);
 }
 
+/*
+ * This allows xhci_do_command with already sc_lock held.
+ * This is needed as USB stack calls close methods with sc_lock_held.
+ * (see usbdivar.h)
+ */
 static usbd_status
 xhci_do_command_locked(struct xhci_softc * const sc,
     struct xhci_trb * const trb, int timeout)
@@ -2296,6 +2368,10 @@ xhci_enable_slot(struct xhci_softc * con
        return err;
 }
 
+/*
+ * Deallocate DMA buffer and ring buffer, and disable_slot.
+ * Should be called with sc_lock held.
+ */
 static usbd_status
 xhci_disable_slot(struct xhci_softc * const sc, uint8_t slot)
 {
@@ -2326,6 +2402,12 @@ xhci_disable_slot(struct xhci_softc * co
        return xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
 }
 
+/*
+ * Change slot state.
+ * bsr=0: ENABLED -> ADDRESSED
+ * bsr=1: ENABLED -> DEFAULT
+ * see xHCI 1.1  4.5.3, 3.3.4
+ */
 static usbd_status
 xhci_address_device(struct xhci_softc * const sc,
     uint64_t icp, uint8_t slot_id, bool bsr)
@@ -2392,6 +2474,11 @@ xhci_set_dcba(struct xhci_softc * const 
            BUS_DMASYNC_PREWRITE);
 }
 
+/*
+ * Allocate DMA buffer and ring buffer for specified slot
+ * and set Device Context Base Address
+ * and issue Set Address device command.
+ */
 static usbd_status
 xhci_init_slot(struct usbd_device *dev, uint32_t slot, int route, int rhport)
 {
@@ -2502,6 +2589,9 @@ xhci_noop(struct usbd_pipe *pipe)
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }
 
+/*
+ * Process root hub request.
+ */
 static int
 xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
     void *buf, int buflen)
@@ -2773,6 +2863,7 @@ xhci_root_intr_transfer(struct usbd_xfer
        return xhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
+/* Wait for roothub port status/change */
 static usbd_status
 xhci_root_intr_start(struct usbd_xfer *xfer)
 {
--- src/sys/dev/usb/xhci.c.orig 2015-04-05 07:10:10.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-04-05 08:46:34.000000000 +0900
@@ -32,9 +32,17 @@ __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #include "opt_usb.h"
 
 #include <sys/param.h>
+
+#if __NetBSD_Version__ >= 799000200
+#define USE_USBHIST
+#endif
+
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/kmem.h>
+#ifndef NHUSB
+#include <sys/malloc.h>
+#endif
 #include <sys/device.h>
 #include <sys/select.h>
 #include <sys/proc.h>
@@ -50,16 +58,96 @@ __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdivar.h>
+#undef NHUSB
+/* XXX any other better flag.. */
+#ifndef URQ_AUTO_DMABUF
+#define NHUSB
+#endif
 #include <dev/usb/usbdi_util.h>
+#ifdef USE_USBHIST
 #include <dev/usb/usbhist.h>
+#endif
 #include <dev/usb/usb_mem.h>
 #include <dev/usb/usb_quirks.h>
 
 #include <dev/usb/xhcireg.h>
 #include <dev/usb/xhcivar.h>
+#ifndef NHUSB
+#include <dev/usb/usbroothub_subr.h>
+#else
 #include <dev/usb/usbroothub.h>
+#endif
+
 
+#ifndef NHUSB
+/* usbd_xfer */
+#define ux_pipe                pipe
+#define ux_priv                priv
+#define ux_buffer      buffer
+#define ux_length      length
+#define ux_actlen      actlen
+#define ux_flags       flags
+#define ux_timeout     timeout
+#define ux_status      status
+#define ux_callback    callback
+#define ux_done                done
+#define ux_state       busy_free
+#define ux_request     request
+#define ux_frlengths   frlengths
+#define ux_nframes     nframes
+#define ux_dmabuf      dmabuf
+#define ux_rqflags     rqflags
+#define ux_hcpriv      hcpriv
+#define ux_hcflags     hcflags
+#define ux_callout     timeout_handle
+#define ux_hccv                hccv
+/* usbd_pipe */
+#define up_dev         device
+#define up_endpoint    endpoint
+#define up_queue       queue
+#define up_async_task  async_task
+#define up_intrxfer    intrxfer
+#define up_repeat      repeat
+#define up_interval    interval
+#define up_methods     methods
+/* usbd_device */
+#define ud_bus         bus
+#define ud_pipe0       default_pipe
+#define ud_addr                address
+#define ud_depth       depth
+#define ud_speed       speed
+#define ud_langid      langid
+#define ud_cookie      cookie
+#define ud_powersrc    powersrc
+#define ud_myhub       myhub
+#define ud_myhsport    myhsport
+#define ud_ep0desc     def_ep_desc
+#define ud_ep0         def_ep
+#define ud_ddesc       ddesc
+#define ud_quirks      quirks
+#define ud_hub         hub
+#define ud_hcpriv      hci_private
+/* usbd_endpoint */
+#define ue_edesc       edesc
+#define ue_toggle      datatoggle
+/* usbd_bus */
+#define ub_hcpriv      hci_private
+#define ub_revision    usbrev
+#define ub_methods     methods
+#define ub_pipesize    pipe_size
+#define ub_roothub     root_hub
+#define ub_devices     devices
+#define ub_usepolling  use_polling
+/* usbd_hub */
+#define uh_hubdesc     hubdesc
+#define uh_ports       ports
+/* usbd_port */
+#define up_portno      portno
+#define up_parent      parent
+/* usb_dma_block */
+#define udma_block     block
 
+#endif
 #ifdef USB_DEBUG
 #ifndef XHCI_DEBUG
 #define xhcidebug 0
@@ -96,9 +184,34 @@ fail:
 #endif /* !XHCI_DEBUG */
 #endif /* USB_DEBUG */
 
+#ifdef USE_USBHIST
 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)
 #define XHCIHIST_FUNC() USBHIST_FUNC()
 #define XHCIHIST_CALLED(name) USBHIST_CALLED(xhcidebug)
+#else /* USE_USBHIST */
+# if defined(USB_DEBUG) && defined(XHCI_DEBUG)
+/* fake USBHIST_LOGN() for netbsd-7 */
+static void
+xhci_histprint(const char *fmt, u_long a0, u_long a1, u_long a2, u_long a3)
+{
+       printf(fmt, a0, a1, a2, a3);
+}
+#  define DPRINTFN(N,FMT,A,B,C,D) do {                                 \
+       if (xhcidebug >= (N)) {                                         \
+               printf("%s: ", __func__);                               \
+               xhci_histprint((FMT),                                   \
+                   (u_long)(A), (u_long)(B), (u_long)(C), (u_long)(D));\
+               printf("\n");                                           \
+       }                                                               \
+    } while(0)
+#  define XHCIHIST_FUNC() do {} while(0)
+#  define XHCIHIST_CALLED(name) do {} while(0)
+# else /* defined(USB_DEBUG) && defined(XHCI_DEBUG) */
+#  define DPRINTFN(N,FMT,A,B,C,D) do {} while(0)
+#  define XHCIHIST_FUNC() do {} while(0)
+#  define XHCIHIST_CALLED(name) do {} while(0)
+# endif /* defined(USB_DEBUG) && defined(XHCI_DEBUG) */
+#endif /* USE_USBHIST */
 
 #define XHCI_DCI_SLOT 0
 #define XHCI_DCI_EP_CONTROL 1
@@ -109,6 +222,9 @@ struct xhci_pipe {
        struct usbd_pipe xp_pipe;
 };
 
+#ifndef NHUSB
+#define USBROOTHUB_INTR_ENDPT 1
+#endif
 #define XHCI_COMMAND_RING_TRBS 256
 #define XHCI_EVENT_RING_TRBS 256
 #define XHCI_EVENT_RING_SEGMENTS 1
@@ -118,13 +234,19 @@ static usbd_status xhci_open(struct usbd
 static int xhci_intr1(struct xhci_softc * const);
 static void xhci_softintr(void *);
 static void xhci_poll(struct usbd_bus *);
+#ifndef NHUSB
+static usbd_status xhci_allocm(struct usbd_bus *, usb_dma_t *, uint32_t);
+static void xhci_freem(struct usbd_bus *, usb_dma_t *);
+#endif
 static struct usbd_xfer *xhci_allocx(struct usbd_bus *);
 static void xhci_freex(struct usbd_bus *, struct usbd_xfer *);
 static void xhci_get_lock(struct usbd_bus *, kmutex_t **);
 static usbd_status xhci_new_device(device_t, struct usbd_bus *, int, int, int,
     struct usbd_port *);
+#ifdef NHUSB
 static int xhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
     void *, int);
+#endif
 
 static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
 //static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
@@ -153,6 +275,14 @@ static void xhci_ring_free(struct xhci_s
 
 static void xhci_noop(struct usbd_pipe *);
 
+#ifndef NHUSB
+static usbd_status xhci_root_ctrl_transfer(struct usbd_xfer *);
+static usbd_status xhci_root_ctrl_start(struct usbd_xfer *);
+static void xhci_root_ctrl_abort(struct usbd_xfer *);
+static void xhci_root_ctrl_close(struct usbd_pipe *);
+static void xhci_root_ctrl_done(struct usbd_xfer *);
+
+#endif
 static usbd_status xhci_root_intr_transfer(struct usbd_xfer *);
 static usbd_status xhci_root_intr_start(struct usbd_xfer *);
 static void xhci_root_intr_abort(struct usbd_xfer *);
@@ -181,6 +311,17 @@ static void xhci_timeout(void *);
 static void xhci_timeout_task(void *);
 
 static const struct usbd_bus_methods xhci_bus_methods = {
+#ifndef NHUSB
+       .open_pipe = xhci_open,
+       .soft_intr = xhci_softintr,
+       .do_poll = xhci_poll,
+       .allocm = xhci_allocm,
+       .freem = xhci_freem,
+       .allocx = xhci_allocx,
+       .freex = xhci_freex,
+       .get_lock = xhci_get_lock,
+       .new_device = xhci_new_device,
+#else
        .ubm_open = xhci_open,
        .ubm_softint = xhci_softintr,
        .ubm_dopoll = xhci_poll,
@@ -189,47 +330,99 @@ static const struct usbd_bus_methods xhc
        .ubm_getlock = xhci_get_lock,
        .ubm_newdev = xhci_new_device,
        .ubm_rhctrl = xhci_roothub_ctrl,
+#endif
+};
+
+#ifndef NHUSB
+static const struct usbd_pipe_methods xhci_root_ctrl_methods = {
+       .transfer = xhci_root_ctrl_transfer,
+       .start = xhci_root_ctrl_start,
+       .abort = xhci_root_ctrl_abort,
+       .close = xhci_root_ctrl_close,
+       .cleartoggle = xhci_noop,
+       .done = xhci_root_ctrl_done,
 };
 
+#endif
 static const struct usbd_pipe_methods xhci_root_intr_methods = {
+#ifndef NHUSB
+       .transfer = xhci_root_intr_transfer,
+       .start = xhci_root_intr_start,
+       .abort = xhci_root_intr_abort,
+       .close = xhci_root_intr_close,
+       .cleartoggle = xhci_noop,
+       .done = xhci_root_intr_done,
+#else
        .upm_transfer = xhci_root_intr_transfer,
        .upm_start = xhci_root_intr_start,
        .upm_abort = xhci_root_intr_abort,
        .upm_close = xhci_root_intr_close,
        .upm_cleartoggle = xhci_noop,
        .upm_done = xhci_root_intr_done,
+#endif
 };
 
 
 static const struct usbd_pipe_methods xhci_device_ctrl_methods = {
+#ifndef NHUSB
+       .transfer = xhci_device_ctrl_transfer,
+       .start = xhci_device_ctrl_start,
+       .abort = xhci_device_ctrl_abort,
+       .close = xhci_device_ctrl_close,
+       .cleartoggle = xhci_noop,
+       .done = xhci_device_ctrl_done,
+#else
        .upm_transfer = xhci_device_ctrl_transfer,
        .upm_start = xhci_device_ctrl_start,
        .upm_abort = xhci_device_ctrl_abort,
        .upm_close = xhci_device_ctrl_close,
        .upm_cleartoggle = xhci_noop,
        .upm_done = xhci_device_ctrl_done,
+#endif
 };
 
 static const struct usbd_pipe_methods xhci_device_isoc_methods = {
+#ifndef NHUSB
+       .cleartoggle = xhci_noop,
+#else
        .upm_cleartoggle = xhci_noop,
+#endif
 };
 
 static const struct usbd_pipe_methods xhci_device_bulk_methods = {
+#ifndef NHUSB
+       .transfer = xhci_device_bulk_transfer,
+       .start = xhci_device_bulk_start,
+       .abort = xhci_device_bulk_abort,
+       .close = xhci_device_bulk_close,
+       .cleartoggle = xhci_noop,
+       .done = xhci_device_bulk_done,
+#else
        .upm_transfer = xhci_device_bulk_transfer,
        .upm_start = xhci_device_bulk_start,
        .upm_abort = xhci_device_bulk_abort,
        .upm_close = xhci_device_bulk_close,
        .upm_cleartoggle = xhci_noop,
        .upm_done = xhci_device_bulk_done,
+#endif
 };
 
 static const struct usbd_pipe_methods xhci_device_intr_methods = {
+#ifndef NHUSB
+       .transfer = xhci_device_intr_transfer,
+       .start = xhci_device_intr_start,
+       .abort = xhci_device_intr_abort,
+       .close = xhci_device_intr_close,
+       .cleartoggle = xhci_noop,
+       .done = xhci_device_intr_done,
+#else
        .upm_transfer = xhci_device_intr_transfer,
        .upm_start = xhci_device_intr_start,
        .upm_abort = xhci_device_intr_abort,
        .upm_close = xhci_device_intr_close,
        .upm_cleartoggle = xhci_noop,
        .upm_done = xhci_device_intr_done,
+#endif
 };
 
 static inline uint32_t
@@ -618,7 +811,9 @@ xhci_init(struct xhci_softc *sc)
 
        /* XXX Low/Full/High speeds for now */
        sc->sc_bus.ub_revision = USBREV_2_0;
+#ifdef NHUSB
        sc->sc_bus.ub_usedma = true;
+#endif
 
        cap = xhci_read_4(sc, XHCI_CAPLENGTH);
        caplength = XHCI_CAP_CAPLENGTH(cap);
@@ -1434,7 +1629,11 @@ xhci_open(struct usbd_pipe *pipe)
        if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0) {
                switch (ed->bEndpointAddress) {
                case USB_CONTROL_ENDPOINT:
+#ifndef NHUSB
+                       pipe->up_methods = &xhci_root_ctrl_methods;
+#else
                        pipe->up_methods = &roothub_ctrl_methods;
+#endif
                        break;
                case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
                        pipe->up_methods = &xhci_root_intr_methods;
@@ -1639,7 +1838,11 @@ xhci_rhpsc(struct xhci_softc * const sc,
        if (xfer == NULL)
                return;
 
+#ifndef NHUSB
+       p = KERNADDR(&xfer->ux_dmabuf, 0);
+#else
        p = xfer->ux_buf;
+#endif
        memset(p, 0, xfer->ux_length);
        p[port/NBBY] |= 1 << (port%NBBY);
        xfer->ux_actlen = xfer->ux_length;
@@ -1852,6 +2055,45 @@ xhci_poll(struct usbd_bus *bus)
        return;
 }
 
+#ifndef NHUSB
+static usbd_status
+xhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)
+{
+       struct xhci_softc * const sc = bus->ub_hcpriv;
+       usbd_status err;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       err = usb_allocmem(&sc->sc_bus, size, 0, dma);
+#if 0
+       if (err == USBD_NOMEM)
+               err = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size);
+#endif
+#ifdef XHCI_DEBUG
+       if (err)
+               DPRINTFN(1, "usb_allocmem(%u)=%d", err, size, 0, 0);
+#endif
+
+       return err;
+}
+
+static void
+xhci_freem(struct usbd_bus *bus, usb_dma_t *dma)
+{
+       struct xhci_softc * const sc = bus->ub_hcpriv;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+#if 0
+       if (dma->udma_block->flags & USB_DMA_RESERVE) {
+               usb_reserve_freem(&sc->sc_dma_reserve, dma);
+               return;
+       }
+#endif
+       usb_freemem(&sc->sc_bus, dma);
+}
+
+#endif /* !NHUSB */
 static struct usbd_xfer *
 xhci_allocx(struct usbd_bus *bus)
 {
@@ -1929,7 +2171,11 @@ xhci_new_device(device_t parent, struct 
        DPRINTFN(4, "port=%d depth=%d speed=%d upport %d",
                 port, depth, speed, up->up_portno);
 
+#ifndef NHUSB
+       dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO);
+#else
        dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
+#endif
        if (dev == NULL)
                return USBD_NOMEM;
 
@@ -2589,6 +2835,489 @@ xhci_noop(struct usbd_pipe *pipe)
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }
 
+#ifndef NHUSB
+/* root hub descriptors */
+
+static const usb_device_descriptor_t xhci_devd = {
+       USB_DEVICE_DESCRIPTOR_SIZE,
+       UDESC_DEVICE,           /* type */
+       {0x00, 0x02},           /* USB version */
+       UDCLASS_HUB,            /* class */
+       UDSUBCLASS_HUB,         /* subclass */
+       UDPROTO_HSHUBSTT,       /* protocol */
+       64,                     /* max packet */
+       {0},{0},{0x00,0x01},    /* device id */
+       1,2,0,                  /* string indexes */
+       1                       /* # of configurations */
+};
+
+static const usb_device_qualifier_t xhci_odevd = {
+       USB_DEVICE_DESCRIPTOR_SIZE,
+       UDESC_DEVICE_QUALIFIER, /* type */
+       {0x00, 0x02},           /* USB version */
+       UDCLASS_HUB,            /* class */
+       UDSUBCLASS_HUB,         /* subclass */
+       UDPROTO_FSHUB,          /* protocol */
+       64,                     /* max packet */
+       1,                      /* # of configurations */
+       0
+};
+
+static const usb_config_descriptor_t xhci_confd = {
+       USB_CONFIG_DESCRIPTOR_SIZE,
+       UDESC_CONFIG,
+       {USB_CONFIG_DESCRIPTOR_SIZE +
+        USB_INTERFACE_DESCRIPTOR_SIZE +
+        USB_ENDPOINT_DESCRIPTOR_SIZE},
+       1,
+       1,
+       0,
+       UC_ATTR_MBO | UC_SELF_POWERED,
+       0                      /* max power */
+};
+
+static const usb_interface_descriptor_t xhci_ifcd = {
+       USB_INTERFACE_DESCRIPTOR_SIZE,
+       UDESC_INTERFACE,
+       0,
+       0,
+       1,
+       UICLASS_HUB,
+       UISUBCLASS_HUB,
+       UIPROTO_HSHUBSTT,
+       0
+};
+
+static const usb_endpoint_descriptor_t xhci_endpd = {
+       USB_ENDPOINT_DESCRIPTOR_SIZE,
+       UDESC_ENDPOINT,
+       UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
+       UE_INTERRUPT,
+       {8, 0},                 /* max packet */
+       12
+};
+
+static const usb_hub_descriptor_t xhci_hubd = {
+       USB_HUB_DESCRIPTOR_SIZE,
+       UDESC_HUB,
+       0,
+       {0,0},
+       0,
+       0,
+       {""},
+       {""},
+};
+
+/* root hub control */
+
+static usbd_status
+xhci_root_ctrl_transfer(struct usbd_xfer *xfer)
+{
+       struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+       usbd_status err;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       /* Insert last in queue. */
+       mutex_enter(&sc->sc_lock);
+       err = usb_insert_transfer(xfer);
+       mutex_exit(&sc->sc_lock);
+       if (err)
+               return err;
+
+       /* Pipe isn't running, start first */
+       return xhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
+}
+
+/*
+ * Process root hub request.
+ */
+static usbd_status
+xhci_root_ctrl_start(struct usbd_xfer *xfer)
+{
+       struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+       usb_port_status_t ps;
+       usb_device_request_t *req;
+       void *buf = NULL;
+       usbd_status err;
+       int len, value, index;
+       int l, totlen = 0;
+       int port, i;
+       uint32_t v;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       if (sc->sc_dying)
+               return USBD_IOERROR;
+
+       req = &xfer->ux_request;
+
+       len = UGETW(req->wLength);
+       value = UGETW(req->wValue);
+       index = UGETW(req->wIndex);
+
+       if (len != 0)
+               buf = KERNADDR(&xfer->ux_dmabuf, 0);
+
+       DPRINTFN(12, "rhreq: %04x %04x %04x %04x",
+           req->bmRequestType | (req->bRequest << 8), value, index, len);
+
+#define C(x,y) ((x) | ((y) << 8))
+       switch (C(req->bRequest, req->bmRequestType)) {
+       case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
+       case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
+       case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
+               /*
+                * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
+                * for the integrated root hub.
+                */
+               break;
+       case C(UR_GET_CONFIG, UT_READ_DEVICE):
+               if (len > 0) {
+                       *(uint8_t *)buf = sc->sc_conf;
+                       totlen = 1;
+               }
+               break;
+       case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
+               DPRINTFN(8, "getdesc: wValue=0x%04x", value, 0, 0, 0);
+               if (len == 0)
+                       break;
+               switch (value >> 8) {
+               case UDESC_DEVICE:
+                       if ((value & 0xff) != 0) {
+                               err = USBD_IOERROR;
+                               goto ret;
+                       }
+                       totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+                       memcpy(buf, &xhci_devd, min(l, sizeof(xhci_devd)));
+                       break;
+               case UDESC_DEVICE_QUALIFIER:
+                       if ((value & 0xff) != 0) {
+                       }
+                       totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+                       memcpy(buf, &xhci_odevd, min(l, sizeof(xhci_odevd)));
+                       break;
+               case UDESC_OTHER_SPEED_CONFIGURATION:
+               case UDESC_CONFIG:
+                       if ((value & 0xff) != 0) {
+                               err = USBD_IOERROR;
+                               goto ret;
+                       }
+                       totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
+                       memcpy(buf, &xhci_confd, min(l, sizeof(xhci_confd)));
+                       ((usb_config_descriptor_t *)buf)->bDescriptorType =
+                           value >> 8;
+                       buf = (char *)buf + l;
+                       len -= l;
+                       l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
+                       totlen += l;
+                       memcpy(buf, &xhci_ifcd, min(l, sizeof(xhci_ifcd)));
+                       buf = (char *)buf + l;
+                       len -= l;
+                       l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
+                       totlen += l;
+                       memcpy(buf, &xhci_endpd, min(l, sizeof(xhci_endpd)));
+                       break;
+               case UDESC_STRING:
+#define sd ((usb_string_descriptor_t *)buf)
+                       switch (value & 0xff) {
+                       case 0: /* Language table */
+                               totlen = usb_makelangtbl(sd, len);
+                               break;
+                       case 1: /* Vendor */
+                               totlen = usb_makestrdesc(sd, len, "NetBSD");
+                               break;
+                       case 2: /* Product */
+                               totlen = usb_makestrdesc(sd, len,
+                                   "xHCI Root Hub");
+                               break;
+                       }
+#undef sd
+                       break;
+               default:
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               break;
+       case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
+               if (len > 0) {
+                       *(uint8_t *)buf = 0;
+                       totlen = 1;
+               }
+               break;
+       case C(UR_GET_STATUS, UT_READ_DEVICE):
+               if (len > 1) {
+                       USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
+                       totlen = 2;
+               }
+               break;
+       case C(UR_GET_STATUS, UT_READ_INTERFACE):
+       case C(UR_GET_STATUS, UT_READ_ENDPOINT):
+               if (len > 1) {
+                       USETW(((usb_status_t *)buf)->wStatus, 0);
+                       totlen = 2;
+               }
+               break;
+       case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
+               if (value >= USB_MAX_DEVICES) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               //sc->sc_addr = value;
+               break;
+       case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
+               if (value != 0 && value != 1) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               sc->sc_conf = value;
+               break;
+       case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
+               break;
+       case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
+       case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
+       case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
+               err = USBD_IOERROR;
+               goto ret;
+       case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
+               break;
+       case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
+               break;
+       /* Hub requests */
+       case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
+               break;
+       /* Hub Port request */
+       case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
+               DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",
+                            index, value, 0, 0);
+               if (index < 1 || index > sc->sc_maxports) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               port = XHCI_PORTSC(index);
+               v = xhci_op_read_4(sc, port);
+               DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
+               v &= ~XHCI_PS_CLEAR;
+               switch (value) {
+               case UHF_PORT_ENABLE:
+                       xhci_op_write_4(sc, port, v &~ XHCI_PS_PED);
+                       break;
+               case UHF_PORT_SUSPEND:
+                       err = USBD_IOERROR;
+                       goto ret;
+               case UHF_PORT_POWER:
+                       break;
+               case UHF_PORT_TEST:
+               case UHF_PORT_INDICATOR:
+                       err = USBD_IOERROR;
+                       goto ret;
+               case UHF_C_PORT_CONNECTION:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_CSC);
+                       break;
+               case UHF_C_PORT_ENABLE:
+               case UHF_C_PORT_SUSPEND:
+               case UHF_C_PORT_OVER_CURRENT:
+                       err = USBD_IOERROR;
+                       goto ret;
+               case UHF_C_BH_PORT_RESET:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_WRC);
+                       break;
+               case UHF_C_PORT_RESET:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
+                       break;
+               case UHF_C_PORT_LINK_STATE:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_PLC);
+                       break;
+               case UHF_C_PORT_CONFIG_ERROR:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_CEC);
+                       break;
+               default:
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+
+               break;
+       case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
+               if (len == 0)
+                       break;
+               if ((value & 0xff) != 0) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               usb_hub_descriptor_t hubd = xhci_hubd;
+
+               hubd.bNbrPorts = sc->sc_maxports;
+               USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+               hubd.bPwrOn2PwrGood = 200;
+               for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)
+                       hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
+               hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
+               l = min(len, hubd.bDescLength);
+               totlen = l;
+               memcpy(buf, &hubd, l);
+               break;
+       case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
+               if (len != 4) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               memset(buf, 0, len); /* ? XXX */
+               totlen = len;
+               break;
+       case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
+               DPRINTFN(8, "get port status i=%d", index, 0, 0, 0);
+               if (index < 1 || index > sc->sc_maxports) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               if (len != 4) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               v = xhci_op_read_4(sc, XHCI_PORTSC(index));
+               DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
+               /* xspeed -> port_status value */
+               switch (XHCI_PS_SPEED_GET(v)) {
+               case 1:
+                       i = UPS_FULL_SPEED;
+                       break;
+               case 2:
+                       i = UPS_LOW_SPEED;
+                       break;
+               case 3:
+                       i = UPS_HIGH_SPEED;
+                       break;
+               case 4:
+                       i = UPS_SUPER_SPEED;
+                       break;
+               default:
+                       i = 0;
+                       break;
+               }
+               if (v & XHCI_PS_CCS)    i |= UPS_CURRENT_CONNECT_STATUS;
+               if (v & XHCI_PS_PED)    i |= UPS_PORT_ENABLED;
+               if (v & XHCI_PS_OCA)    i |= UPS_OVERCURRENT_INDICATOR;
+               //if (v & XHCI_PS_SUSP) i |= UPS_SUSPEND;
+               if (v & XHCI_PS_PR)     i |= UPS_RESET;
+               if (v & XHCI_PS_PP) {
+                       if (i & UPS_SUPER_SPEED)
+                                       i |= UPS_PORT_POWER_SS;
+                       else
+                                       i |= UPS_PORT_POWER;
+               }
+               USETW(ps.wPortStatus, i);
+               i = 0;
+               if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
+               if (v & XHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;
+               if (v & XHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;
+               if (v & XHCI_PS_PRC)    i |= UPS_C_PORT_RESET;
+               if (v & XHCI_PS_WRC)    i |= UPS_C_BH_PORT_RESET;
+               if (v & XHCI_PS_PLC)    i |= UPS_C_PORT_LINK_STATE;
+               if (v & XHCI_PS_CEC)    i |= UPS_C_PORT_CONFIG_ERROR;
+               USETW(ps.wPortChange, i);
+               l = min(len, sizeof ps);
+               memcpy(buf, &ps, l);
+               totlen = l;
+               break;
+       case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
+               err = USBD_IOERROR;
+               goto ret;
+       case C(UR_SET_HUB_DEPTH, UT_WRITE_CLASS_DEVICE):
+               break;
+       case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
+               break;
+       /* Hub Port request */
+       case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
+       {
+               int optval = (index >> 8) & 0xff;
+               index &= 0xff;
+               if (index < 1 || index > sc->sc_maxports) {
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+               port = XHCI_PORTSC(index);
+               v = xhci_op_read_4(sc, port);
+               DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
+               v &= ~XHCI_PS_CLEAR;
+               switch (value) {
+               case UHF_PORT_ENABLE:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_PED);
+                       break;
+               case UHF_PORT_SUSPEND:
+                       /* XXX suspend */
+                       break;
+               case UHF_PORT_RESET:
+                       v &= ~ (XHCI_PS_PED | XHCI_PS_PR);
+                       xhci_op_write_4(sc, port, v | XHCI_PS_PR);
+                       /* Wait for reset to complete. */
+                       usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
+                       if (sc->sc_dying) {
+                               err = USBD_IOERROR;
+                               goto ret;
+                       }
+                       v = xhci_op_read_4(sc, port);
+                       if (v & XHCI_PS_PR) {
+                               xhci_op_write_4(sc, port, v & ~XHCI_PS_PR);
+                               usb_delay_ms(&sc->sc_bus, 10);
+                               /* XXX */
+                       }
+                       break;
+               case UHF_PORT_POWER:
+                       /* XXX power control */
+                       break;
+               /* XXX more */
+               case UHF_C_PORT_RESET:
+                       xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
+                       break;
+               case UHF_PORT_U1_TIMEOUT:
+                       if (XHCI_PS_SPEED_GET(v) != 4) {
+                               err = USBD_IOERROR;
+                               goto ret;
+                       }
+                       port = XHCI_PORTPMSC(index);
+                       v = xhci_op_read_4(sc, port);
+                       v &= ~XHCI_PM3_U1TO_SET(0xff);
+                       v |= XHCI_PM3_U1TO_SET(optval);
+                       xhci_op_write_4(sc, port, v);
+                       break;
+               case UHF_PORT_U2_TIMEOUT:
+                       if (XHCI_PS_SPEED_GET(v) != 4) {
+                               err = USBD_IOERROR;
+                               goto ret;
+                       }
+                       port = XHCI_PORTPMSC(index);
+                       v = xhci_op_read_4(sc, port);
+                       v &= ~XHCI_PM3_U2TO_SET(0xff);
+                       v |= XHCI_PM3_U2TO_SET(optval);
+                       xhci_op_write_4(sc, port, v);
+                       break;
+               default:
+                       err = USBD_IOERROR;
+                       goto ret;
+               }
+
+               }
+               break;
+       case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
+       case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
+       case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER):
+       case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
+               break;
+       default:
+               err = USBD_IOERROR;
+               goto ret;
+       }
+       xfer->ux_actlen = totlen;
+       err = USBD_NORMAL_COMPLETION;
+ret:
+       xfer->ux_status = err;
+       mutex_enter(&sc->sc_lock);
+       usb_transfer_complete(xfer);
+       mutex_exit(&sc->sc_lock);
+       return USBD_IN_PROGRESS;
+}
+
+#else /* !NHUSB */
 /*
  * Process root hub request.
  */
@@ -2842,6 +3571,32 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
        return totlen;
 }
 
+#endif /* !NHUSB */
+#ifndef NHUSB
+static void
+xhci_root_ctrl_abort(struct usbd_xfer *xfer)
+{
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+       /* Nothing to do, all transfers are synchronous. */
+}
+
+
+static void
+xhci_root_ctrl_close(struct usbd_pipe *pipe)
+{
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+       /* Nothing to do. */
+}
+
+static void
+xhci_root_ctrl_done(struct usbd_xfer *xfer)
+{
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       xfer->ux_hcpriv = NULL;
+}
+
+#endif /* !NHUSB */
 /* root hub interrupt */
 
 static usbd_status
--- src/sys/dev/usb/uhub.c.orig 2015-03-27 15:05:01.000000000 +0900
+++ src/sys/dev/usb/uhub.c      2015-04-05 16:51:55.000000000 +0900
@@ -39,11 +39,13 @@
 __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.8 2015/03/21 11:33:37 skrll Exp 
$");
 
 #include <sys/param.h>
+
 #include <sys/systm.h>
+#include <sys/device.h>
 #include <sys/kernel.h>
 #include <sys/kmem.h>
-#include <sys/device.h>
 #include <sys/proc.h>
+#include <sys/sysctl.h>
 
 #include <sys/bus.h>
 
@@ -51,15 +53,48 @@ __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.1
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbdivar.h>
+#include <dev/usb/usbhist.h>
 
-#ifdef UHUB_DEBUG
-#define DPRINTF(x)     if (uhubdebug) printf x
-#define DPRINTFN(n,x)  if (uhubdebug>(n)) printf x
-int    uhubdebug = 0;
+#ifdef USB_DEBUG
+#ifndef UHUB_DEBUG
+#define uhubdebug 0
 #else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
-#endif
+static int uhubdebug = 0;
+
+SYSCTL_SETUP(sysctl_hw_uhub_setup, "sysctl hw.uhub setup")
+{
+       int err;
+       const struct sysctlnode *rnode;
+       const struct sysctlnode *cnode;
+
+       err = sysctl_createv(clog, 0, NULL, &rnode,
+           CTLFLAG_PERMANENT, CTLTYPE_NODE, "uhub",
+           SYSCTL_DESCR("uhub global controls"),
+           NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+
+       if (err)
+               goto fail;
+
+       /* control debugging printfs */
+       err = sysctl_createv(clog, 0, &rnode, &cnode,
+           CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
+           "debug", SYSCTL_DESCR("Enable debugging output"),
+           NULL, 0, &uhubdebug, sizeof(uhubdebug), CTL_CREATE, CTL_EOL);
+       if (err)
+               goto fail;
+
+       return;
+fail:
+       aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
+}
+
+#endif /* UHUB_DEBUG */
+#endif /* USB_DEBUG */
+
+#define DPRINTF(FMT,A,B,C,D)   USBHIST_LOGN(uhubdebug,1,FMT,A,B,C,D)
+#define DPRINTFN(N,FMT,A,B,C,D)        USBHIST_LOGN(uhubdebug,N,FMT,A,B,C,D)
+#define UHUBHIST_FUNC() USBHIST_FUNC()
+#define UHUBHIST_CALLED(name) USBHIST_CALLED(uhubdebug)
 
 struct uhub_softc {
        device_t                sc_dev;         /* base device */
@@ -118,12 +153,14 @@ uhub_match(device_t parent, cfdata_t mat
        struct usb_attach_arg *uaa = aux;
        int matchvalue;
 
+       UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
        if (uhub_ubermatch)
                matchvalue = UMATCH_HIGHEST+1;
        else
                matchvalue = UMATCH_DEVCLASS_DEVSUBCLASS;
 
-       DPRINTFN(5,("uhub_match, uaa=%p\n", uaa));
+       DPRINTFN(5, "uaa=%p", uaa, 0, 0, 0);
        /*
         * The subclass for hubs seems to be 0 for some and 1 for others,
         * so we just ignore the subclass.
@@ -151,7 +188,8 @@ uhub_attach(device_t parent, device_t se
        struct usbd_tt *tts = NULL;
 #endif
 
-       DPRINTFN(1,("uhub_attach\n"));
+       UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
        sc->sc_dev = self;
        sc->sc_hub = dev;
        sc->sc_proto = uaa->uaa_proto;
@@ -169,8 +207,7 @@ uhub_attach(device_t parent, device_t se
 
        err = usbd_set_config_index(dev, 0, 1);
        if (err) {
-               DPRINTF(("%s: configuration failed, error=%s\n",
-                   device_xname(sc->sc_dev), usbd_errstr(err)));
+               DPRINTF("configuration failed, sc %p error %d", sc, err, 0, 0);
                return;
        }
 
@@ -187,7 +224,7 @@ uhub_attach(device_t parent, device_t se
        USETW2(req.wValue, UDESC_HUB, 0);
        USETW(req.wIndex, 0);
        USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
-       DPRINTFN(1,("%s: getting hub descriptor\n", __func__));
+       DPRINTF("uhub %d getting hub descriptor", device_unit(self), 0, 0, 0);
        err = usbd_do_request(dev, &req, &hubdesc);
        nports = hubdesc.bNbrPorts;
        if (!err && nports > 7) {
@@ -195,8 +232,8 @@ uhub_attach(device_t parent, device_t se
                err = usbd_do_request(dev, &req, &hubdesc);
        }
        if (err) {
-               DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
-                   device_xname(sc->sc_dev), usbd_errstr(err)));
+               DPRINTF("getting hub descriptor failed, uhub %d error %d",
+                   device_unit(self), err, 0, 0);
                return;
        }
 
@@ -338,7 +375,8 @@ uhub_attach(device_t parent, device_t se
                if (err)
                        aprint_error_dev(self, "port %d power on failed, %s\n",
                            port, usbd_errstr(err));
-               DPRINTF(("usb_init_port: turn on port %d power\n", port));
+               DPRINTF("uhub %d turn on port %d power", device_unit(self),
+                   port, 0, 0);
        }
 
        /* Wait for stable power if we are not a root hub */
@@ -377,7 +415,10 @@ uhub_explore(struct usbd_device *dev)
        int port;
        int change, status, reconnect;
 
-       DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->ud_addr));
+       UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+       DPRINTFN(10, "uhub %d dev=%p addr=%d speed=%u",
+           device_unit(sc->sc_dev), dev, dev->ud_addr, dev->ud_speed);
 
        if (!sc->sc_running)
                return USBD_NOT_STARTED;
@@ -391,12 +432,15 @@ uhub_explore(struct usbd_device *dev)
 
                err = usbd_get_hub_status(dev, &hs);
                if (err) {
-                       DPRINTF(("%s: get hub status failed, err=%d\n",
-                                device_xname(sc->sc_dev), err));
+                       DPRINTF("uhub %d get hub status failed, err %d",
+                           device_unit(sc->sc_dev), err, 0, 0);
                } else {
                        /* just acknowledge */
                        status = UGETW(hs.wHubStatus);
                        change = UGETW(hs.wHubChange);
+                       DPRINTF("uhub %d s/c=%x/%x", device_unit(sc->sc_dev),
+                           status, change, 0);
+
                        if (change & UHS_LOCAL_POWER)
                                usbd_clear_hub_feature(dev,
                                                       UHF_C_HUB_LOCAL_POWER);
@@ -419,16 +463,15 @@ uhub_explore(struct usbd_device *dev)
                if (PORTSTAT_ISSET(sc, port) || reconnect) {
                        err = usbd_get_port_status(dev, port, &up->up_status);
                        if (err) {
-                               DPRINTF(("uhub_explore: get port stat failed, "
-                                        "error=%s\n", usbd_errstr(err)));
+                               DPRINTF("uhub %d get port stat failed, err %d",
+                                   device_unit(sc->sc_dev), err, 0, 0);
                                continue;
                        }
                        status = UGETW(up->up_status.wPortStatus);
                        change = UGETW(up->up_status.wPortChange);
-#if 0
-                       printf("%s port %d: s/c=%x/%x\n",
-                              device_xname(sc->sc_dev), port, status, change);
-#endif
+
+                       DPRINTF("uhub %d port %d: s/c=%x/%x",
+                           device_unit(sc->sc_dev), port, status, change);
                }
                if (!change && !reconnect) {
                        /* No status change, just do recursive explore. */
@@ -438,7 +481,8 @@ uhub_explore(struct usbd_device *dev)
                }
 
                if (change & UPS_C_PORT_ENABLED) {
-                       DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
+                       DPRINTF("uhub %d port %d C_PORT_ENABLED",
+                           device_unit(sc->sc_dev), port, 0, 0);
                        usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
                        if (change & UPS_C_CONNECT_STATUS) {
                                /* Ignore the port error if the device
@@ -473,8 +517,8 @@ uhub_explore(struct usbd_device *dev)
 
                /* We have a connect status change, handle it. */
 
-               DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
-                        dev->ud_addr, port));
+               DPRINTF("status change hub=%d port=%d", dev->ud_addr, port, 0,
+                   0);
                usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
                /*
                 * If there is already a device on the port the change status
@@ -486,20 +530,23 @@ uhub_explore(struct usbd_device *dev)
        disco:
                if (up->up_dev != NULL) {
                        /* Disconnected */
-                       DPRINTF(("uhub_explore: device addr=%d disappeared "
-                                "on port %d\n", up->up_dev->ud_addr, port));
+                       DPRINTF("uhub %d device addr=%d disappeared on port %d",
+                           device_unit(sc->sc_dev), up->up_dev->ud_addr, port,
+                           0);
                        usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
                        usbd_clear_port_feature(dev, port,
                                                UHF_C_PORT_CONNECTION);
                }
                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
                        /* Nothing connected, just ignore it. */
-                       DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
-                                   "_STATUS\n", port));
+                       DPRINTFN(3, "uhub %d port=%d !CURRENT_CONNECT_STATUS",
+                           device_unit(sc->sc_dev), port, 0, 0);
                        continue;
                }
 
                /* Connected */
+               DPRINTF("unit %d dev->ud_speed=%u dev->ud_depth=%u",
+                   device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);
 
                if (!(status & UPS_PORT_POWER))
                        aprint_normal_dev(sc->sc_dev,
@@ -517,12 +564,15 @@ uhub_explore(struct usbd_device *dev)
                /* Get port status again, it might have changed during reset */
                err = usbd_get_port_status(dev, port, &up->up_status);
                if (err) {
-                       DPRINTF(("uhub_explore: get port status failed, "
-                                "error=%s\n", usbd_errstr(err)));
+                       DPRINTF("uhub %d port=%d get port status failed, "
+                           "err %d", device_unit(sc->sc_dev), port, err, 0);
                        continue;
                }
                status = UGETW(up->up_status.wPortStatus);
                change = UGETW(up->up_status.wPortChange);
+               DPRINTF("hub %d port %d reset: s/c=%x/%x",
+                      device_unit(sc->sc_dev), port, status, change);
+
                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
                        /* Nothing connected, just ignore it. */
 #ifdef DIAGNOSTIC
@@ -557,8 +607,8 @@ uhub_explore(struct usbd_device *dev)
                          dev->ud_depth + 1, speed, port, up);
                /* XXX retry a few times? */
                if (err) {
-                       DPRINTFN(-1,("uhub_explore: usbd_new_device failed, "
-                                    "error=%s\n", usbd_errstr(err)));
+                       DPRINTF("usbd_new_device failed, error %d", err, 0, 0,
+                           0);
                        /* Avoid addressing problems by disabling. */
                        /* usbd_reset_port(dev, port, &up->status); */
 
@@ -597,7 +647,9 @@ uhub_detach(device_t self, int flags)
        struct usbd_port *rup;
        int nports, port, rc;
 
-       DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
+       UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+       DPRINTF("uhub %d sc=%p flags=%d", device_unit(self), sc, flags, 0);
 
        if (hub == NULL)                /* Must be partially working */
                return 0;
@@ -708,7 +760,9 @@ uhub_intr(struct usbd_xfer *xfer, void *
 {
        struct uhub_softc *sc = addr;
 
-       DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
+       UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+       DPRINTFN(5, "uhub %d sc=%p", device_unit(sc->sc_dev), sc, 0, 0);
 
        if (status == USBD_STALLED)
                usbd_clear_endpoint_stall_async(sc->sc_ipipe);
--- ../nick-nhusb/src/sys/dev/usb/uhub.c.orig   2015-04-05 16:51:55.000000000 
+0900
+++ ../nick-nhusb/src/sys/dev/usb/uhub.c        2015-04-05 17:21:44.000000000 
+0900
@@ -108,11 +108,13 @@ struct uhub_softc {
        size_t                  sc_statuslen;
        int                     sc_explorepending;
        int             sc_isehciroothub; /* see comment in uhub_intr() */
+       int             sc_isxhciroothub;
 
        u_char                  sc_running;
 };
 
-#define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
+#define UHUB_IS_HIGH_SPEED(sc) \
+    ((sc)->sc_proto == UDPROTO_HSHUBSTT || (sc)->sc_proto == UDPROTO_HSHUBMTT)
 #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
 
 #define PORTSTAT_ISSET(sc, port) \
@@ -147,6 +149,76 @@ CFATTACH_DECL2_NEW(uroothub, sizeof(stru
  */
 int uhub_ubermatch = 0;
 
+static usbd_status
+usbd_get_hub_desc(struct usbd_device *dev, usb_hub_descriptor_t *hd, int speed)
+{
+       usb_device_request_t req;
+       usbd_status err;
+       int nports;
+
+       UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+       /* don't issue UDESC_HUB to SS hub, or it would stall */
+       if (dev->ud_depth != 0 && dev->ud_speed == USB_SPEED_SUPER) {
+               usb_hub_ss_descriptor_t hssd;
+               int rmvlen;
+
+               memset(&hssd, 0, sizeof(hssd));
+               req.bmRequestType = UT_READ_CLASS_DEVICE;
+               req.bRequest = UR_GET_DESCRIPTOR;
+               USETW2(req.wValue, UDESC_SS_HUB, 0);
+               USETW(req.wIndex, 0);
+               USETW(req.wLength, USB_HUB_SS_DESCRIPTOR_SIZE);
+               DPRINTFN(1, "getting sshub descriptor", 0, 0, 0, 0);
+               err = usbd_do_request(dev, &req, &hssd);
+               nports = hssd.bNbrPorts;
+               if (dev->ud_depth != 0 && nports > UHD_SS_NPORTS_MAX) {
+                       DPRINTF("num of ports %d exceeds maxports %d",
+                           nports, UHD_SS_NPORTS_MAX, 0, 0);
+                       nports = hd->bNbrPorts = UHD_SS_NPORTS_MAX;
+               }
+               rmvlen = (nports + 7) / 8;
+               hd->bDescLength = USB_HUB_DESCRIPTOR_SIZE +
+                   (rmvlen > 1 ? rmvlen : 1) - 1;
+               memcpy(hd->DeviceRemovable, hssd.DeviceRemovable, rmvlen);
+               hd->bDescriptorType             = hssd.bDescriptorType;
+               hd->bNbrPorts                   = hssd.bNbrPorts;
+               hd->wHubCharacteristics[0]      = hssd.wHubCharacteristics[0];
+               hd->wHubCharacteristics[1]      = hssd.wHubCharacteristics[1];
+               hd->bPwrOn2PwrGood              = hssd.bPwrOn2PwrGood;
+               hd->bHubContrCurrent            = hssd.bHubContrCurrent;
+       } else {
+               req.bmRequestType = UT_READ_CLASS_DEVICE;
+               req.bRequest = UR_GET_DESCRIPTOR;
+               USETW2(req.wValue, UDESC_HUB, 0);
+               USETW(req.wIndex, 0);
+               USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
+               DPRINTFN(1, "getting hub descriptor", 0, 0, 0, 0);
+               err = usbd_do_request(dev, &req, hd);
+               nports = hd->bNbrPorts;
+               if (!err && nports > 7) {
+                       USETW(req.wLength,
+                           USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
+                       err = usbd_do_request(dev, &req, hd);
+               }
+       }
+
+       return err;
+}
+
+static usbd_status
+usbd_set_hub_depth(struct usbd_device *dev, int depth)
+{
+       usb_device_request_t req;
+
+       req.bmRequestType = UT_WRITE_CLASS_DEVICE;
+       req.bRequest = UR_SET_HUB_DEPTH;
+       USETW(req.wValue, depth);
+       USETW(req.wIndex, 0);
+       USETW(req.wLength, 0);
+       return usbd_do_request(dev, &req, 0);
+}
+
 int
 uhub_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -179,7 +251,6 @@ uhub_attach(device_t parent, device_t se
        char *devinfop;
        usbd_status err;
        struct usbd_hub *hub = NULL;
-       usb_device_request_t req;
        usb_hub_descriptor_t hubdesc;
        int p, port, nports, nremov, pwrdly;
        struct usbd_interface *iface;
@@ -219,18 +290,9 @@ uhub_attach(device_t parent, device_t se
        }
 
        /* Get hub descriptor. */
-       req.bmRequestType = UT_READ_CLASS_DEVICE;
-       req.bRequest = UR_GET_DESCRIPTOR;
-       USETW2(req.wValue, UDESC_HUB, 0);
-       USETW(req.wIndex, 0);
-       USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
-       DPRINTF("uhub %d getting hub descriptor", device_unit(self), 0, 0, 0);
-       err = usbd_do_request(dev, &req, &hubdesc);
+       memset(&hubdesc, 0, sizeof(hubdesc));
+       err = usbd_get_hub_desc(dev, &hubdesc, dev->ud_speed);
        nports = hubdesc.bNbrPorts;
-       if (!err && nports > 7) {
-               USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
-               err = usbd_do_request(dev, &req, &hubdesc);
-       }
        if (err) {
                DPRINTF("getting hub descriptor failed, uhub %d error %d",
                    device_unit(self), err, 0, 0);
@@ -258,6 +320,16 @@ uhub_attach(device_t parent, device_t se
        hub->uh_explore = uhub_explore;
        hub->uh_hubdesc = hubdesc;
 
+       if (dev->ud_speed == USB_SPEED_SUPER && dev->ud_depth != 0) {
+               aprint_debug_dev(self, "setting hub depth %u\n",
+                   dev->ud_depth-1);
+               err = usbd_set_hub_depth(dev, dev->ud_depth - 1);
+               if (err) {
+                       aprint_error_dev(self, "can't set depth\n");
+                       goto bad;
+               }
+       }
+
        /* Set up interrupt pipe. */
        err = usbd_device2interface_handle(dev, 0, &iface);
        if (err) {
@@ -290,6 +362,8 @@ uhub_attach(device_t parent, device_t se
                goto bad;
        if (device_is_a(device_parent(device_parent(sc->sc_dev)), "ehci"))
                sc->sc_isehciroothub = 1;
+       if (device_is_a(device_parent(device_parent(sc->sc_dev)), "xhci"))
+               sc->sc_isxhciroothub = 1;
 
        /* force initial scan */
        memset(sc->sc_status, 0xff, sc->sc_statuslen);
@@ -317,9 +391,10 @@ uhub_attach(device_t parent, device_t se
         * These are the events on the bus when a hub is attached:
         *  Get device and config descriptors (see attach code)
         *  Get hub descriptor (see above)
+        *  Set hub depth (if super speed)
         *  For all ports
         *     turn on power
-        *     wait for power to become stable
+        *  Wait for power to become stable
         * (all below happens in explore code)
         *  For all ports
         *     clear C_PORT_CONNECTION
@@ -505,6 +580,19 @@ uhub_explore(struct usbd_device *dev)
                                            port);
                        }
                }
+#if 1
+               if (change & UPS_C_PORT_RESET)
+                       usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
+#endif
+               if (change & UPS_C_BH_PORT_RESET)
+                       usbd_clear_port_feature(dev, port,
+                           UHF_C_BH_PORT_RESET);
+               if (change & UPS_C_PORT_LINK_STATE)
+                       usbd_clear_port_feature(dev, port,
+                           UHF_C_PORT_LINK_STATE);
+               if (change & UPS_C_PORT_CONFIG_ERROR)
+                       usbd_clear_port_feature(dev, port,
+                           UHF_C_PORT_CONFIG_ERROR);
 
                /* XXX handle overcurrent and resume events! */
 
@@ -548,7 +636,14 @@ uhub_explore(struct usbd_device *dev)
                DPRINTF("unit %d dev->ud_speed=%u dev->ud_depth=%u",
                    device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);
 
-               if (!(status & UPS_PORT_POWER))
+               if ((!(status & UPS_PORT_POWER) &&
+                   /* check POWER for root/non-root hub if non-SS */
+                   ((dev->ud_depth == 0 && !(status & UPS_SUPER_SPEED)) ||
+                   (dev->ud_depth != 0 && dev->ud_speed != USB_SPEED_SUPER)))||
+                   /* check POWER_SS for root/non-root hub if SS */
+                   (!(status & UPS_PORT_POWER_SS) &&
+                   ((dev->ud_depth == 0 && (status & UPS_SUPER_SPEED)) ||
+                    (dev->ud_depth != 0 && dev->ud_speed == USB_SPEED_SUPER))))
                        aprint_normal_dev(sc->sc_dev,
                            "strange, connected port %d has no power\n", port);
 
@@ -591,8 +686,9 @@ uhub_explore(struct usbd_device *dev)
                }
 
                /* Figure out device speed */
-#if 0
-               if (status & UPS_SUPER_SPEED)
+#if 1
+               if ((status & UPS_SUPER_SPEED) ||
+                   (dev->ud_speed == USB_SPEED_SUPER && dev->ud_depth != 0))
                        speed = USB_SPEED_SUPER;
                else
 #endif
@@ -602,6 +698,8 @@ uhub_explore(struct usbd_device *dev)
                        speed = USB_SPEED_LOW;
                else
                        speed = USB_SPEED_FULL;
+               DPRINTF("unit %d: speed %u\n", device_unit(sc->sc_dev), speed,
+                   0, 0);
                /* Get device info and set its address. */
                err = usbd_new_device(sc->sc_dev, dev->ud_bus,
                          dev->ud_depth + 1, speed, port, up);
@@ -629,7 +727,7 @@ uhub_explore(struct usbd_device *dev)
                }
        }
        /* enable status change notifications again */
-       if (!sc->sc_isehciroothub)
+       if (!sc->sc_isehciroothub && !sc->sc_isxhciroothub)
                memset(sc->sc_status, 0, sc->sc_statuslen);
        sc->sc_explorepending = 0;
        return USBD_NORMAL_COMPLETION;
@@ -785,4 +883,12 @@ uhub_intr(struct usbd_xfer *xfer, void *
        if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
            sc->sc_isehciroothub)
                usb_needs_explore(sc->sc_hub);
+       /* 
+        * XXX force re-scan all ports of xhci root hub
+        */
+       if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
+           sc->sc_isxhciroothub) {
+               memset(sc->sc_status, 0xff, sc->sc_statuslen);
+               usb_needs_explore(sc->sc_hub);
+       }
 }
--- src/sys/dev/usb/usb.h.orig  2014-12-04 07:43:25.000000000 +0900
+++ src/sys/dev/usb/usb.h       2014-12-04 08:54:56.000000000 +0900
@@ -244,6 +247,7 @@ typedef struct {
 #define UC_REMOTE_WAKEUP       0x20
        uByte           bMaxPower; /* max current in 2 mA units */
 #define UC_POWER_FACTOR 2
+#define UC_POWER_FACTOR_SS 8
 } UPACKED usb_config_descriptor_t;
 #define USB_CONFIG_DESCRIPTOR_SIZE 9
 
@@ -301,6 +305,7 @@ typedef struct {
 } UPACKED usb_endpoint_descriptor_t;
 #define USB_ENDPOINT_DESCRIPTOR_SIZE 7
 
+/* USB 3.0 9.6.2, Table 9-12 */
 typedef struct {
        uByte           bLength;
        uByte           bDescriptorType;
@@ -314,6 +319,7 @@ typedef struct {
 } UPACKED usb_endpoint_ss_comp_descriptor_t;
 #define USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE 6
 
+/* USB 3.0 9.6.2, Table 9-12 */
 typedef struct {
        uByte           bLength;
        uByte           bDescriptorType;
@@ -322,10 +328,12 @@ typedef struct {
 } UPACKED usb_bos_descriptor_t;
 #define USB_BOS_DESCRIPTOR_SIZE 5
 
+/* common members of device capability descriptors */
 typedef struct {
        uByte           bLength;
        uByte           bDescriptorType;
        uByte           bDevCapabilityType;
+/* Table 9-14 */
 #define USB_DEVCAP_RESERVED                    0x00
 #define USB_DEVCAP_WUSB                                0x01
 #define USB_DEVCAP_USB2EXT                     0x02
@@ -341,17 +349,19 @@ typedef struct {
 #define USB_DEVCAP_WUSB_EXT                    0x0c
        /* data ... */
 } UPACKED usb_device_capability_descriptor_t;
-#define USB_DEVICE_CAPABILITY_DESCRIPTOR_SIZE 3 /* variable length */
+#define USB_DEVICE_CAPABILITY_DESCRIPTOR_SIZE 3 /* at least */
 
+/* 9.6.2.1 */
 typedef struct {
        uByte           bLength;
        uByte           bDescriptorType;
        uByte           bDevCapabilityType;
        uDWord          bmAttributes;
 #define USB_DEVCAP_USB2EXT_LPM __BIT(1)
-} UPACKED usb_usb2ext_descriptor_t;
+} UPACKED usb_devcap_usb2ext_descriptor_t;
 #define USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE 7
 
+/* 9.6.2.2 */
 typedef struct {
        uByte           bLength;
        uByte           bDescriptorType;
@@ -359,16 +369,17 @@ typedef struct {
        uByte           bmAttributes;
 #define USB_DEVCAP_SS_LTM __BIT(1)
        uWord           wSpeedsSupported;
-#define USB_DEVCAP_SS_SPEED_SS __BIT(0)
+#define USB_DEVCAP_SS_SPEED_LS __BIT(0)
 #define USB_DEVCAP_SS_SPEED_FS __BIT(1)
 #define USB_DEVCAP_SS_SPEED_HS __BIT(2)
-#define USB_DEVCAP_SS_SPEED_LS __BIT(3)
+#define USB_DEVCAP_SS_SPEED_SS __BIT(3)
        uByte           bFunctionalitySupport;
        uByte           bU1DevExitLat;
        uWord           wU2DevExitLat;
 } UPACKED usb_devcap_ss_descriptor_t;
 #define USB_DEVCAP_SS_DESCRIPTOR_SIZE 10
 
+/* 9.6.2.4 */
 typedef struct {
        uByte           bLength;
        uByte           bDescriptorType;
@@ -733,7 +744,9 @@ typedef struct {
 #endif
 
 #define USB_MIN_POWER          100 /* mA */
+#define USB_MIN_POWER_SS       150 /* mA */
 #define USB_MAX_POWER          500 /* mA */
+#define USB_MAX_POWER_SS       900 /* mA */
 
 #define USB_BUS_RESET_DELAY    100 /* ms XXX?*/
 
--- src/sys/dev/usb/usb_subr.c.orig     2015-03-27 15:05:02.000000000 +0900
+++ src/sys/dev/usb/usb_subr.c  2015-03-27 15:11:01.000000000 +0900
@@ -1411,6 +1411,13 @@ usbd_fill_deviceinfo(struct usbd_device 
                                        err = USB_PORT_ENABLED;
                                else if (s & UPS_SUSPEND)
                                        err = USB_PORT_SUSPENDED;
+                               /*
+                                * UPS_PORT_POWER_SS is available only
+                                * if SS, otherwise it means UPS_LOW_SPEED.
+                                */
+                               else if ((s & UPS_PORT_POWER_SS) &&
+                                   dev->ud_speed == USB_SPEED_SUPER)
+                                       err = USB_PORT_POWERED;
                                else if (s & UPS_PORT_POWER)
                                        err = USB_PORT_POWERED;
                                else
--- src/sys/dev/usb/xhcireg.h.orig      2014-11-18 21:02:04.000000000 +0900
+++ src/sys/dev/usb/xhcireg.h   2015-04-05 09:01:54.000000000 +0900
@@ -38,6 +38,16 @@
 #define         PCI_USBREV_3_0         0x30    /* USB 3.0 */
 #define        PCI_XHCI_FLADJ          0x61    /* RW frame length adjust */
 
+#define        PCI_XHCI_INTEL_XUSB2PR  0xD0    /* Intel USB2 Port Routing */
+#define        PCI_XHCI_INTEL_USB2PRM  0xD4    /* Intel USB2 Port Routing Mask 
*/
+#define        PCI_XHCI_INTEL_USB3_PSSEN 0xD8  /* Intel USB3 Port SuperSpeed 
Enable */
+#define        PCI_XHCI_INTEL_USB3PRM  0xDC    /* Intel USB3 Port Routing Mask 
*/
+
+#define        PCI_XHCI_INTEL_XUSB2PR  0xD0    /* Intel USB2 Port Routing */
+#define        PCI_XHCI_INTEL_USB2PRM  0xD4    /* Intel USB2 Port Routing Mask 
*/
+#define        PCI_XHCI_INTEL_USB3_PSSEN 0xD8  /* Intel USB3 Port SuperSpeed 
Enable */
+#define        PCI_XHCI_INTEL_USB3PRM  0xDC    /* Intel USB3 Port Routing Mask 
*/
+
 /* XHCI capability registers */
 #define XHCI_CAPLENGTH         0x00    /* RO capability */
 #define        XHCI_CAP_CAPLENGTH(x)   ((x) & 0xFF)
@@ -168,6 +178,7 @@
 #define        XHCI_IMOD_ICNT_GET(x)   (((x) >> 16) & 0xFFFF)  /* 250ns unit */
 #define        XHCI_IMOD_ICNT_SET(x)   (((x) & 0xFFFF) << 16)  /* 250ns unit */
 #define        XHCI_IMOD_DEFAULT       0x000001F4U     /* 8000 IRQ/second */
+#define        XHCI_IMOD_DEFAULT_LP    0x000003E8U     /* 4000 IRQ/sec for 
LynxPoint */
 #define        XHCI_ERSTSZ(n)          (0x0028 + (0x20 * (n))) /* XHCI event 
ring segment table size */
 #define        XHCI_ERSTS_GET(x)       ((x) & 0xFFFF)
 #define        XHCI_ERSTS_SET(x)       ((x) & 0xFFFF)
@@ -188,18 +199,20 @@
 /* XHCI legacy support */
 #define        XHCI_XECP_ID(x)         ((x) & 0xFF)
 #define        XHCI_XECP_NEXT(x)       (((x) >> 8) & 0xFF)
-#if 0
 #define        XHCI_XECP_BIOS_SEM      0x0002
 #define        XHCI_XECP_OS_SEM        0x0003
-#endif
 
-/* XHCI capability ID's */
-#define        XHCI_ID_USB_LEGACY      0x0001
-#define        XHCI_ID_PROTOCOLS       0x0002
-#define        XHCI_ID_POWER_MGMT      0x0003
-#define        XHCI_ID_VIRTUALIZATION  0x0004
-#define        XHCI_ID_MSG_IRQ         0x0005
-#define        XHCI_ID_USB_LOCAL_MEM   0x0006
+/* XHCI extended capability ID's */
+#define        XHCI_ID_USB_LEGACY      0x0001  /* USB Legacy Support */
+#define         XHCI_XECP_USBLESUP     0x0000  /* Legacy Support Capability 
Reg */
+#define         XHCI_XECP_USBLEGCTLSTS 0x0004  /* Legacy Support Ctrl & Status 
Reg */
+#define        XHCI_ID_PROTOCOLS       0x0002  /* Supported Protocol */
+#define        XHCI_ID_POWER_MGMT      0x0003  /* Extended Power Management */
+#define        XHCI_ID_VIRTUALIZATION  0x0004  /* I/O Virtualization */
+#define        XHCI_ID_MSG_IRQ         0x0005  /* Message Interrupt */
+#define        XHCI_ID_USB_LOCAL_MEM   0x0006  /* Local Memory */
+#define        XHCI_ID_USB_DEBUG       0x000A  /* USB Debug Capability */
+#define        XHCI_ID_XMSG_IRQ        0x0011  /* Extended Message Interrupt */
 
 #define XHCI_PAGE_SIZE(sc) ((sc)->sc_pgsz)
 
@@ -266,6 +279,8 @@ struct xhci_trb {
 #define XHCI_TRB_3_FRID_SET(x)          (((x) & 0x7FF) << 20)
 #define XHCI_TRB_3_ISO_SIA_BIT          (1U << 31)
 #define XHCI_TRB_3_SUSP_EP_BIT          (1U << 23)
+#define XHCI_TRB_3_VFID_GET(x)          (((x) >> 16) & 0xFF)
+#define XHCI_TRB_3_VFID_SET(x)          (((x) & 0xFF) << 16)
 #define XHCI_TRB_3_SLOT_GET(x)          (((x) >> 24) & 0xFF)
 #define XHCI_TRB_3_SLOT_SET(x)          (((x) & 0xFF) << 24)
 
@@ -375,10 +390,20 @@ struct xhci_trb {
 #define XHCI_SCTX_3_DEV_ADDR_GET(x)             ((x) & 0xFF)
 #define XHCI_SCTX_3_SLOT_STATE_SET(x)           (((x) & 0x1F) << 27)
 #define XHCI_SCTX_3_SLOT_STATE_GET(x)           (((x) >> 27) & 0x1F)
+#define XHCI_SLOTSTATE_DISABLED                        0 /* disabled or 
enabled */
+#define XHCI_SLOTSTATE_ENABLED                 0
+#define XHCI_SLOTSTATE_DEFAULT                 1
+#define XHCI_SLOTSTATE_ADDRESSED               2
+#define XHCI_SLOTSTATE_CONFIGURED              3
 
 
 #define XHCI_EPCTX_0_EPSTATE_SET(x)             ((x) & 0x7)
 #define XHCI_EPCTX_0_EPSTATE_GET(x)             ((x) & 0x7)
+#define XHCI_EPSTATE_DISABLED                  0
+#define XHCI_EPSTATE_RUNNING                   1
+#define XHCI_EPSTATE_HALTED                    2
+#define XHCI_EPSTATE_STOPPED                   3
+#define XHCI_EPSTATE_ERROR                     4
 #define XHCI_EPCTX_0_MULT_SET(x)                (((x) & 0x3) << 8)
 #define XHCI_EPCTX_0_MULT_GET(x)                (((x) >> 8) & 0x3)
 #define XHCI_EPCTX_0_MAXP_STREAMS_SET(x)        (((x) & 0x1F) << 10)
--- src/sys/dev/usb/xhcivar.h.orig      2015-03-27 15:05:03.000000000 +0900
+++ src/sys/dev/usb/xhcivar.h   2015-03-27 15:53:58.000000000 +0900
@@ -109,6 +109,10 @@ struct xhci_softc {
 
        bool sc_ac64;
        bool sc_dying;
+
+       int sc_quirks;
+#define XHCI_QUIRK_FORCE_INTR  __BIT(0) /* force interrupt reading */
+#define XHCI_QUIRK_INTEL       __BIT(1) /* Intel xhci chip */
 };
 
 int    xhci_init(struct xhci_softc *);

Reply via email to