Index: sys/dev/usb/usb_subr.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v retrieving revision 1.198.2.26 diff -u -p -r1.198.2.26 usb_subr.c --- sys/dev/usb/usb_subr.c 19 Mar 2016 07:12:21 -0000 1.198.2.26 +++ sys/dev/usb/usb_subr.c 4 Apr 2016 15:05:07 -0000 @@ -1162,23 +1166,11 @@ usbd_new_device(device_t parent, struct usb_device_descriptor_t *dd; usb_port_status_t ps; usbd_status err; - int addr; int i; int p; DPRINTF("bus=%p port=%d depth=%d speed=%d", bus, port, depth, speed); - if (bus->ub_methods->ubm_newdev != NULL) - return (bus->ub_methods->ubm_newdev)(parent, bus, depth, speed, - port, up); - - addr = usbd_getnewaddr(bus); - if (addr < 0) { - printf("%s: No free USB addresses, new device ignored.\n", - device_xname(bus->ub_usbctl)); - return USBD_NO_ADDR; - } - dev = kmem_zalloc(sizeof(*dev), KM_SLEEP); if (dev == NULL) return USBD_NOMEM; @@ -1247,6 +1239,15 @@ usbd_new_device(device_t parent, struct return err; } + /* Do any bus specific preparation */ + if (bus->ub_methods->ubm_dinit != NULL) { + err = bus->ub_methods->ubm_dinit(dev); + if (err) { + usbd_remove_device(dev, up); + return err; + } + } + dd = &dev->ud_ddesc; /* Try a few times in case the device is slow (i.e. outside specs.) */ for (i = 0; i < 10; i++) { @@ -1259,8 +1260,7 @@ usbd_new_device(device_t parent, struct usbd_reset_port(up->up_parent, port, &ps); } if (err) { - DPRINTF("addr=%d, getting first desc failed: %d", addr, err, - 0, 0); + DPRINTF("getting first desc failed: %d", err, 0, 0, 0); usbd_remove_device(dev, up); return err; } @@ -1269,20 +1269,8 @@ usbd_new_device(device_t parent, struct if (up->up_parent) usbd_reset_port(up->up_parent, port, &ps); - if (speed == USB_SPEED_HIGH) { - /* Max packet size must be 64 (sec 5.5.3). */ - if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) { -#ifdef DIAGNOSTIC - printf("usbd_new_device: addr=%d bad max packet " - "size=%d. adjusting to %d.\n", - addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET); -#endif - dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET; - } - } - - DPRINTF("adding unit addr=%d, rev=%02x, class=%d, subclass=%d", addr, - UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass); + DPRINTF("adding unit rev=%02x, class=%d, subclass=%d", + UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, 0); DPRINTF("protocol=%d, maxpacket=%d, len=%d, speed=%d", dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, dev->ud_speed); @@ -1299,7 +1287,21 @@ usbd_new_device(device_t parent, struct return USBD_INVAL; } - USETW(dev->ud_ep0desc.wMaxPacketSize, dd->bMaxPacketSize); + /* 4.3, 4.8.2.1 */ + if (USB_IS_SS(speed)) { + USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET); + } else + switch (speed) { + case USB_SPEED_FULL: + /* XXX using 64 as initial mps of ep0 in FS */ + case USB_SPEED_HIGH: + USETW(dev->ud_ep0desc.wMaxPacketSize, USB_2_MAX_CTRL_PACKET); + break; + case USB_SPEED_LOW: + default: + USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET); + break; + } /* Re-establish the default pipe with the new MPS. */ usbd_kill_pipe(dev->ud_pipe0); @@ -1312,13 +1314,28 @@ usbd_new_device(device_t parent, struct } /* Set the address */ - DPRINTFN(5, "setting device address=%d", addr, 0, 0, 0); - err = usbd_set_address(dev, addr); + int addr = 0; + err = USBD_NORMAL_COMPLETION; + if (bus->ub_methods->ubm_setaddr != NULL) { + addr = bus->ub_methods->ubm_setaddr(dev); + if (addr < 0) + err = USBD_NO_ADDR; + } else { + /* Pick a free address on this bus segment */ + addr = usbd_getnewaddr(bus); + if (addr > 0) { + err = usbd_set_address(dev, addr); + if (err) + err = USBD_SET_ADDR_FAILED; + } else { + err = USBD_NO_ADDR; + } + } + + DPRINTFN(5, "device address=%d", addr, 0, 0, 0); if (err) { - DPRINTF("set address %d failed, err = %d", addr, err, 0, 0); - err = USBD_SET_ADDR_FAILED; + DPRINTF("... failed, err = %d", err, 0, 0, 0); usbd_remove_device(dev, up); - return err; } /* Allow device time to set new address */ @@ -1366,6 +1383,15 @@ usbd_new_device(device_t parent, struct return err; } + /* Do any bus specific configuration now everything is known */ + if (bus->ub_methods->ubm_dconf != NULL) { + err = bus->ub_methods->ubm_dconf(dev); + if (err) { + usbd_remove_device(dev, up); + return err; + } + } + return USBD_NORMAL_COMPLETION; } @@ -1416,6 +1442,8 @@ usbd_remove_device(struct usbd_device *d if (dev->ud_pipe0 != NULL) usbd_kill_pipe(dev->ud_pipe0); up->up_dev = NULL; + if (dev->ud_bus->ub_methods->ubm_dfini != NULL) + dev->ud_bus->ub_methods->ubm_dfini(dev); dev->ud_bus->ub_devices[dev->ud_addr] = NULL; kmem_free(dev, sizeof(*dev)); @@ -1702,10 +1730,10 @@ usb_disconnect_port(struct usbd_port *up DPRINTFN(3, "up=%p dev=%p port=%d", up, dev, up->up_portno, 0); + /* + * ehci handover to companion controller can come here + */ if (dev == NULL) { -#ifdef DIAGNOSTIC - printf("usb_disconnect_port: no device\n"); -#endif return 0; } @@ -1727,6 +1755,8 @@ usb_disconnect_port(struct usbd_port *up } usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); + if (dev->ud_bus->ub_methods->ubm_dfini != NULL) + dev->ud_bus->ub_methods->ubm_dfini(dev); dev->ud_bus->ub_devices[dev->ud_addr] = NULL; up->up_dev = NULL; usb_free_device(dev); Index: sys/dev/usb/usbdivar.h =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdivar.h,v retrieving revision 1.109.2.26 diff -u -p -r1.109.2.26 usbdivar.h --- sys/dev/usb/usbdivar.h 29 Mar 2016 08:42:41 -0000 1.109.2.26 +++ sys/dev/usb/usbdivar.h 4 Apr 2016 15:05:07 -0000 @@ -47,7 +47,11 @@ * ubm_freex - * ubm_getlock - Called at attach time * ubm_newdev - Will take lock - ubm_rhctrl + * ubm_setaddr - HC method to assign/set address + * ubm_dinit - HC method when a new device added + * ubm_dfini - HC method when device is removed + * ubm_dconf - HC method finish device configuration + * ubm_rhctrl * * PIPE METHOD LOCK NOTES * ----------------------- ------- ------------------------- @@ -91,14 +95,18 @@ struct usbd_endpoint { }; struct usbd_bus_methods { - usbd_status (*ubm_open)(struct usbd_pipe *); - void (*ubm_softint)(void *); - void (*ubm_dopoll)(struct usbd_bus *); - struct usbd_xfer *(*ubm_allocx)(struct usbd_bus *, unsigned int); - void (*ubm_freex)(struct usbd_bus *, struct usbd_xfer *); - void (*ubm_getlock)(struct usbd_bus *, kmutex_t **); - usbd_status (*ubm_newdev)(device_t, struct usbd_bus *, int, - int, int, struct usbd_port *); + usbd_status (*ubm_open)(struct usbd_pipe *); + void (*ubm_softint)(void *); + void (*ubm_dopoll)(struct usbd_bus *); + struct usbd_xfer * (*ubm_allocx)(struct usbd_bus *, unsigned int); + void (*ubm_freex)(struct usbd_bus *, + struct usbd_xfer *); + void (*ubm_getlock)(struct usbd_bus *, kmutex_t **); + + int (*ubm_setaddr)(struct usbd_device *); + int (*ubm_dinit)(struct usbd_device *); + void (*ubm_dfini)(struct usbd_device *); + int (*ubm_dconf)(struct usbd_device *); int (*ubm_rhctrl)(struct usbd_bus *, usb_device_request_t *, void *, int); Index: sys/dev/usb/xhci.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/xhci.c,v retrieving revision 1.28.2.54 diff -u -p -r1.28.2.54 xhci.c --- sys/dev/usb/xhci.c 19 Mar 2016 11:30:21 -0000 1.28.2.54 +++ sys/dev/usb/xhci.c 4 Apr 2016 15:05:08 -0000 @@ -122,6 +122,8 @@ struct xhci_pipe { #define XHCI_COMMAND_RING_TRBS 256 #define XHCI_EVENT_RING_TRBS 256 #define XHCI_EVENT_RING_SEGMENTS 1 + +/* Event data */ #define XHCI_TRB_3_ED_BIT XHCI_TRB_3_ISP_BIT static usbd_status xhci_open(struct usbd_pipe *); @@ -132,8 +134,12 @@ static void xhci_poll(struct usbd_bus *) static struct usbd_xfer *xhci_allocx(struct usbd_bus *, unsigned int); static void xhci_freex(struct usbd_bus *, struct usbd_xfer *); static void xhci_get_lock(struct usbd_bus *, kmutex_t **); -static usbd_status xhci_new_device(device_t, struct usbd_bus *, int, int, int, - struct usbd_port *); + +static int xhci_device_init(struct usbd_device *); +static void xhci_device_fini(struct usbd_device *); +static int xhci_set_addr(struct usbd_device *); +static int xhci_configure_device(struct usbd_device *); + static int xhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *, void *, int); @@ -150,7 +156,7 @@ static usbd_status xhci_do_command1(stru struct xhci_trb * const, int, int); static usbd_status xhci_do_command_locked(struct xhci_softc * const, struct xhci_trb * const, int); -static usbd_status xhci_init_slot(struct usbd_device *, uint32_t, int, int); +static usbd_status xhci_init_slot(struct usbd_device *, uint32_t, uint32_t, int); static usbd_status xhci_enable_slot(struct xhci_softc * const, uint8_t * const); static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t); @@ -198,7 +204,10 @@ static const struct usbd_bus_methods xhc .ubm_allocx = xhci_allocx, .ubm_freex = xhci_freex, .ubm_getlock = xhci_get_lock, - .ubm_newdev = xhci_new_device, + .ubm_setaddr = xhci_set_addr, + .ubm_dinit = xhci_device_init, + .ubm_dfini = xhci_device_fini, + .ubm_dconf = xhci_configure_device, .ubm_rhctrl = xhci_roothub_ctrl, }; @@ -2101,9 +2110,7 @@ xhci_get_lock(struct usbd_bus *bus, kmut *lock = &sc->sc_lock; } -extern uint32_t usb_cookie_no; - -/* +/* XXXNH review * Called if uhub_explore finds a new device (via usbd_new_device). * Allocate and construct dev structure of default endpoint (ep0). * Determine initial MaxPacketSize (mps) by speed. @@ -2113,73 +2120,27 @@ extern uint32_t usb_cookie_no; * Read device descriptor. * Register this device. */ + static usbd_status -xhci_new_device(device_t parent, struct usbd_bus *bus, int depth, - int speed, int port, struct usbd_port *up) +xhci_new_device(struct usbd_device *dev, bool bsr) { - struct xhci_softc * const sc = XHCI_BUS2SC(bus); - struct usbd_device *dev; - usbd_status err; - usb_device_descriptor_t *dd; + struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus); + struct xhci_slot *xs; struct usbd_device *hub; - struct usbd_device *adev; + usbd_status err; + uint8_t slot; int rhport = 0; - struct xhci_slot *xs; - uint32_t *cp; - uint32_t route = 0; - uint8_t slot = 0; - uint8_t addr; XHCIHIST_FUNC(); XHCIHIST_CALLED(); - DPRINTFN(4, "port=%d depth=%d speed=%d upport %d", - port, depth, speed, up->up_portno); - - dev = kmem_zalloc(sizeof(*dev), KM_SLEEP); - if (dev == NULL) - return USBD_NOMEM; - - dev->ud_bus = bus; - - /* Set up default endpoint handle. */ - dev->ud_ep0.ue_edesc = &dev->ud_ep0desc; - - /* Set up default endpoint descriptor. */ - dev->ud_ep0desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE; - dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT; - dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT; - dev->ud_ep0desc.bmAttributes = UE_CONTROL; - /* 4.3, 4.8.2.1 */ - if (USB_IS_SS(speed)) { - USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET); - } else - switch (speed) { - case USB_SPEED_FULL: - /* XXX using 64 as initial mps of ep0 in FS */ - case USB_SPEED_HIGH: - USETW(dev->ud_ep0desc.wMaxPacketSize, USB_2_MAX_CTRL_PACKET); - break; - case USB_SPEED_LOW: - default: - USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET); - break; - } - dev->ud_ep0desc.bInterval = 0; - - /* doesn't matter, just don't let it uninitialized */ - dev->ud_ep0.ue_toggle = 0; - DPRINTFN(4, "up %p portno %d", up, up->up_portno, 0, 0); - - dev->ud_quirks = &usbd_no_quirk; - dev->ud_addr = 0; - dev->ud_ddesc.bMaxPacketSize = 0; - dev->ud_depth = depth; - dev->ud_powersrc = up; - dev->ud_myhub = up->up_parent; + /* No-op for the root port */ + if (dev->ud_depth == 0) + return USBD_NORMAL_COMPLETION; - up->up_dev = dev; + uint32_t route = 0; + dev->ud_hcpriv = NULL; - /* Locate root hub port */ + /* Work back up to the root hub */ for (hub = dev; hub != NULL; hub = hub->ud_myhub) { uint32_t dep; @@ -2200,149 +2161,196 @@ xhci_new_device(device_t parent, struct (rhport > UHD_SS_NPORTS_MAX ? UHD_SS_NPORTS_MAX : rhport) << ((dep - 1) * 4); } + /* why??? */ route = route >> 4; DPRINTFN(4, "rhport %d Route %05x hub %p", rhport, route, hub, 0); - /* Locate port on upstream high speed hub */ - for (adev = dev, hub = up->up_parent; - hub != NULL && hub->ud_speed != USB_SPEED_HIGH; - adev = hub, hub = hub->ud_myhub) - ; - if (hub) { - int p; - for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) { - if (hub->ud_hub->uh_ports[p].up_dev == adev) { - dev->ud_myhsport = &hub->ud_hub->uh_ports[p]; - goto found; - } - } - panic("xhci_new_device: cannot find HS port"); - found: - DPRINTFN(4, "high speed port %d", p, 0, 0, 0); - } else { - dev->ud_myhsport = NULL; + /* Allocate a slot */ + err = xhci_enable_slot(sc, &slot); + if (err) + return err; + err = xhci_init_slot(dev, slot, route, rhport); + if (err) { +#if 0 + /* XXXNH xhci_init_slot should not screw up !!! */ + /* + * We have to disable_slot here because + * xs->xs_idx == 0 when xhci_init_slot fails, + * in that case usbd_remove_dev won't work. + */ + mutex_enter(&sc->sc_lock); + xhci_disable_slot(sc, slot); + mutex_exit(&sc->sc_lock); +#endif + return err; } + xs = &sc->sc_slots[slot]; - dev->ud_speed = speed; - dev->ud_langid = USBD_NOLANG; - dev->ud_cookie.cookie = ++usb_cookie_no; - - /* Establish the default pipe. */ - err = usbd_setup_pipe(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL, - &dev->ud_pipe0); + /* Do the addressing side effects */ + err = xhci_address_device(sc, xhci_slot_get_icp(sc, xs, 0), slot, + bsr); if (err) { - goto bad; + /* XXX Tidy up */ + return err; } - dd = &dev->ud_ddesc; + dev->ud_hcpriv = xs; - if ((depth == 0) && (port == 0)) { - KASSERT(bus->ub_devices[dev->ud_addr] == NULL); - bus->ub_devices[dev->ud_addr] = dev; - err = usbd_get_initial_ddesc(dev, dd); - if (err) - goto bad; - err = usbd_reload_device_desc(dev); - if (err) - goto bad; - } else { - err = xhci_enable_slot(sc, &slot); - if (err) - goto bad; - xs = &sc->sc_slots[slot]; - dev->ud_hcpriv = xs; - err = xhci_init_slot(dev, slot, route, rhport); - if (err) { - dev->ud_hcpriv = NULL; - /* - * We have to disable_slot here because - * xs->xs_idx == 0 when xhci_init_slot fails, - * in that case usbd_remove_dev won't work. - */ - mutex_enter(&sc->sc_lock); - xhci_disable_slot(sc, slot); - mutex_exit(&sc->sc_lock); - goto bad; - } - - /* Allow device time to set new address */ - usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); - cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT); - //hexdump("slot context", cp, sc->sc_ctxsz); - addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]); - DPRINTFN(4, "device address %u", addr, 0, 0, 0); - /* XXX ensure we know when the hardware does something - we can't yet cope with */ - KASSERT(addr >= 1 && addr <= 127); - 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; + return USBD_NORMAL_COMPLETION; +} - err = usbd_get_initial_ddesc(dev, dd); - if (err) - goto bad; - /* 4.8.2.1 */ - if (USB_IS_SS(speed)) { - if (dd->bMaxPacketSize != 9) { - printf("%s: invalid mps 2^%u for SS ep0," - " using 512\n", - device_xname(sc->sc_dev), - dd->bMaxPacketSize); - dd->bMaxPacketSize = 9; - } - USETW(dev->ud_ep0desc.wMaxPacketSize, - (1 << dd->bMaxPacketSize)); - } else - USETW(dev->ud_ep0desc.wMaxPacketSize, - dd->bMaxPacketSize); - DPRINTFN(4, "bMaxPacketSize %u", dd->bMaxPacketSize, 0, 0, 0); - xhci_update_ep0_mps(sc, xs, - UGETW(dev->ud_ep0desc.wMaxPacketSize)); - err = usbd_reload_device_desc(dev); - if (err) - goto bad; +static int +xhci_device_init(struct usbd_device *dev) +{ -#if 0 - /* Re-establish the default pipe with the new MPS. */ - /* In xhci this is done by xhci_update_ep0_mps. */ - usbd_kill_pipe(dev->ud_pipe0); - err = usbd_setup_pipe(dev, 0, &dev->ud_ep0, - USBD_DEFAULT_INTERVAL, &dev->ud_pipe0); -#endif - } + return xhci_new_device(dev, true); +} + +static int +xhci_set_addr(struct usbd_device *dev) +{ + struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus); + struct xhci_slot *xs = dev->ud_hcpriv; + usbd_status err; + uint32_t *cp; + uint8_t addr; - DPRINTFN(1, "adding unit addr=%d, rev=%02x,", - dev->ud_addr, UGETW(dd->bcdUSB), 0, 0); - DPRINTFN(1, " class=%d, subclass=%d, protocol=%d,", - dd->bDeviceClass, dd->bDeviceSubClass, - dd->bDeviceProtocol, 0); - DPRINTFN(1, " mps=%d, len=%d, noconf=%d, speed=%d", - dd->bMaxPacketSize, dd->bLength, dd->bNumConfigurations, - dev->ud_speed); - - usbd_get_device_strings(dev); - - usbd_get_device_strings(dev); - - usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); - - if ((depth == 0) && (port == 0)) { - usbd_attach_roothub(parent, dev); - DPRINTFN(1, "root_hub %p", bus->ub_roothub, 0, 0, 0); + XHCIHIST_FUNC(); XHCIHIST_CALLED(); + + /* For the root port, return a value that the controller wont */ + if (dev->ud_depth == 0) + return 0; + + /* + * Slot is enabled and currently in the default state, disable it, + * then assign an address to get it into the addressed state. + */ + err = xhci_disable_slot(sc, xs->xs_idx); + if (err) + return -1; + err = xhci_new_device(dev, false); + if (err) + return -1; + + /* Locate our context */ + cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT); + addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]); + DPRINTFN(4, "device address %u", addr, 0, 0, 0); + + /* Update the endpoint 0 max packet size */ + xhci_update_ep0_mps(sc, xs, + UGETW(dev->ud_ep0desc.wMaxPacketSize)); + + return addr; +} + +static int +xhci_configure_device(struct usbd_device *dev) +{ + struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus); + struct xhci_slot *xs = dev->ud_hcpriv; + uint32_t *cp; + struct xhci_trb trb; + usbd_status err; + int speed = dev->ud_speed; + bool ishub = false; + bool usemtt = false; + + /* No-op for the root hub */ + if (dev->ud_depth == 0) return USBD_NORMAL_COMPLETION; + + /* Set up input control context */ + cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL); + cp[0] = htole32(0); + cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(XHCI_DCI_SLOT)); + + /* + * Complete the input slot context now the full descriptor is + * available + */ + cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT)); + + if (dev->ud_hub) { + uint8_t tttime = 0; + + /* Think time for high speed hubs */ + switch (UGETW(dev->ud_hub->uh_hubdesc.wHubCharacteristics) & UHD_TT_THINK) { + case UHD_TT_THINK_8: tttime = 0; break; + case UHD_TT_THINK_16: tttime = 1; break; + case UHD_TT_THINK_24: tttime = 2; break; + case UHD_TT_THINK_32: tttime = 3; break; + } + + ishub = true; + + cp[1] |= htole32( + XHCI_SCTX_1_NUM_PORTS_SET(dev->ud_hub->uh_hubdesc.bNbrPorts) + ); + cp[2] |= htole32( + XHCI_SCTX_2_TT_THINK_TIME_SET(tttime) + ); } +#define IS_TTHUB(dd) \ + ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \ + (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT) - err = usbd_probe_and_attach(parent, dev, port, dev->ud_addr); - bad: - if (err != USBD_NORMAL_COMPLETION) { - usbd_remove_device(dev, up); + /* + * Use MTT if this is a HS hub with MTT enabled, or this is a + * LS or FS (non hub) device connected to a HS hub with MTT + * enabled. + */ + if (ishub && (speed == USB_SPEED_HIGH) && IS_TTHUB(&dev->ud_ddesc)) { + usemtt = true; + } else { + if (((speed == USB_SPEED_LOW) || (speed == USB_SPEED_FULL)) && + (dev->ud_myhsport != NULL) && /* => there is a HS hub somewhere upstream */ + (dev->ud_myhub != NULL) && + (dev->ud_myhub->ud_speed == USB_SPEED_HIGH) && /* => it is our nearest hub */ + (dev->ud_myhub->ud_depth != 0) && + !ishub && + IS_TTHUB(&dev->ud_myhsport->up_parent->ud_ddesc)) { + usemtt = true; + } } + cp[0] |= htole32( + XHCI_SCTX_0_MTT_SET(usemtt ? 1 : 0) | + XHCI_SCTX_0_HUB_SET(ishub ? 1 : 0) + ); + + /* Sync input contexts before they are read from memory */ + usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE); + hexdump("input context", xhci_slot_get_icv(sc, xs, 0), + sc->sc_ctxsz * 4); + + trb.trb_0 = xhci_slot_get_icp(sc, xs, 0); + trb.trb_2 = 0; + trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX); + + err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT); + return err; } +static void +xhci_device_fini(struct usbd_device *dev) +{ + struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus); + struct xhci_slot * const xs = dev->ud_hcpriv; + + /* No-op for the root port */ + if (dev->ud_depth == 0) + return; + + if (xs != NULL) { + xhci_disable_slot(sc, xs->xs_idx); + dev->ud_hcpriv = NULL; + } +} + static usbd_status xhci_ring_init(struct xhci_softc * const sc, struct xhci_ring * const xr, size_t ntrb, size_t align) @@ -2696,10 +2704,9 @@ xhci_set_dcba(struct xhci_softc * const /* * Allocate DMA buffer and ring buffer for specified slot * and set Device Context Base Address - * and issue Set Address device command. */ static usbd_status -xhci_init_slot(struct usbd_device *dev, uint32_t slot, int route, int rhport) +xhci_init_slot(struct usbd_device *dev, uint32_t slot, uint32_t route, int rhport) { struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus); struct xhci_slot *xs; @@ -2776,26 +2783,22 @@ xhci_init_slot(struct usbd_device *dev, xhci_set_dcba(sc, DMAADDR(&xs->xs_dc_dma, 0), slot); - err = xhci_address_device(sc, xhci_slot_get_icp(sc, xs, 0), slot, - false); - usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD); hexdump("output context", xhci_slot_get_dcv(sc, xs, 0), sc->sc_ctxsz * 2); + xs->xs_idx = slot; + return USBD_NORMAL_COMPLETION; + bad2: - if (err == USBD_NORMAL_COMPLETION) { - xs->xs_idx = slot; - } else { - for (int i = 1; i < dci; i++) { - xhci_ring_free(sc, &xs->xs_ep[i].xe_tr); - memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i])); - } - usb_freemem(&sc->sc_bus, &xs->xs_ic_dma); - bad1: - usb_freemem(&sc->sc_bus, &xs->xs_dc_dma); - xs->xs_idx = 0; + for (int i = 1; i < dci; i++) { + xhci_ring_free(sc, &xs->xs_ep[i].xe_tr); + memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i])); } + usb_freemem(&sc->sc_bus, &xs->xs_ic_dma); + bad1: + usb_freemem(&sc->sc_bus, &xs->xs_dc_dma); + xs->xs_idx = 0; return err; }