From owner-p4-projects@FreeBSD.ORG Wed Aug 11 18:26:06 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id C2C42106572A; Wed, 11 Aug 2010 18:26:03 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5B0741065EB7 for ; Wed, 11 Aug 2010 18:26:01 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:4f8:fff6::2d]) by mx1.freebsd.org (Postfix) with ESMTP id E85028FC14 for ; Wed, 11 Aug 2010 18:25:58 +0000 (UTC) Received: from skunkworks.freebsd.org (localhost [127.0.0.1]) by skunkworks.freebsd.org (8.14.4/8.14.4) with ESMTP id o7BIPw9G084048 for ; Wed, 11 Aug 2010 18:25:58 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.4/8.14.4/Submit) id o7BIPwvV084044 for perforce@freebsd.org; Wed, 11 Aug 2010 18:25:58 GMT (envelope-from hselasky@FreeBSD.org) Date: Wed, 11 Aug 2010 18:25:58 GMT Message-Id: <201008111825.o7BIPwvV084044@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 182149 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Aug 2010 18:26:06 -0000 http://p4web.freebsd.org/@@182149?ac=10 Change 182149 by hselasky@hselasky_laptop001 on 2010/08/09 19:48:33 USB controller (XHCI): - fix problem about short USB transfers (compute correct remainder). - correctly initialise USB HUB fields in slot context - correct interrupt endpoint intervals (we round down the intervals). - add support for USB 2.0 device suspend and resume - add new callback function to correctly update the current XHCI device state. - at this point the XHCI driver works with any kind of USB device (HS/LS/FS and SS) - have tested ISOC, BULK, CONTROL and INTERRUPT transfer types. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#23 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#20 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#23 (text+ko) ==== @@ -122,10 +122,9 @@ static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, struct usb_endpoint_descriptor *); static usb_proc_callback_t xhci_configure_msg; static usb_error_t xhci_configure_device(struct usb_device *); -static usb_error_t xhci_configure_endpoint(struct usb_device *, struct usb_endpoint_descriptor *, uint64_t, uint16_t, uint8_t, uint8_t, uint16_t, uint16_t); +static usb_error_t xhci_configure_endpoint(struct usb_device *, struct usb_endpoint_descriptor *, uint64_t, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t); static usb_error_t xhci_configure_mask(struct usb_device *, uint32_t, uint8_t); static usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *, uint64_t, uint8_t); -static usb_error_t xhci_cmd_reset_dev(struct xhci_softc *, uint8_t); extern struct usb_bus_methods xhci_bus_methods; @@ -637,6 +636,7 @@ static void xhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb) { + int64_t offset; uint64_t td_event; uint32_t temp; uint32_t remainder; @@ -688,18 +688,37 @@ td = xfer->td_transfer_cache; - DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx +/- 16)\n", + DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n", (long long)td_event, (long long)td->td_self, - (long long)td->td_event_last); + (long long)td->td_self + sizeof(td->td_trb)); + + /* + * NOTE: Some XHCI implementations might not trigger + * an event on the last LINK TRB so we need to + * consider both the last and second last event + * address as conditions for a successful transfer. + * + * NOTE: We assume that the XHCI will only trigger one + * event per chain of TRBs. + */ + + offset = td_event - td->td_self; - if ((td_event == td->td_event_last) || - (td_event == (td->td_event_last - 16)) || - (halted && (td_event >= td->td_self) && - (td_event <= td->td_event_last))) { + if ((offset >= 0) && + (offset < sizeof(td->td_trb))) { usb_pc_cpu_invalidate(td->page_cache); + /* compute rest of remainder, if any */ + for (i = (offset / 16) + 1; i < td->ntrb; i++) { + temp = le32toh(td->td_trb[i].dwTrb2); + remainder += XHCI_TRB_2_BYTES_GET(temp); + } + + DPRINTFN(5, "New remainder: %u\n", remainder); + + /* clear isochronous transfer errors */ if (xfer->flags_int.isochronous_xfr) { if (halted) { halted = 0; @@ -1073,27 +1092,11 @@ XHCI_CMD_LOCK(sc); switch (hdev->state) { - case XHCI_ST_ADDRESSED: - case XHCI_ST_CONFIGURED: - if (udev->address == 0) { - err = xhci_cmd_reset_dev(sc, index); - - if (err != 0) { - DPRINTF("Device reset failed\n"); - } - } else { - err = 0; - break; - } - case XHCI_ST_DEFAULT: + case XHCI_ST_ENABLED: hdev->state = XHCI_ST_ENABLED; - /* FALLTHROUGH */ - - case XHCI_ST_ENABLED: - /* set configure mask to slot and EP0 */ xhci_configure_mask(udev, 3, 0); @@ -1124,7 +1127,7 @@ &udev->ctrl_ep_desc); err = xhci_configure_endpoint(udev, &udev->ctrl_ep_desc, pepext->physaddr, - 0, 1, 1, mps, mps); + 0, 1, 1, 0, mps, mps); if (err != 0) { DPRINTF("Could not configure default endpoint\n"); @@ -1138,7 +1141,8 @@ (address == 0), index); if (err != 0) { - DPRINTF("Could not set address\n"); + DPRINTF("Could not set address " + "for slot %u.\n", index); if (address != 0) break; } @@ -1152,27 +1156,10 @@ /* update device state to new value */ - if (address != 0) { - - /* we skip the addressed state */ - hdev->state = XHCI_ST_CONFIGURED; - - xhci_configure_mask(udev, 1, 0); - - err = xhci_configure_device(udev); - if (err != 0) { - DPRINTF("Could not configure device\n"); - break; - } - - err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); - if (err != 0) { - DPRINTF("Could not evaluate device context\n"); - break; - } - } else { + if (address != 0) + hdev->state = XHCI_ST_ADDRESSED; + else hdev->state = XHCI_ST_DEFAULT; - } break; default: @@ -1399,7 +1386,6 @@ struct xhci_td *td; struct xhci_td *td_next; struct xhci_td *td_alt_next; - uint64_t addr; uint32_t buf_offset; uint32_t average; uint32_t len_old; @@ -1553,11 +1539,20 @@ XHCI_TRB_3_TYPE_SET(temp->trb_type) | XHCI_TRB_3_FRID_SET(temp->isoc_frame); - if (temp->direction == UE_DIR_IN) + if (temp->direction == UE_DIR_IN) { dword |= XHCI_TRB_3_DIR_IN; - if (average == 0) - dword |= XHCI_TRB_3_IDT_BIT; + /* + * NOTE: Only the SETUP stage should + * use the IDT bit. Else transactions + * can be sent using the wrong data + * toggle value. + */ + + if ((temp->trb_type != XHCI_TRB_TYPE_SETUP_STAGE) && + (temp->trb_type != XHCI_TRB_TYPE_STATUS_STAGE)) + dword |= XHCI_TRB_3_ISP_BIT; + } td->td_trb[x].dwTrb3 = htole32(dword); @@ -1578,12 +1573,6 @@ DPRINTF("NTRB=%u\n", x); - /* compute event pointer */ - - addr = td->td_self; - addr += x * sizeof(struct xhci_trb); - td->td_event_last = addr; - /* fill out link TRB */ if (td_next != NULL) { @@ -1629,7 +1618,7 @@ goto restart; } - if (temp->multishort == 0) { + if (temp->multishort != 0) { /* remove chain bit and clear TD SIZE - end of frame */ td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); @@ -1656,6 +1645,7 @@ temp.last_frame = 0; temp.offset = 0; temp.multishort = xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr || xfer->flags_int.short_frames_ok; /* toggle the DMA set we are using */ @@ -1867,23 +1857,6 @@ usb_pc_cpu_flush(&sc->sc_hw.ctx_pc); } -static uint8_t -xhci_log2(uint32_t x) -{ - uint8_t retval; - - retval = 0; - while (1) { - if (x == 1) - break; - x >>= 2; - if (x == 0) - break; - retval++; - } - return (retval); -} - static usb_error_t xhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop) { @@ -1913,7 +1886,7 @@ xhci_configure_endpoint(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, uint64_t ring_addr, uint16_t interval, uint8_t max_packet_count, uint8_t mult, - uint16_t max_packet_size, uint16_t max_frame_size) + uint8_t fps_shift, uint16_t max_packet_size, uint16_t max_frame_size) { struct usb_page_search buf_inp; struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); @@ -1921,7 +1894,7 @@ uint32_t temp; uint8_t index; uint8_t epno; - uint8_t k; + uint8_t type; index = udev->controller_slot_id; @@ -1930,8 +1903,9 @@ pinp = buf_inp.buffer; epno = edesc->bEndpointAddress; + type = edesc->bmAttributes & UE_XFERTYPE; - if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) + if (type == UE_CONTROL) epno |= UE_DIR_IN; epno = XHCI_EPNO2EPID(epno); @@ -1947,21 +1921,38 @@ if (mult == 0) return (USB_ERR_BAD_BUFSIZE); - mult--; - temp = XHCI_EPCTX_0_EPSTATE_SET(0) | XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | XHCI_EPCTX_0_LSA_SET(0); - switch (edesc->bmAttributes & UE_XFERTYPE) { + switch (udev->speed) { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + /* 1ms -> 125us */ + fps_shift += 3; + break; + default: + break; + } + + switch (type) { case UE_INTERRUPT: - k = xhci_log2(interval) + 3; - temp |= XHCI_EPCTX_0_IVAL_SET(k); + if (fps_shift > 3) + fps_shift--; + temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); break; case UE_ISOCHRONOUS: - if (udev->speed == USB_SPEED_SUPER) { - temp |= XHCI_EPCTX_0_MULT_SET(mult); + temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); + + switch (udev->speed) { + case USB_SPEED_SUPER: + if (mult > 3) + mult = 3; + temp |= XHCI_EPCTX_0_MULT_SET(mult - 1); max_packet_count /= mult; + break; + default: + break; } break; default: @@ -1976,11 +1967,11 @@ XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size); if ((udev->parent_hs_hub != NULL) || (udev->address != 0)) { - if ((edesc->bmAttributes & UE_XFERTYPE) != UE_ISOCHRONOUS) + if (type != UE_ISOCHRONOUS) temp |= XHCI_EPCTX_1_CERR_SET(3); } - switch (edesc->bmAttributes & UE_XFERTYPE) { + switch (type) { case UE_CONTROL: temp |= XHCI_EPCTX_1_EPTYPE_SET(4); break; @@ -1995,7 +1986,8 @@ break; } - if (edesc->bEndpointAddress & UE_DIR_IN) + /* check for IN direction */ + if (epno & 1) temp |= XHCI_EPCTX_1_EPTYPE_SET(4); pinp->ctx_ep[epno - 1].dwEpCtx1 = htole32(temp); @@ -2004,19 +1996,17 @@ pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(ring_addr); - temp = 0; - switch (edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: case UE_ISOCHRONOUS: - temp |= XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size); - temp |= XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX); + temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size); + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX); break; case UE_CONTROL: - temp |= XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); break; default: - temp |= XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX); + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX); break; } @@ -2048,7 +2038,8 @@ xfer->endpoint->edesc, pepext->physaddr, xfer->interval, xfer->max_packet_count, (ecomp != NULL) ? (ecomp->bmAttributes & 3) + 1 : 1, - xfer->max_packet_size, xfer->max_frame_size)); + usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size, + xfer->max_frame_size)); } static usb_error_t @@ -2135,7 +2126,7 @@ break; } - is_hub = (udev->hub != NULL) && + is_hub = (sc->sc_hw.devs[index].nports != 0) && ((udev->speed == USB_SPEED_SUPER) || (udev->speed = USB_SPEED_HIGH)); @@ -2147,7 +2138,7 @@ temp = XHCI_SCTX_1_RH_PORT_SET(rh_port); if (is_hub) - temp |= XHCI_SCTX_1_NUM_PORTS_SET(udev->hub->nports); + temp |= XHCI_SCTX_1_NUM_PORTS_SET(sc->sc_hw.devs[index].nports); switch (udev->speed) { case USB_SPEED_SUPER: @@ -2170,16 +2161,24 @@ temp = XHCI_SCTX_2_IRQ_TARGET_SET(0); - if (is_hub) { - if (udev->speed == USB_SPEED_HIGH) - temp |= XHCI_SCTX_2_TT_THINK_TIME_SET(3); - } + if (is_hub) + temp |= XHCI_SCTX_2_TT_THINK_TIME_SET(sc->sc_hw.devs[index].tt); hubdev = udev->parent_hs_hub; - if (hubdev != NULL) { - temp |= XHCI_SCTX_2_TT_HUB_SID_SET(hubdev->controller_slot_id); - temp |= XHCI_SCTX_2_TT_PORT_NUM_SET(hubdev->port_no); + /* check if we should activate the transaction translator */ + switch (udev->speed) { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + if (hubdev != NULL) { + temp |= XHCI_SCTX_2_TT_HUB_SID_SET( + hubdev->controller_slot_id); + temp |= XHCI_SCTX_2_TT_PORT_NUM_SET( + udev->hs_port_no); + } + break; + default: + break; } pinp->ctx_slot.dwSctx2 = htole32(temp); @@ -2342,7 +2341,8 @@ epno = XHCI_EPNO2EPID(epno); index = xfer->xroot->udev->controller_slot_id; - XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0)); + if (xfer->xroot->udev->flags.self_suspended == 0) + XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0)); } static void @@ -2536,8 +2536,15 @@ static void xhci_device_generic_open(struct usb_xfer *xfer) { - if (xfer->flags_int.isochronous_xfr) - usb_hs_bandwidth_alloc(xfer); + if (xfer->flags_int.isochronous_xfr) { + switch (xfer->xroot->udev->speed) { + case USB_SPEED_FULL: + break; + default: + usb_hs_bandwidth_alloc(xfer); + break; + } + } } static void @@ -2547,8 +2554,15 @@ xhci_device_done(xfer, USB_ERR_CANCELLED); - if (xfer->flags_int.isochronous_xfr) - usb_hs_bandwidth_free(xfer); + if (xfer->flags_int.isochronous_xfr) { + switch (xfer->xroot->udev->speed) { + case USB_SPEED_FULL: + break; + default: + usb_hs_bandwidth_free(xfer); + break; + } + } } static void @@ -3237,10 +3251,6 @@ xfer->flags_int.curr_dma_set = 1; goto alloc_dma_set; } - - /* make sure we catch any set address updates */ - if (parm->buf != NULL) - xhci_set_address(xfer->xroot->udev, NULL, 0); } static usb_error_t @@ -3249,7 +3259,6 @@ struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); struct usb_page_search buf_dev; struct usb_page_search buf_inp; - struct usb_device *hub; struct usb_device *udev; struct xhci_endpoint_ext *pepext; struct usb_endpoint_descriptor *edesc; @@ -3288,46 +3297,6 @@ XHCI_CMD_LOCK(sc); - /* figure out if a parent HUB should be configured */ - - hub = udev->parent_hs_hub; - if (hub == NULL) { - hub = udev->parent_hub; - if (hub == NULL) - hub = NULL; - else if (hub->parent_hub == NULL) - hub = NULL; - else if (hub->speed != USB_SPEED_SUPER) - hub = NULL; - } else { - /* check for root HUB */ - if (hub->parent_hub == NULL) - hub = NULL; - } - - if (hub != NULL) { - - struct usb_page_search buf_hub; - - DPRINTF("Configure HUB\n"); - - usbd_get_page(&sc->sc_hw.devs[ - hub->controller_slot_id].input_pc, 0, &buf_hub); - - /* set configure mask to slot only */ - xhci_configure_mask(hub, 1, 0); - - /* configure input slot context structure */ - err = xhci_configure_device(hub); - - /* update context */ - if (err == 0) - err = xhci_cmd_evaluate_ctx(sc, buf_hub.physaddr, index); - - if (err) - DPRINTF("Could not update parent HS HUB context.\n"); - } - /* configure endpoint */ err = xhci_configure_endpoint_by_xfer(xfer); @@ -3625,25 +3594,61 @@ static void xhci_device_resume(struct usb_device *udev) { + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + uint8_t index; + uint8_t n; + DPRINTF("\n"); + /* check for root HUB */ + if (udev->parent_hub == NULL) + return; + + index = udev->controller_slot_id; + + XHCI_CMD_LOCK(sc); + + /* blindly resume all endpoints */ + USB_BUS_LOCK(udev->bus); - /* start endpoint */ + for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) + XWRITE4(sc, door, XHCI_DOORBELL(index), n | XHCI_DB_SID_SET(0)); USB_BUS_UNLOCK(udev->bus); + + XHCI_CMD_UNLOCK(sc); } static void xhci_device_suspend(struct usb_device *udev) { + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + uint8_t index; + uint8_t n; + usb_error_t err; + DPRINTF("\n"); - USB_BUS_LOCK(udev->bus); + /* check for root HUB */ + if (udev->parent_hub == NULL) + return; + + index = udev->controller_slot_id; + + XHCI_CMD_LOCK(sc); + + /* blindly suspend all endpoints */ - /* stop endpoint */ + for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) { + err = xhci_cmd_stop_ep(sc, 1, n, index); + if (err != 0) { + DPRINTF("Failed to suspend endpoint " + "%u on slot %u (ignored).\n", n, index); + } + } - USB_BUS_UNLOCK(udev->bus); + XHCI_CMD_UNLOCK(sc); } static void @@ -3652,6 +3657,89 @@ DPRINTF("\n"); } +static void +xhci_device_state_change(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct usb_page_search buf_inp; + usb_error_t err; + uint8_t index; + + /* check for root HUB */ + if (udev->parent_hub == NULL) + return; + + index = udev->controller_slot_id; + + DPRINTF("\n"); + + if (usb_get_device_state(udev) == USB_STATE_CONFIGURED) { + err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, + &sc->sc_hw.devs[index].tt); + if (err != 0) + sc->sc_hw.devs[index].nports = 0; + } + + XHCI_CMD_LOCK(sc); + + switch (usb_get_device_state(udev)) { + case USB_STATE_POWERED: + if (sc->sc_hw.devs[index].state == XHCI_ST_DEFAULT) + break; + + sc->sc_hw.devs[index].state = XHCI_ST_DEFAULT; + + err = xhci_cmd_reset_dev(sc, index); + + if (err != 0) { + DPRINTF("Device reset failed " + "for slot %u.\n", index); + } + break; + + case USB_STATE_ADDRESSED: + if (sc->sc_hw.devs[index].state == XHCI_ST_ADDRESSED) + break; + + sc->sc_hw.devs[index].state = XHCI_ST_ADDRESSED; + + err = xhci_cmd_configure_ep(sc, 0, 1, index); + + if (err) { + DPRINTF("Failed to deconfigure " + "slot %u.\n", index); + } + break; + + case USB_STATE_CONFIGURED: + if (sc->sc_hw.devs[index].state == XHCI_ST_CONFIGURED) + break; + + sc->sc_hw.devs[index].state = XHCI_ST_CONFIGURED; + + usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); + + xhci_configure_mask(udev, 1, 0); + + err = xhci_configure_device(udev); + if (err != 0) { + DPRINTF("Could not configure device " + "at slot %u.\n", index); + } + + err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); + if (err != 0) { + DPRINTF("Could not evaluate device " + "context at slot %u.\n", index); + } + break; + + default: + break; + } + XHCI_CMD_UNLOCK(sc); +} + struct usb_bus_methods xhci_bus_methods = { .endpoint_init = xhci_ep_init, .endpoint_uninit = xhci_ep_uninit, @@ -3668,4 +3756,5 @@ .start_dma_delay = xhci_start_dma_delay, .set_address = xhci_set_address, .clear_stall = xhci_ep_clear_stall, + .device_state_change = xhci_device_state_change, }; ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#20 (text+ko) ==== @@ -314,7 +314,6 @@ * Extra information needed: */ uint64_t td_self; - uint64_t td_event_last; struct xhci_td *next; struct xhci_td *alt_next; struct xhci_td *obj_next; @@ -378,6 +377,9 @@ struct xhci_endpoint_ext endp[XHCI_MAX_ENDPOINTS]; uint8_t state; + uint8_t nports; + uint8_t tt; + uint8_t reserved; }; struct xhci_hw_softc {