tech-kern archive

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

xhci patch for nick-nhusb branch



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 *);


Home | Main Index | Thread Index | Old Index