Module Name: src
Committed By: skrll
Date: Mon Jan 2 16:55:50 UTC 2017
Modified Files:
src/sys/arch/arm/nvidia [nick-nhusb]: tegra_xusb.c
src/sys/dev/pci [nick-nhusb]: xhci_pci.c
src/sys/dev/usb [nick-nhusb]: usb.h xhci.c xhcireg.h xhcivar.h
Log Message:
Parse the extended capabilies to and log each controller port to SS/HS
bus root hub ports.
Create/attach the two buses and adapt the xhci_roothub_ctrl to deal with
both buses and sets of roothub ports.
XXX the roothub ub_devices entry needs work to interact with usbdevs(1)
XXX correctly
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/arch/arm/nvidia/tegra_xusb.c
cvs rdiff -u -r1.4.2.7 -r1.4.2.8 src/sys/dev/pci/xhci_pci.c
cvs rdiff -u -r1.111.2.10 -r1.111.2.11 src/sys/dev/usb/usb.h
cvs rdiff -u -r1.28.2.82 -r1.28.2.83 src/sys/dev/usb/xhci.c
cvs rdiff -u -r1.2.2.9 -r1.2.2.10 src/sys/dev/usb/xhcireg.h
cvs rdiff -u -r1.4.12.11 -r1.4.12.12 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/arch/arm/nvidia/tegra_xusb.c
diff -u src/sys/arch/arm/nvidia/tegra_xusb.c:1.1.2.2 src/sys/arch/arm/nvidia/tegra_xusb.c:1.1.2.3
--- src/sys/arch/arm/nvidia/tegra_xusb.c:1.1.2.2 Wed Oct 5 20:55:25 2016
+++ src/sys/arch/arm/nvidia/tegra_xusb.c Mon Jan 2 16:55:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_xusb.c,v 1.1.2.2 2016/10/05 20:55:25 skrll Exp $ */
+/* $NetBSD: tegra_xusb.c,v 1.1.2.3 2017/01/02 16:55:50 skrll Exp $ */
/*
* Copyright (c) 2016 Jonathan A. Kollasch
@@ -30,7 +30,7 @@
#include "opt_tegra.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_xusb.c,v 1.1.2.2 2016/10/05 20:55:25 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_xusb.c,v 1.1.2.3 2017/01/02 16:55:50 skrll Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -349,6 +349,8 @@ tegra_xusb_mountroot(device_t self)
sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint);
+ sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint);
+
error = xusb_mailbox_send(psc, 0x01000000);
if (error) {
aprint_error_dev(self, "send failed, error=%d\n", error);
Index: src/sys/dev/pci/xhci_pci.c
diff -u src/sys/dev/pci/xhci_pci.c:1.4.2.7 src/sys/dev/pci/xhci_pci.c:1.4.2.8
--- src/sys/dev/pci/xhci_pci.c:1.4.2.7 Mon Dec 5 10:55:16 2016
+++ src/sys/dev/pci/xhci_pci.c Mon Jan 2 16:55:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: xhci_pci.c,v 1.4.2.7 2016/12/05 10:55:16 skrll Exp $ */
+/* $NetBSD: xhci_pci.c,v 1.4.2.8 2017/01/02 16:55:50 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.4.2.7 2016/12/05 10:55:16 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v 1.4.2.8 2017/01/02 16:55:50 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.h
diff -u src/sys/dev/usb/usb.h:1.111.2.10 src/sys/dev/usb/usb.h:1.111.2.11
--- src/sys/dev/usb/usb.h:1.111.2.10 Wed Oct 5 20:55:57 2016
+++ src/sys/dev/usb/usb.h Mon Jan 2 16:55:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: usb.h,v 1.111.2.10 2016/10/05 20:55:57 skrll Exp $ */
+/* $NetBSD: usb.h,v 1.111.2.11 2017/01/02 16:55:50 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 + 1) /* 0, root, and 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/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.28.2.82 src/sys/dev/usb/xhci.c:1.28.2.83
--- src/sys/dev/usb/xhci.c:1.28.2.82 Mon Jan 2 16:54:15 2017
+++ src/sys/dev/usb/xhci.c Mon Jan 2 16:55:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: xhci.c,v 1.28.2.82 2017/01/02 16:54:15 skrll Exp $ */
+/* $NetBSD: xhci.c,v 1.28.2.83 2017/01/02 16:55:50 skrll Exp $ */
/*
* Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.82 2017/01/02 16:54:15 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.83 2017/01/02 16:55:50 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 */
@@ -578,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);
@@ -701,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: {
@@ -817,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);
@@ -861,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");
@@ -1038,10 +1145,6 @@ xhci_init(struct xhci_softc *sc)
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));
@@ -1707,24 +1810,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);
@@ -2185,8 +2292,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;
+#define XHCI_ROOTHUB_INDEX 128
+ KASSERT(bus->ub_devices[XHCI_ROOTHUB_INDEX] == NULL);
+ bus->ub_devices[XHCI_ROOTHUB_INDEX] = dev;
err = usbd_get_initial_ddesc(dev, dd);
if (err) {
DPRINTFN(1, "get_initial_ddesc %u", err, 0, 0, 0);
@@ -2241,12 +2349,18 @@ 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);
+
+ KASSERTMSG(bus->ub_devices[dev->ud_addr] == NULL,
+ "addr %d already allocated", dev->ud_addr);
+ /*
+ * The root hub is given a slot
+ */
bus->ub_devices[dev->ud_addr] = dev;
err = usbd_get_initial_ddesc(dev, dd);
@@ -2303,7 +2417,6 @@ xhci_new_device(device_t parent, struct
return USBD_NORMAL_COMPLETION;
}
-
err = usbd_probe_and_attach(parent, dev, port, dev->ud_addr);
bad:
if (err != USBD_NORMAL_COMPLETION) {
@@ -2949,6 +3062,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;
@@ -2981,7 +3095,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;
@@ -3003,8 +3117,13 @@ xhci_setup_route(struct usbd_pipe *pipe,
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);
}
/*
@@ -3243,6 +3362,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);
@@ -3285,13 +3406,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;
@@ -3329,6 +3452,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus,
return -1;
}
break;
+ }
case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
if (len == 0)
break;
@@ -3339,11 +3463,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);
@@ -3356,16 +3482,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;
@@ -3395,6 +3524,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):
@@ -3405,12 +3535,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:
@@ -3445,8 +3578,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);
@@ -3455,8 +3589,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);
@@ -3505,6 +3640,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();
@@ -3512,7 +3648,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;
@@ -3522,13 +3658,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);
@@ -3538,12 +3675,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.2.2.9 src/sys/dev/usb/xhcireg.h:1.2.2.10
--- src/sys/dev/usb/xhcireg.h:1.2.2.9 Mon Jan 2 16:39:36 2017
+++ src/sys/dev/usb/xhcireg.h Mon Jan 2 16:55:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: xhcireg.h,v 1.2.2.9 2017/01/02 16:39:36 skrll Exp $ */
+/* $NetBSD: xhcireg.h,v 1.2.2.10 2017/01/02 16:55:50 skrll Exp $ */
/*-
* Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
@@ -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.4.12.11 src/sys/dev/usb/xhcivar.h:1.4.12.12
--- src/sys/dev/usb/xhcivar.h:1.4.12.11 Mon May 30 06:48:46 2016
+++ src/sys/dev/usb/xhcivar.h Mon Jan 2 16:55:50 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: xhcivar.h,v 1.4.12.11 2016/05/30 06:48:46 skrll Exp $ */
+/* $NetBSD: xhcivar.h,v 1.4.12.12 2017/01/02 16:55:50 skrll Exp $ */
/*
* Copyright (c) 2013 Jonathan A. Kollasch
@@ -41,6 +41,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))
@@ -70,6 +71,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 */
@@ -77,7 +79,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;
@@ -86,22 +89,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;