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;