Module Name:    src
Committed By:   skrll
Date:           Thu Jan 19 16:05:00 UTC 2017

Modified Files:
        src/sys/dev/pci: xhci_pci.c
        src/sys/dev/usb: usb.c usb.h usb_subr.c usbdivar.h xhci.c xhcireg.h
            xhcivar.h

Log Message:
Pull across xhci(4) improvemnts from nick-nhusb


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/pci/xhci_pci.c
cvs rdiff -u -r1.164 -r1.165 src/sys/dev/usb/usb.c
cvs rdiff -u -r1.114 -r1.115 src/sys/dev/usb/usb.h
cvs rdiff -u -r1.217 -r1.218 src/sys/dev/usb/usb_subr.c
cvs rdiff -u -r1.113 -r1.114 src/sys/dev/usb/usbdivar.h
cvs rdiff -u -r1.67 -r1.68 src/sys/dev/usb/xhci.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/usb/xhcireg.h
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/usb/xhcivar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/xhci_pci.c
diff -u src/sys/dev/pci/xhci_pci.c:1.7 src/sys/dev/pci/xhci_pci.c:1.8
--- src/sys/dev/pci/xhci_pci.c:1.7	Thu Oct 13 20:05:06 2016
+++ src/sys/dev/pci/xhci_pci.c	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhci_pci.c,v 1.7 2016/10/13 20:05:06 jdolecek Exp $	*/
+/*	$NetBSD: xhci_pci.c,v 1.8 2017/01/19 16:05:00 skrll Exp $	*/
 /*	OpenBSD: xhci_pci.c,v 1.4 2014/07/12 17:38:51 yuo Exp	*/
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v 1.7 2016/10/13 20:05:06 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v 1.8 2017/01/19 16:05:00 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -126,7 +126,6 @@ xhci_pci_attach(device_t parent, device_
 	char intrbuf[PCI_INTRSTR_LEN];
 
 	sc->sc_dev = self;
-	sc->sc_bus.ub_hcpriv = sc;
 
 	pci_aprint_devinfo(pa, "USB Controller");
 
@@ -219,8 +218,11 @@ xhci_pci_attach(device_t parent, device_
 	                          xhci_shutdown))
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
-	/* Attach usb device. */
+	/* Attach usb buses. */
 	sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint);
+
+ 	sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint);
+
 	return;
 
 fail:

Index: src/sys/dev/usb/usb.c
diff -u src/sys/dev/usb/usb.c:1.164 src/sys/dev/usb/usb.c:1.165
--- src/sys/dev/usb/usb.c:1.164	Sun Aug 14 14:42:22 2016
+++ src/sys/dev/usb/usb.c	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb.c,v 1.164 2016/08/14 14:42:22 skrll Exp $	*/
+/*	$NetBSD: usb.c,v 1.165 2017/01/19 16:05:00 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2002, 2008, 2012 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.164 2016/08/14 14:42:22 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.165 2017/01/19 16:05:00 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -727,8 +727,12 @@ usbioctl(dev_t devt, u_long cmd, void *d
 			error = EINVAL;
 			goto fail;
 		}
-		if (addr < 0 || addr >= USB_MAX_DEVICES ||
-		    sc->sc_bus->ub_devices[addr] == NULL) {
+		if (addr < 0 || addr >= USB_MAX_DEVICES) {
+			error = EINVAL;
+			goto fail;
+		}
+		size_t dindex = usb_addr2dindex(addr);
+		if (sc->sc_bus->ub_devices[dindex] == NULL) {
 			error = EINVAL;
 			goto fail;
 		}
@@ -750,7 +754,7 @@ usbioctl(dev_t devt, u_long cmd, void *d
 					goto ret;
 			}
 		}
-		err = usbd_do_request_flags(sc->sc_bus->ub_devices[addr],
+		err = usbd_do_request_flags(sc->sc_bus->ub_devices[dindex],
 			  &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen,
 			  USBD_DEFAULT_TIMEOUT);
 		if (err) {
@@ -783,7 +787,8 @@ usbioctl(dev_t devt, u_long cmd, void *d
 			error = EINVAL;
 			goto fail;
 		}
-		if ((dev = sc->sc_bus->ub_devices[addr]) == NULL) {
+		size_t dindex = usb_addr2dindex(addr);
+		if ((dev = sc->sc_bus->ub_devices[dindex]) == NULL) {
 			error = ENXIO;
 			goto fail;
 		}
@@ -802,7 +807,8 @@ usbioctl(dev_t devt, u_long cmd, void *d
 			error = EINVAL;
 			goto fail;
 		}
-		if ((dev = sc->sc_bus->ub_devices[addr]) == NULL) {
+		size_t dindex = usb_addr2dindex(addr);
+		if ((dev = sc->sc_bus->ub_devices[dindex]) == NULL) {
 			error = ENXIO;
 			goto fail;
 		}

Index: src/sys/dev/usb/usb.h
diff -u src/sys/dev/usb/usb.h:1.114 src/sys/dev/usb/usb.h:1.115
--- src/sys/dev/usb/usb.h:1.114	Sat Sep 17 06:29:50 2016
+++ src/sys/dev/usb/usb.h	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb.h,v 1.114 2016/09/17 06:29:50 skrll Exp $	*/
+/*	$NetBSD: usb.h,v 1.115 2017/01/19 16:05:00 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -53,9 +53,9 @@
 
 #define USB_STACK_VERSION 2
 
-#define USB_MAX_DEVICES 128
-#define USB_MIN_DEVICES 2               /* unused + root HUB */
-#define USB_START_ADDR 0
+#define USB_MAX_DEVICES		128		/* 0, 1-127 */
+#define USB_MIN_DEVICES		2               /* unused + root HUB */
+#define USB_START_ADDR		0
 
 #define USB_CONTROL_ENDPOINT 0
 #define USB_MAX_ENDPOINTS 16

Index: src/sys/dev/usb/usb_subr.c
diff -u src/sys/dev/usb/usb_subr.c:1.217 src/sys/dev/usb/usb_subr.c:1.218
--- src/sys/dev/usb/usb_subr.c:1.217	Sun Dec  4 10:12:35 2016
+++ src/sys/dev/usb/usb_subr.c	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb_subr.c,v 1.217 2016/12/04 10:12:35 skrll Exp $	*/
+/*	$NetBSD: usb_subr.c,v 1.218 2017/01/19 16:05:00 skrll Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $	*/
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.217 2016/12/04 10:12:35 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.218 2017/01/19 16:05:00 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -801,7 +801,7 @@ usbd_setup_pipe_flags(struct usbd_device
 	if (err) {
 		DPRINTF("endpoint=0x%x failed, error=%d",
 		    ep->ue_edesc->bEndpointAddress, err, 0, 0);
-		kmem_intr_free(p, dev->ud_bus->ub_pipesize);
+		kmem_free(p, dev->ud_bus->ub_pipesize);
 		return err;
 	}
 
@@ -832,9 +832,11 @@ usbd_getnewaddr(struct usbd_bus *bus)
 {
 	int addr;
 
-	for (addr = 1; addr < USB_MAX_DEVICES; addr++)
-		if (bus->ub_devices[addr] == NULL)
+	for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
+		size_t dindex = usb_addr2dindex(addr);
+		if (bus->ub_devices[dindex] == NULL)
 			return addr;
+	}
 	return -1;
 }
 
@@ -1160,8 +1162,8 @@ usbd_get_initial_ddesc(struct usbd_devic
  * and attach a driver.
  */
 usbd_status
-usbd_new_device(device_t parent, struct usbd_bus* bus, int depth,
-                int speed, int port, struct usbd_port *up)
+usbd_new_device(device_t parent, struct usbd_bus *bus, int depth, int speed,
+    int port, struct usbd_port *up)
 {
 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
 	struct usbd_device *dev, *adev;
@@ -1248,7 +1250,7 @@ usbd_new_device(device_t parent, struct 
 
 	/* Establish the default pipe. */
 	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
-			      &dev->ud_pipe0, USBD_MPSAFE);
+	    &dev->ud_pipe0, USBD_MPSAFE);
 	if (err) {
 		usbd_remove_device(dev, up);
 		return err;
@@ -1261,6 +1263,11 @@ usbd_new_device(device_t parent, struct 
 		err = usbd_get_initial_ddesc(dev, dd);
 		if (!err)
 			break;
+		/*
+		 * The root hub can never fail to give the initial descriptor,
+		 * but assert it just in case.
+		 */
+		KASSERT(up->up_parent);
 		usbd_delay_ms(dev, 200);
 		if ((i & 3) == 3)
 			usbd_reset_port(up->up_parent, port, &ps);
@@ -1331,7 +1338,7 @@ usbd_new_device(device_t parent, struct 
 	/* Allow device time to set new address */
 	usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
 	dev->ud_addr = addr;	/* new device address now */
-	bus->ub_devices[addr] = dev;
+	bus->ub_devices[usb_addr2dindex(addr)] = dev;
 
 	/* Re-establish the default pipe with the new address. */
 	usbd_kill_pipe(dev->ud_pipe0);
@@ -1423,7 +1430,7 @@ usbd_remove_device(struct usbd_device *d
 	if (dev->ud_pipe0 != NULL)
 		usbd_kill_pipe(dev->ud_pipe0);
 	up->up_dev = NULL;
-	dev->ud_bus->ub_devices[dev->ud_addr] = NULL;
+	dev->ud_bus->ub_devices[usb_addr2dindex(dev->ud_addr)] = NULL;
 
 	kmem_free(dev, sizeof(*dev));
 }
@@ -1553,7 +1560,8 @@ usbd_fill_deviceinfo(struct usbd_device 
 		if (p->up_dev)
 			err = p->up_dev->ud_addr;
 		else {
-			int s = UGETW(p->up_status.wPortStatus);
+			const int s = UGETW(p->up_status.wPortStatus);
+			const bool sshub_p = USB_IS_SS(dev->ud_speed);
 			if (s & UPS_PORT_ENABLED)
 				err = USB_PORT_ENABLED;
 			else if (s & UPS_SUSPEND)
@@ -1563,10 +1571,9 @@ usbd_fill_deviceinfo(struct usbd_device 
 			 * on 3.x, and UPS_PORT_POWER is available
 			 * only on 2.0 or 1.1.
 			 */
-			else if (USB_IS_SS(dev->ud_speed) &&
-			    (s & UPS_PORT_POWER_SS))
+			else if (sshub_p && (s & UPS_PORT_POWER_SS))
 				err = USB_PORT_POWERED;
-			else if (s & UPS_PORT_POWER)
+			else if (!sshub_p && (s & UPS_PORT_POWER))
 				err = USB_PORT_POWERED;
 			else
 				err = USB_PORT_DISABLED;
@@ -1629,7 +1636,7 @@ usbd_fill_deviceinfo_old(struct usbd_dev
 		if (p->up_dev)
 			err = p->up_dev->ud_addr;
 		else {
-			int s = UGETW(p->up_status.wPortStatus);
+			const int s = UGETW(p->up_status.wPortStatus);
 			if (s & UPS_PORT_ENABLED)
 				err = USB_PORT_ENABLED;
 			else if (s & UPS_SUSPEND)
@@ -1731,9 +1738,14 @@ usb_disconnect_port(struct usbd_port *up
 		KASSERT(!dev->ud_nifaces_claimed);
 	}
 
-	usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
-	dev->ud_bus->ub_devices[dev->ud_addr] = NULL;
+	mutex_enter(dev->ud_bus->ub_lock);
+	dev->ud_bus->ub_devices[usb_addr2dindex(dev->ud_addr)] = NULL;
 	up->up_dev = NULL;
+	mutex_exit(dev->ud_bus->ub_lock);
+
+	usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
+
 	usb_free_device(dev);
+
 	return 0;
 }

Index: src/sys/dev/usb/usbdivar.h
diff -u src/sys/dev/usb/usbdivar.h:1.113 src/sys/dev/usb/usbdivar.h:1.114
--- src/sys/dev/usb/usbdivar.h:1.113	Sat Apr 23 10:15:32 2016
+++ src/sys/dev/usb/usbdivar.h	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdivar.h,v 1.113 2016/04/23 10:15:32 skrll Exp $	*/
+/*	$NetBSD: usbdivar.h,v 1.114 2017/01/19 16:05:00 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
@@ -139,6 +139,9 @@ struct usbd_hub {
 };
 
 /*****/
+/* 0, root, and 1->127 */
+#define USB_ROOTHUB_INDEX	1
+#define USB_TOTAL_DEVICES	(USB_MAX_DEVICES + 1)
 
 struct usbd_bus {
 	/* Filled by HC driver */
@@ -164,7 +167,7 @@ struct usbd_bus {
 	struct usbd_device     *ub_roothub;
 	uint8_t			ub_rhaddr;	/* roothub address */
 	uint8_t			ub_rhconf;	/* roothub configuration */
-	struct usbd_device     *ub_devices[USB_MAX_DEVICES];
+	struct usbd_device     *ub_devices[USB_TOTAL_DEVICES];
 	kcondvar_t              ub_needsexplore_cv;
 	char			ub_needsexplore;/* a hub a signalled a change */
 	char			ub_usepolling;
@@ -352,6 +355,13 @@ usbd_xfer_isread(struct usbd_xfer *xfer)
 	   UE_DIR_IN;
 }
 
+static inline size_t
+usb_addr2dindex(int addr)
+{
+
+	return USB_ROOTHUB_INDEX + addr;
+}
+
 /*
  * These macros reflect the current locking scheme.  They might change.
  */

Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.67 src/sys/dev/usb/xhci.c:1.68
--- src/sys/dev/usb/xhci.c:1.67	Sat Sep  3 12:07:41 2016
+++ src/sys/dev/usb/xhci.c	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhci.c,v 1.67 2016/09/03 12:07:41 skrll Exp $	*/
+/*	$NetBSD: xhci.c,v 1.68 2017/01/19 16:05:00 skrll Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.67 2016/09/03 12:07:41 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.68 2017/01/19 16:05:00 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -531,6 +531,36 @@ xhci_get_epstate(struct xhci_softc * con
 	return XHCI_EPCTX_0_EPSTATE_GET(le32toh(cp[0]));
 }
 
+static inline unsigned int
+xhci_ctlrport2bus(struct xhci_softc * const sc, unsigned int ctlrport)
+{
+	const unsigned int port = ctlrport - 1;
+	const uint8_t bit = __BIT(port % NBBY);
+
+	return __SHIFTOUT(sc->sc_ctlrportbus[port / NBBY], bit);
+}
+
+/*
+ * Return the roothub port for a controller port.  Both are 1..n.
+ */
+static inline unsigned int
+xhci_ctlrport2rhport(struct xhci_softc * const sc, unsigned int ctrlport)
+{
+
+	return sc->sc_ctlrportmap[ctrlport - 1];
+}
+
+/*
+ * Return the controller port for a bus roothub port.  Both are 1..n.
+ */
+static inline unsigned int
+xhci_rhport2ctlrport(struct xhci_softc * const sc, unsigned int bn,
+    unsigned int rhport)
+{
+
+	return sc->sc_rhportmap[bn][rhport - 1];
+}
+
 /* --- */
 
 void
@@ -548,11 +578,17 @@ xhci_detach(struct xhci_softc *sc, int f
 {
 	int rv = 0;
 
-	if (sc->sc_child != NULL)
-		rv = config_detach(sc->sc_child, flags);
+	if (sc->sc_child2 != NULL) {
+		rv = config_detach(sc->sc_child2, flags);
+		if (rv != 0)
+			return rv;
+	}
 
-	if (rv != 0)
-		return rv;
+	if (sc->sc_child != NULL) {
+		rv = config_detach(sc->sc_child, flags);
+		if (rv != 0)
+			return rv;
+	}
 
 	/* XXX unconfigure/free slots */
 
@@ -564,6 +600,7 @@ xhci_detach(struct xhci_softc *sc, int f
 	xhci_op_write_8(sc, XHCI_CRCR, 0);
 	xhci_ring_free(sc, &sc->sc_cr);
 	cv_destroy(&sc->sc_command_cv);
+	cv_destroy(&sc->sc_cmdbusy_cv);
 
 	xhci_rt_write_4(sc, XHCI_ERSTSZ(0), 0);
 	xhci_rt_write_8(sc, XHCI_ERSTBA(0), 0);
@@ -577,6 +614,13 @@ xhci_detach(struct xhci_softc *sc, int f
 
 	kmem_free(sc->sc_slots, sizeof(*sc->sc_slots) * sc->sc_maxslots);
 
+	kmem_free(sc->sc_ctlrportbus, sc->sc_maxports * sizeof(uint8_t) / NBBY);
+	kmem_free(sc->sc_ctlrportmap, sc->sc_maxports * sizeof(int));
+
+	for (size_t j = 0; j < __arraycount(sc->sc_rhportmap); j++) {
+		kmem_free(sc->sc_rhportmap[j], sc->sc_maxports * sizeof(int));
+	}
+
 	mutex_destroy(&sc->sc_lock);
 	mutex_destroy(&sc->sc_intr_lock);
 
@@ -700,37 +744,79 @@ hexdump(const char *msg, const void *bas
 #endif
 }
 
+/* 7.2 xHCI Support Protocol Capability */
+static void
+xhci_id_protocols(struct xhci_softc *sc, bus_size_t ecp)
+{
+	/* XXX Cache this lot */
+
+	const uint32_t w0 = xhci_read_4(sc, ecp);
+	const uint32_t w4 = xhci_read_4(sc, ecp + 4);
+	const uint32_t w8 = xhci_read_4(sc, ecp + 8);
+	const uint32_t wc = xhci_read_4(sc, ecp + 0xc);
+
+	aprint_debug_dev(sc->sc_dev,
+	    " SP: %08x %08x %08x %08x\n", w0, w4, w8, wc);
+
+	if (w4 != XHCI_XECP_USBID)
+		return;
+
+	const int major = XHCI_XECP_SP_W0_MAJOR(w0);
+	const int minor = XHCI_XECP_SP_W0_MINOR(w0);
+	const uint8_t cpo = XHCI_XECP_SP_W8_CPO(w8);
+	const uint8_t cpc = XHCI_XECP_SP_W8_CPC(w8);
+
+	const uint16_t mm = __SHIFTOUT(w0, __BITS(31, 16));
+	switch (mm) {
+	case 0x0200:
+	case 0x0300:
+	case 0x0301:
+		aprint_debug_dev(sc->sc_dev, " %s ports %d - %d\n",
+		    major == 3 ? "ss" : "hs", cpo, cpo + cpc -1);
+		break;
+	default:
+		aprint_debug_dev(sc->sc_dev, " unknown major/minor (%d/%d)\n",
+		    major, minor);
+		return;
+	}
+
+	const size_t bus = (major == 3) ? 0 : 1;
+
+	/* Index arrays with 0..n-1 where ports are numbered 1..n */
+	for (size_t cp = cpo - 1; cp < cpo + cpc - 1; cp++) {
+		if (sc->sc_ctlrportmap[cp] != 0) {
+			aprint_error_dev(sc->sc_dev, "contoller port %zu "
+			    "already assigned", cp);
+			continue;
+		}
+
+		sc->sc_ctlrportbus[cp / NBBY] |=
+		    bus == 0 ? 0 : __BIT(cp % NBBY);
+
+		const size_t rhp = sc->sc_rhportcount[bus]++;
+
+		KASSERTMSG(sc->sc_rhportmap[bus][rhp] == 0,
+		    "bus %zu rhp %zu is %d", bus, rhp,
+		    sc->sc_rhportmap[bus][rhp]);
+
+		sc->sc_rhportmap[bus][rhp] = cp + 1;
+		sc->sc_ctlrportmap[cp] = rhp + 1;
+	}
+}
+
 /* Process extended capabilities */
 static void
 xhci_ecp(struct xhci_softc *sc, uint32_t hcc)
 {
-	uint32_t ecp, ecr;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	ecp = XHCI_HCC_XECP(hcc) * 4;
+	bus_size_t ecp = XHCI_HCC_XECP(hcc) * 4;
 	while (ecp != 0) {
-		ecr = xhci_read_4(sc, ecp);
-		aprint_debug_dev(sc->sc_dev, "ECR %x: %08x\n", ecp, ecr);
+		uint32_t ecr = xhci_read_4(sc, ecp);
+		aprint_debug_dev(sc->sc_dev, "ECR %lx: %08x\n", ecp, ecr);
 		switch (XHCI_XECP_ID(ecr)) {
 		case XHCI_ID_PROTOCOLS: {
-			uint32_t w4, w8, wc;
-			uint16_t w2;
-			w2 = (ecr >> 16) & 0xffff;
-			w4 = xhci_read_4(sc, ecp + 4);
-			w8 = xhci_read_4(sc, ecp + 8);
-			wc = xhci_read_4(sc, ecp + 0xc);
-			aprint_debug_dev(sc->sc_dev,
-			    " SP: %08x %08x %08x %08x\n", ecr, w4, w8, wc);
-			/* unused */
-			if (w4 == 0x20425355 && (w2 & 0xff00) == 0x0300) {
-				sc->sc_ss_port_start = (w8 >> 0) & 0xff;;
-				sc->sc_ss_port_count = (w8 >> 8) & 0xff;;
-			}
-			if (w4 == 0x20425355 && (w2 & 0xff00) == 0x0200) {
-				sc->sc_hs_port_start = (w8 >> 0) & 0xff;
-				sc->sc_hs_port_count = (w8 >> 8) & 0xff;
-			}
+			xhci_id_protocols(sc, ecp);
 			break;
 		}
 		case XHCI_ID_USB_LEGACY: {
@@ -816,8 +902,19 @@ xhci_init(struct xhci_softc *sc)
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
+	/* Set up the bus struct for the usb 3 and usb 2 buses */
+	sc->sc_bus.ub_methods = &xhci_bus_methods;
+	sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);
 	sc->sc_bus.ub_revision = USBREV_3_0;
 	sc->sc_bus.ub_usedma = true;
+	sc->sc_bus.ub_hcpriv = sc;
+
+	sc->sc_bus2.ub_methods = &xhci_bus_methods;
+	sc->sc_bus2.ub_pipesize = sizeof(struct xhci_pipe);
+	sc->sc_bus2.ub_revision = USBREV_2_0;
+	sc->sc_bus2.ub_usedma = true;
+	sc->sc_bus2.ub_hcpriv = sc;
+	sc->sc_bus2.ub_dmatag = sc->sc_bus.ub_dmatag;
 
 	cap = xhci_read_4(sc, XHCI_CAPLENGTH);
 	caplength = XHCI_CAP_CAPLENGTH(cap);
@@ -860,10 +957,21 @@ xhci_init(struct xhci_softc *sc)
 	aprint_debug_dev(sc->sc_dev, "hcc=%s\n", sbuf);
 	aprint_debug_dev(sc->sc_dev, "xECP %x\n", XHCI_HCC_XECP(hcc) * 4);
 
-	/* print PSI and take ownership from BIOS */
+	/* default all ports to bus 0, i.e. usb 3 */
+	sc->sc_ctlrportbus = kmem_zalloc(sc->sc_maxports * sizeof(uint8_t) / NBBY, KM_SLEEP);
+	sc->sc_ctlrportmap = kmem_zalloc(sc->sc_maxports * sizeof(int), KM_SLEEP);
+
+	/* controller port to bus roothub port map */
+	for (size_t j = 0; j < __arraycount(sc->sc_rhportmap); j++) {
+		sc->sc_rhportmap[j] = kmem_zalloc(sc->sc_maxports * sizeof(int), KM_SLEEP);
+	}
+
+	/*
+	 * Process all Extended Capabilities
+	 */
 	xhci_ecp(sc, hcc);
 
-	bsz = XHCI_PORTSC(sc->sc_maxports + 1);
+	bsz = XHCI_PORTSC(sc->sc_maxports);
 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, caplength, bsz,
 	    &sc->sc_obh) != 0) {
 		aprint_error_dev(sc->sc_dev, "operational subregion failure\n");
@@ -1033,13 +1141,10 @@ xhci_init(struct xhci_softc *sc)
 	}
 
 	cv_init(&sc->sc_command_cv, "xhcicmd");
+	cv_init(&sc->sc_cmdbusy_cv, "xhcicmdq");
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
 
-	/* 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);
 	erst[0].erste_0 = htole64(xhci_ring_trbp(&sc->sc_er, 0));
@@ -1698,24 +1803,28 @@ xhci_clear_endpoint_stall_async(struct u
 
 /* Process roothub port status/change events and notify to uhub_intr. */
 static void
-xhci_rhpsc(struct xhci_softc * const sc, u_int port)
+xhci_rhpsc(struct xhci_softc * const sc, u_int ctlrport)
 {
-	struct usbd_xfer * const xfer = sc->sc_intrxfer;
-	uint8_t *p;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 	DPRINTFN(4, "xhci%d: port %u status change", device_unit(sc->sc_dev),
-	    port, 0, 0);
+	   ctlrport, 0, 0);
 
-	if (xfer == NULL)
+	if (ctlrport > sc->sc_maxports)
 		return;
 
-	if (port > sc->sc_maxports)
+	const size_t bn = xhci_ctlrport2bus(sc, ctlrport);
+	const size_t rhp = xhci_ctlrport2rhport(sc, ctlrport);
+	struct usbd_xfer * const xfer = sc->sc_intrxfer[bn];
+
+	DPRINTFN(4, "xhci%d: bus %d bp %u xfer %p status change",
+	    device_unit(sc->sc_dev), bn, rhp, xfer);
+
+	if (xfer == NULL)
 		return;
 
-	p = xfer->ux_buf;
+	uint8_t *p = xfer->ux_buf;
 	memset(p, 0, xfer->ux_length);
-	p[port/NBBY] |= 1 << (port%NBBY);
+	p[rhp / NBBY] |= 1 << (rhp % NBBY);
 	xfer->ux_actlen = xfer->ux_length;
 	xfer->ux_status = USBD_NORMAL_COMPLETION;
 	usb_transfer_complete(xfer);
@@ -1907,11 +2016,15 @@ xhci_event_cmd(struct xhci_softc * const
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	trb_0 = le64toh(trb->trb_0);
 	trb_2 = le32toh(trb->trb_2);
 	trb_3 = le32toh(trb->trb_3);
 
 	if (trb_0 == sc->sc_command_addr) {
+		sc->sc_resultpending = false;
+
 		sc->sc_result_trb.trb_0 = trb_0;
 		sc->sc_result_trb.trb_2 = trb_2;
 		sc->sc_result_trb.trb_3 = trb_3;
@@ -2171,9 +2284,9 @@ xhci_new_device(device_t parent, struct 
 
 	dd = &dev->ud_ddesc;
 
-	if ((depth == 0) && (port == 0)) {
-		KASSERT(bus->ub_devices[dev->ud_addr] == NULL);
-		bus->ub_devices[dev->ud_addr] = dev;
+	if (depth == 0 && port == 0) {
+		KASSERT(bus->ub_devices[USB_ROOTHUB_INDEX] == NULL);
+		bus->ub_devices[USB_ROOTHUB_INDEX] = dev;
 		err = usbd_get_initial_ddesc(dev, dd);
 		if (err) {
 			DPRINTFN(1, "get_initial_ddesc %u", err, 0, 0, 0);
@@ -2228,13 +2341,19 @@ xhci_new_device(device_t parent, struct 
 		//hexdump("slot context", cp, sc->sc_ctxsz);
 		uint8_t addr = XHCI_SCTX_3_DEV_ADDR_GET(le32toh(cp[3]));
 		DPRINTFN(4, "device address %u", addr, 0, 0, 0);
-		/* XXX ensure we know when the hardware does something
-		   we can't yet cope with */
+		/*
+		 * XXX ensure we know when the hardware does something
+		 * we can't yet cope with
+		 */
 		KASSERTMSG(addr >= 1 && addr <= 127, "addr %d", addr);
 		dev->ud_addr = addr;
-		/* XXX dev->ud_addr not necessarily unique on bus */
-		KASSERT(bus->ub_devices[dev->ud_addr] == NULL);
-		bus->ub_devices[dev->ud_addr] = dev;
+
+		KASSERTMSG(bus->ub_devices[usb_addr2dindex(dev->ud_addr)] == NULL,
+		    "addr %d already allocated", dev->ud_addr);
+		/*
+		 * The root hub is given its own slot
+		 */
+		bus->ub_devices[usb_addr2dindex(dev->ud_addr)] = dev;
 
 		err = usbd_get_initial_ddesc(dev, dd);
 		if (err) {
@@ -2284,13 +2403,12 @@ xhci_new_device(device_t parent, struct 
 
 	usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);
 
-	if ((depth == 0) && (port == 0)) {
+	if (depth == 0 && port == 0) {
 		usbd_attach_roothub(parent, dev);
-		DPRINTFN(1, "root_hub %p", bus->ub_roothub, 0, 0, 0);
+		DPRINTFN(1, "root hub %p", dev, 0, 0, 0);
 		return USBD_NORMAL_COMPLETION;
 	}
 
-
 	err = usbd_probe_and_attach(parent, dev, port, dev->ud_addr);
  bad:
 	if (err != USBD_NORMAL_COMPLETION) {
@@ -2496,8 +2614,9 @@ xhci_do_command_locked(struct xhci_softc
 	KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
 	KASSERT(mutex_owned(&sc->sc_lock));
 
-	/* XXX KASSERT may fire when cv_timedwait unlocks sc_lock */
-	KASSERT(sc->sc_command_addr == 0);
+	while (sc->sc_command_addr != 0)
+		cv_wait(&sc->sc_cmdbusy_cv, &sc->sc_lock);
+
 	/*
 	 * If enqueue pointer points at last of ring, it's Link TRB,
 	 * command TRB will be stored in 0th TRB.
@@ -2507,17 +2626,21 @@ xhci_do_command_locked(struct xhci_softc
 	else
 		sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
 
+	sc->sc_resultpending = true;
+
 	mutex_enter(&cr->xr_lock);
 	xhci_ring_put(sc, cr, NULL, trb, 1);
 	mutex_exit(&cr->xr_lock);
 
 	xhci_db_write_4(sc, XHCI_DOORBELL(0), 0);
 
-	if (cv_timedwait(&sc->sc_command_cv, &sc->sc_lock,
-	    MAX(1, mstohz(timeout))) == EWOULDBLOCK) {
-		xhci_abort_command(sc);
-		err = USBD_TIMEOUT;
-		goto timedout;
+	while (sc->sc_resultpending) {
+		if (cv_timedwait(&sc->sc_command_cv, &sc->sc_lock,
+		    MAX(1, mstohz(timeout))) == EWOULDBLOCK) {
+			xhci_abort_command(sc);
+			err = USBD_TIMEOUT;
+			goto timedout;
+		}
 	}
 
 	trb->trb_0 = sc->sc_result_trb.trb_0;
@@ -2541,7 +2664,10 @@ xhci_do_command_locked(struct xhci_softc
 	}
 
 timedout:
+	sc->sc_resultpending = false;
 	sc->sc_command_addr = 0;
+	cv_broadcast(&sc->sc_cmdbusy_cv);
+
 	return err;
 }
 
@@ -2928,6 +3054,7 @@ xhci_setup_ctx(struct usbd_pipe *pipe)
 static void
 xhci_setup_route(struct usbd_pipe *pipe, uint32_t *cp)
 {
+	struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
 	struct usbd_device *dev = pipe->up_dev;
 	struct usbd_port *up = dev->ud_powersrc;
 	struct usbd_device *hub;
@@ -2960,7 +3087,7 @@ xhci_setup_route(struct usbd_pipe *pipe,
 		    << ((dep - 1) * 4);
 	}
 	route = route >> 4;
-	DPRINTFN(4, "rhport %u Route %05x hub %p", rhport, route, hub, 0);
+	size_t bn = hub == sc->sc_bus.ub_roothub ? 0 : 1;
 
 	/* Locate port on upstream high speed hub */
 	for (adev = dev, hub = up->up_parent;
@@ -2975,15 +3102,20 @@ xhci_setup_route(struct usbd_pipe *pipe,
 				goto found;
 			}
 		}
-		panic("xhci_setup_route: cannot find HS port");
+		panic("%s: cannot find HS port", __func__);
 	found:
 		DPRINTFN(4, "high speed port %d", p, 0, 0, 0);
 	} else {
 		dev->ud_myhsport = NULL;
 	}
 
+	const size_t ctlrport = xhci_rhport2ctlrport(sc, bn, rhport);
+
+	DPRINTFN(4, "rhport %u ctlrport %u Route %05x hub %p", rhport,
+	    ctlrport, route, hub);
+
 	cp[0] |= XHCI_SCTX_0_ROUTE_SET(route);
-	cp[1] |= XHCI_SCTX_1_RH_PORT_SET(rhport);
+	cp[1] |= XHCI_SCTX_1_RH_PORT_SET(ctlrport);
 }
 
 /*
@@ -3222,6 +3354,8 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 	if (sc->sc_dying)
 		return -1;
 
+	size_t bn = bus == &sc->sc_bus ? 0 : 1;
+
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
@@ -3264,13 +3398,15 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	/* Clear Port Feature 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) {
+	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): {
+		const size_t cp = xhci_rhport2ctlrport(sc, bn, index);
+
+		DPRINTFN(4, "UR_CLEAR_PORT_FEAT bp=%d feat=%d bus=%d cp=%d",
+		    index, value, bn, cp);
+		if (index < 1 || index > sc->sc_rhportcount[bn]) {
 			return -1;
 		}
-		port = XHCI_PORTSC(index);
+		port = XHCI_PORTSC(cp);
 		v = xhci_op_read_4(sc, port);
 		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
 		v &= ~XHCI_PS_CLEAR;
@@ -3308,6 +3444,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			return -1;
 		}
 		break;
+	}
 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
 		if (len == 0)
 			break;
@@ -3318,11 +3455,13 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 
 		totlen = min(buflen, sizeof(hubd));
 		memcpy(&hubd, buf, totlen);
-		hubd.bNbrPorts = sc->sc_maxports;
+		hubd.bNbrPorts = sc->sc_rhportcount[bn];
 		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? */
+		for (i = 0, l = sc->sc_rhportcount[bn]; l > 0; i++, l -= 8) {
+			/* XXX can't find out? */
+			hubd.DeviceRemovable[i++] = 0;
+		}
 		hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
 		totlen = min(totlen, hubd.bDescLength);
 		memcpy(buf, &hubd, totlen);
@@ -3335,16 +3474,19 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 		totlen = len;
 		break;
 	/* Get Port Status request */
-	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) {
+	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): {
+		const size_t cp = xhci_rhport2ctlrport(sc, bn, index);
+
+		DPRINTFN(8, "get port status bn=%d i=%d cp=%zu", bn, index, cp,
+		    0);
+		if (index < 1 || index > sc->sc_rhportcount[bn]) {
 			return -1;
 		}
 		if (len != 4) {
 			return -1;
 		}
-		v = xhci_op_read_4(sc, XHCI_PORTSC(index));
-		DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
+		v = xhci_op_read_4(sc, XHCI_PORTSC(cp));
+		DPRINTFN(4, "getrhportsc %d %08x", cp, v, 0, 0);
 		i = xhci_xspeed2psspeed(XHCI_PS_SPEED_GET(v));
 		if (v & XHCI_PS_CCS)	i |= UPS_CURRENT_CONNECT_STATUS;
 		if (v & XHCI_PS_PED)	i |= UPS_PORT_ENABLED;
@@ -3374,6 +3516,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 		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):
@@ -3384,12 +3527,15 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): {
 		int optval = (index >> 8) & 0xff;
 		index &= 0xff;
-		if (index < 1 || index > sc->sc_maxports) {
+		if (index < 1 || index > sc->sc_rhportcount[bn]) {
 			return -1;
 		}
-		port = XHCI_PORTSC(index);
+
+		const size_t cp = xhci_rhport2ctlrport(sc, bn, index);
+
+		port = XHCI_PORTSC(cp);
 		v = xhci_op_read_4(sc, port);
-		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
+		DPRINTFN(4, "index %d cp %d portsc=0x%08x", index, cp, v, 0);
 		v &= ~XHCI_PS_CLEAR;
 		switch (value) {
 		case UHF_PORT_ENABLE:
@@ -3424,8 +3570,9 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			if (XHCI_PS_SPEED_GET(v) < XHCI_PS_SPEED_SS) {
 				return -1;
 			}
-			port = XHCI_PORTPMSC(index);
+			port = XHCI_PORTPMSC(cp);
 			v = xhci_op_read_4(sc, port);
+			DPRINTFN(4, "index %d cp %d portpmsc=0x%08x", index, cp, v, 0);
 			v &= ~XHCI_PM3_U1TO_SET(0xff);
 			v |= XHCI_PM3_U1TO_SET(optval);
 			xhci_op_write_4(sc, port, v);
@@ -3434,8 +3581,9 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			if (XHCI_PS_SPEED_GET(v) < XHCI_PS_SPEED_SS) {
 				return -1;
 			}
-			port = XHCI_PORTPMSC(index);
+			port = XHCI_PORTPMSC(cp);
 			v = xhci_op_read_4(sc, port);
+			DPRINTFN(4, "index %d cp %d portpmsc=0x%08x", index, cp, v, 0);
 			v &= ~XHCI_PM3_U2TO_SET(0xff);
 			v |= XHCI_PM3_U2TO_SET(optval);
 			xhci_op_write_4(sc, port, v);
@@ -3484,6 +3632,7 @@ static usbd_status
 xhci_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
+	const size_t bn = XHCI_XFER2BUS(xfer) == &sc->sc_bus ? 0 : 1;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
@@ -3491,7 +3640,7 @@ xhci_root_intr_start(struct usbd_xfer *x
 		return USBD_IOERROR;
 
 	mutex_enter(&sc->sc_lock);
-	sc->sc_intrxfer = xfer;
+	sc->sc_intrxfer[bn] = xfer;
 	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
@@ -3501,13 +3650,14 @@ static void
 xhci_root_intr_abort(struct usbd_xfer *xfer)
 {
 	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
+	const size_t bn = XHCI_XFER2BUS(xfer) == &sc->sc_bus ? 0 : 1;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 	KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
 
-	sc->sc_intrxfer = NULL;
+	sc->sc_intrxfer[bn] = NULL;
 
 	xfer->ux_status = USBD_CANCELLED;
 	usb_transfer_complete(xfer);
@@ -3517,12 +3667,14 @@ static void
 xhci_root_intr_close(struct usbd_pipe *pipe)
 {
 	struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
+	const struct usbd_xfer *xfer = pipe->up_intrxfer;
+	const size_t bn = XHCI_XFER2BUS(xfer) == &sc->sc_bus ? 0 : 1;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 
-	sc->sc_intrxfer = NULL;
+	sc->sc_intrxfer[bn] = NULL;
 }
 
 static void

Index: src/sys/dev/usb/xhcireg.h
diff -u src/sys/dev/usb/xhcireg.h:1.8 src/sys/dev/usb/xhcireg.h:1.9
--- src/sys/dev/usb/xhcireg.h:1.8	Sat Sep  3 12:05:36 2016
+++ src/sys/dev/usb/xhcireg.h	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: xhcireg.h,v 1.8 2016/09/03 12:05:36 skrll Exp $ */
+/* $NetBSD: xhcireg.h,v 1.9 2017/01/19 16:05:00 skrll Exp $ */
 
 /*-
  * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
@@ -38,10 +38,10 @@
 
 #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 */
@@ -66,7 +66,7 @@
     (__SHIFTOUT((x), XHCI_HCS2_SPBUFHI) << 5) | \
     (__SHIFTOUT((x), XHCI_HCS2_SPBUFLO))
 
-#define	XHCI_HCSPARAMS3		0x0C	/* RO structual parameters 3 */
+#define	XHCI_HCSPARAMS3		0x0c	/* RO structual parameters 3 */
 #define	 XHCI_HCS3_U1_DEL(x)	((x) & 0xFF)
 #define	 XHCI_HCS3_U2_DEL(x)	(((x) >> 16) & 0xFFFF)
 
@@ -132,14 +132,14 @@
 #define	 XHCI_CRCR_LO_CRR	0x00000008	/* RW - command ring running */
 #define	 XHCI_CRCR_LO_MASK	0x0000000F
 
-#define	XHCI_CRCR_HI		0x1C	/* XHCI command ring control */
+#define	XHCI_CRCR_HI		0x1c	/* XHCI command ring control */
 #define	XHCI_DCBAAP		0x30	/* XHCI dev context BA pointer */
 #define	XHCI_DCBAAP_HI		0x34	/* XHCI dev context BA pointer */
 #define	XHCI_CONFIG		0x38
 #define	XHCI_CONFIG_SLOTS_MASK	0x000000FF	/* RW - number of device slots enabled */
 
 /* XHCI port status registers */
-#define	XHCI_PORTSC(n)		(0x3F0 + (0x10 * (n)))	/* XHCI port status */
+#define	XHCI_PORTSC(n)		(0x3f0 + (0x10 * (n)))	/* XHCI port status */
 #define	 XHCI_PS_CCS		0x00000001	/* RO - current connect status */
 #define	 XHCI_PS_PED		0x00000002	/* RW - port enabled / disabled */
 #define	 XHCI_PS_OCA		0x00000008	/* RO - over current active */
@@ -170,7 +170,7 @@
 #define	 XHCI_PS_WPR		0x80000000U	/* RW - warm port reset */
 #define	 XHCI_PS_CLEAR		0x80FF01FFU	/* command bits */
 
-#define	XHCI_PORTPMSC(n)	(0x3F4 + (0x10 * (n)))	/* XHCI status and control */
+#define	XHCI_PORTPMSC(n)	(0x3f4 + (0x10 * (n)))	/* XHCI status and control */
 #define	 XHCI_PM3_U1TO_GET(x)	(((x) >> 0) & 0xFF)	/* RW - U1 timeout */
 #define	 XHCI_PM3_U1TO_SET(x)	(((x) & 0xFF) << 0)	/* RW - U1 timeout */
 #define	 XHCI_PM3_U2TO_GET(x)	(((x) >> 8) & 0xFF)	/* RW - U2 timeout */
@@ -184,10 +184,10 @@
 #define	 XHCI_PM2_L1SLOT_SET(x)	(((x) & 0xFF) << 8)	/* RW - L1 device slot */
 #define	 XHCI_PM2_HLE		0x00010000		/* RW - hardware LPM enable */
 
-#define	XHCI_PORTLI(n)		(0x3F8 + (0x10 * (n)))	/* XHCI port link info */
+#define	XHCI_PORTLI(n)		(0x3f8 + (0x10 * (n)))	/* XHCI port link info */
 #define	 XHCI_PLI3_ERR_GET(x)	(((x) >> 0) & 0xFFFF)	/* RO - port link errors */
 
-#define	XHCI_PORTRSV(n)		(0x3FC + (0x10 * (n)))	/* XHCI port reserved */
+#define	XHCI_PORTRSV(n)		(0x3fc + (0x10 * (n)))	/* XHCI port reserved */
 
 /* XHCI runtime registers.  Offset given by XHCI_CAPLENGTH + XHCI_RTSOFF registers */
 #define	XHCI_MFINDEX		0x0000		/* RO - microframe index */
@@ -224,11 +224,9 @@
 #define	 XHCI_DB_SID_GET(x)	(((x) >> 16) & 0xFFFF)	/* RW - doorbell stream ID */
 #define	 XHCI_DB_SID_SET(x)	(((x) & 0xFFFF) << 16)	/* RW - doorbell stream ID */
 
-/* XHCI legacy support */
+/* 7 xHCI Extendeded capabilities */
 #define	XHCI_XECP_ID(x)		((x) & 0xFF)
 #define	XHCI_XECP_NEXT(x)	(((x) >> 8) & 0xFF)
-#define	XHCI_XECP_BIOS_SEM	0x0002
-#define	XHCI_XECP_OS_SEM	0x0003
 
 /* XHCI extended capability ID's */
 #define	XHCI_ID_USB_LEGACY	0x0001	/* USB Legacy Support */
@@ -242,6 +240,27 @@
 #define	XHCI_ID_USB_DEBUG	0x000A	/* USB Debug Capability */
 #define	XHCI_ID_XMSG_IRQ	0x0011	/* Extended Message Interrupt */
 
+/* 7.1 xHCI legacy support */
+#define	XHCI_XECP_BIOS_SEM	0x0002
+#define	XHCI_XECP_OS_SEM	0x0003
+
+/* 7.2 xHCI Supported Protocol Capability */
+#define	XHCI_XECP_USBID 0x20425355
+
+#define	XHCI_XECP_SP_W0_MINOR_MASK	__BITS(23, 16)
+#define	XHCI_XECP_SP_W0_MINOR(x)	__SHIFTOUT((x), XHCI_XECP_SP_W0_MINOR_MASK)
+#define	XHCI_XECP_SP_W0_MAJOR_MASK	__BITS(31, 24)
+#define	XHCI_XECP_SP_W0_MAJOR(x)	__SHIFTOUT((x), XHCI_XECP_SP_W0_MAJOR_MASK)
+
+#define	XHCI_XECP_SP_W8_CPO_MASK	__BITS(7, 0)
+#define	XHCI_XECP_SP_W8_CPO(x)		__SHIFTOUT((x), XHCI_XECP_SP_W8_CPO_MASK)
+#define	XHCI_XECP_SP_W8_CPC_MASK	__BITS(15, 8)
+#define	XHCI_XECP_SP_W8_CPC(x)		__SHIFTOUT((x), XHCI_XECP_SP_W8_CPC_MASK)
+#define	XHCI_XECP_SP_W8_PD_MASK		__BITS(27, 16)
+#define	XHCI_XECP_SP_W8_PD(x)		__SHIFTOUT((x), XHCI_XECP_SP_W8_PD_MASK)
+#define	XHCI_XECP_SP_W8_PSIC_MASK	__BITS(31, 28)
+#define	XHCI_XECP_SP_W8_PSIC(x)		__SHIFTOUT((x), XHCI_XECP_SP_W8_PSIC_MASK)
+
 #define XHCI_PAGE_SIZE(sc) ((sc)->sc_pgsz)
 
 /* Chapter 6, Table 49 */

Index: src/sys/dev/usb/xhcivar.h
diff -u src/sys/dev/usb/xhcivar.h:1.6 src/sys/dev/usb/xhcivar.h:1.7
--- src/sys/dev/usb/xhcivar.h:1.6	Tue May  3 13:14:44 2016
+++ src/sys/dev/usb/xhcivar.h	Thu Jan 19 16:05:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhcivar.h,v 1.6 2016/05/03 13:14:44 skrll Exp $	*/
+/*	$NetBSD: xhcivar.h,v 1.7 2017/01/19 16:05:00 skrll Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -42,6 +42,7 @@ struct xhci_xfer {
 #define XHCI_BUS2SC(bus)	((bus)->ub_hcpriv)
 #define XHCI_PIPE2SC(pipe)	XHCI_BUS2SC((pipe)->up_dev->ud_bus)
 #define XHCI_XFER2SC(xfer)	XHCI_BUS2SC((xfer)->ux_bus)
+#define XHCI_XFER2BUS(xfer)	((xfer)->ux_bus)
 #define XHCI_XPIPE2SC(d)	XHCI_BUS2SC((d)->xp_pipe.up_dev->ud_bus)
 
 #define XHCI_XFER2XXFER(xfer)	((struct xhci_xfer *)(xfer))
@@ -71,6 +72,7 @@ struct xhci_slot {
 struct xhci_softc {
 	device_t sc_dev;
 	device_t sc_child;
+	device_t sc_child2;
 	bus_size_t sc_ios;
 	bus_space_tag_t sc_iot;
 	bus_space_handle_t sc_ioh;	/* Base */
@@ -78,7 +80,8 @@ struct xhci_softc {
 	bus_space_handle_t sc_obh;	/* Operational Base */
 	bus_space_handle_t sc_rbh;	/* Runtime Base */
 	bus_space_handle_t sc_dbh;	/* Doorbell Registers */
-	struct usbd_bus sc_bus;
+	struct usbd_bus sc_bus;		/* USB 3 bus */
+	struct usbd_bus sc_bus2;	/* USB 2 bus */
 
 	kmutex_t sc_lock;
 	kmutex_t sc_intr_lock;
@@ -87,22 +90,26 @@ struct xhci_softc {
 	char sc_vendor[32];		/* vendor string for root hub */
 	int sc_id_vendor;		/* vendor ID for root hub */
 
-	struct usbd_xfer *sc_intrxfer;
-
 	pool_cache_t sc_xferpool;
 
 	bus_size_t sc_pgsz;		/* xHCI page size */
 	uint32_t sc_ctxsz;
 	int sc_maxslots;
 	int sc_maxintrs;
-	int sc_maxports;
 	int sc_maxspbuf;
 
-	/* XXX suboptimal */
-	int sc_hs_port_start;
-	int sc_hs_port_count;
-	int sc_ss_port_start;
-	int sc_ss_port_count;
+	/*
+	 * Port routing and root hub - xHCI 4.19.7
+	 */
+	int sc_maxports;		/* number of controller ports */
+
+	uint8_t *sc_ctlrportbus;	/* a bus bit per port */
+
+	int *sc_ctlrportmap;
+	int *sc_rhportmap[2];
+	int sc_rhportcount[2];
+	struct usbd_xfer *sc_intrxfer[2];
+
 
 	struct xhci_slot * sc_slots;
 
@@ -114,9 +121,11 @@ struct xhci_softc {
 	usb_dma_t sc_spbufarray_dma;
 	usb_dma_t *sc_spbuf_dma;
 
+	kcondvar_t sc_cmdbusy_cv;
 	kcondvar_t sc_command_cv;
 	bus_addr_t sc_command_addr;
 	struct xhci_trb sc_result_trb;
+	bool sc_resultpending;
 
 	bool sc_ac64;
 	bool sc_dying;

Reply via email to