Date: Tue, 3 Aug 2010 15:51:47 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 181776 for review Message-ID: <201008031551.o73FplPM003633@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@181776?ac=10 Change 181776 by hselasky@hselasky_laptop001 on 2010/08/03 15:51:26 USB controller (XHCI): - add more XHCI command function wrappers - rename some variables/functions Affected files ... .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#10 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#12 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#4 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#10 (text+ko) ==== @@ -117,7 +117,7 @@ extern struct usb_bus_methods xhci_bus_methods; -void +static void xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) { struct xhci_softc *sc = XHCI_BUS2SC(bus); @@ -184,7 +184,10 @@ } sc->sc_noport = i; - sc->sc_nodev = XHCI_HCS1_DEVSLOT_MAX(temp); + sc->sc_noslot = XHCI_HCS1_DEVSLOT_MAX(temp); + + if (sc->sc_noslot > XHCI_MAX_DEVICES) + sc->sc_noslot = XHCI_MAX_DEVICES; temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); @@ -223,7 +226,7 @@ /* setup number of device slots */ - XWRITE4(sc, oper, XHCI_CONFIG, XHCI_MAX_DEVICES); + XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot); /* Setup interrupter registers */ @@ -277,12 +280,6 @@ XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); - /* - * We only need the 32-lower bits of the command dequeue - * pointer to keep track of the TRBs: - */ - sc->sc_cmd_dp = (uint32_t)addr; - phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].dwTrb2 = htole32(0); phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].dwTrb3 = htole32( @@ -350,7 +347,9 @@ sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = XHCI_MAX_DEVICES; - TAILQ_INIT(&sc->sc_cmd_head); + /* setup command queue mutex and condition varible */ + cv_init(&sc->sc_cmd_cv, "CMDQ"); + sx_init(&sc->sc_cmd_sx, "CMDQ lock"); /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, @@ -362,6 +361,15 @@ } void +xhci_uninit(struct xhci_softc *sc) +{ + usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc); + + cv_destroy(&sc->sc_cmd_cv); + sx_destroy(&sc->sc_cmd_sx); +} + +void xhci_suspend(struct xhci_softc *sc) { /* XXX TODO */ @@ -582,11 +590,20 @@ } static void +xhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb) +{ + if (sc->sc_cmd_addr == trb->qwTrb0) { + sc->sc_cmd_result[0] = trb->dwTrb2; + sc->sc_cmd_result[1] = trb->dwTrb2; + cv_signal(&sc->sc_cmd_cv); + } +} + +static void xhci_interrupt_poll(struct xhci_softc *sc) { struct usb_page_search buf_res; struct xhci_hw_root *phwr; - struct xhci_command *pcmd; uint32_t temp; uint16_t i; uint8_t event; @@ -598,7 +615,7 @@ phwr = buf_res.buffer; - /* 1) Receive any events */ + /* Receive any events */ usb_pc_cpu_invalidate(&sc->sc_hw.root_pc); @@ -622,6 +639,9 @@ case XHCI_TRB_EVENT_TRANSFER: xhci_check_transfer(sc, &phwr->hwr_events[i]); break; + case XHCI_TRB_EVENT_CMD_COMPLETE: + xhci_check_command(sc, &phwr->hwr_events[i]); + break; default: DPRINTF("Received event = 0x%x\n", event); break; @@ -647,94 +667,161 @@ sc->sc_event_idx = i; sc->sc_event_ccs = j; +} + +static usb_error_t +xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb, + uint16_t timeout_ms) +{ + struct usb_page_search buf_res; + struct xhci_hw_root *phwr; + uint64_t addr; + uint32_t temp; + uint8_t i; + uint8_t j; + int err; + + XHCI_CMD_ASSERT_LOCKED(sc); + + /* get hardware root structure */ + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + phwr = buf_res.buffer; - /* 2) Queue any commands */ + /* Queue command */ + + USB_BUS_LOCK(&sc->sc_bus); i = sc->sc_command_idx; j = sc->sc_command_ccs; - /* check if there are any commands on the queue */ - while ((pcmd = TAILQ_FIRST(&sc->sc_cmd_head)) != NULL) { + phwr->hwr_commands[i].qwTrb0 = trb->qwTrb0; + phwr->hwr_commands[i].dwTrb2 = trb->dwTrb2; + + usb_pc_cpu_flush(&sc->sc_hw.root_pc); + + temp = trb->dwTrb3; + + if (j) + temp |= htole32(XHCI_TRB_3_CYCLE_BIT); + else + temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT); + + phwr->hwr_commands[i].dwTrb3 = temp; - k = (phwr->hwr_events[i].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT)) ? 1 : 0; + usb_pc_cpu_flush(&sc->sc_hw.root_pc); - temp = (uint32_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i]; + DPRINTFN(10, "command[%u] = %u\n", i, + XHCI_TRB_3_TYPE_GET(le32toh(temp))); - /* check if we need to wait for XHCI to process commands */ - if ((sc->sc_cmd_dp == temp) && (j == k)) - break; + addr = (uint64_t)buf_res.physaddr + + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i]; + sc->sc_cmd_addr = htole64(addr); - TAILQ_REMOVE(&sc->sc_cmd_head, pcmd, entry); - pcmd->entry.tqe_prev = NULL; + i++; - phwr->hwr_events[i].qwTrb0 = pcmd->trb.qwTrb0; - phwr->hwr_events[i].dwTrb2 = pcmd->trb.dwTrb2; + if (i == (XHCI_MAX_COMMANDS - 1)) { - usb_pc_cpu_flush(&sc->sc_hw.root_pc); + /* update cycle bit of LINK TRB */ - temp = pcmd->trb.dwTrb3; + temp = phwr->hwr_commands[i].dwTrb3; if (j) temp |= htole32(XHCI_TRB_3_CYCLE_BIT); else temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT); - phwr->hwr_events[i].dwTrb3 = temp; + phwr->hwr_commands[i].dwTrb3 = temp; usb_pc_cpu_flush(&sc->sc_hw.root_pc); - XWRITE4(sc, door, XHCI_DOORBELL(0), 0); + i = 0; + j ^= 1; + } + + sc->sc_command_idx = i; + sc->sc_command_ccs = j; + + XWRITE4(sc, door, XHCI_DOORBELL(0), 0); - DPRINTFN(10, "command[%u] = %u\n", i, - XHCI_TRB_3_TYPE_GET(le32toh(temp))); + err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx, + USB_MS_TO_TICKS(timeout_ms)); - i++; + if (err) { + DPRINTFN(0, "Command timeout!\n"); + err = USB_ERR_TIMEOUT; + trb->dwTrb2 = 0; + trb->dwTrb3 = 0; + } else { + temp = le32toh(sc->sc_cmd_result[0]); + if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS) + err = USB_ERR_INVAL; - if (i == (XHCI_MAX_COMMANDS - 1)) { + trb->dwTrb2 = sc->sc_cmd_result[0]; + trb->dwTrb3 = sc->sc_cmd_result[1]; + } - /* update cycle bit of LINK TRB */ + USB_BUS_UNLOCK(&sc->sc_bus); - temp = phwr->hwr_events[i].dwTrb3; + return (err); +} - if (j) - temp |= htole32(XHCI_TRB_3_CYCLE_BIT); - else - temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT); +static usb_error_t +xhci_cmd_enable_slot(struct xhci_softc *sc, uint8_t *pslot) +{ + struct xhci_trb trb; + uint32_t temp; + usb_error_t err; - phwr->hwr_events[i].dwTrb3 = temp; + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + trb.dwTrb3 = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ENABLE_SLOT)); - usb_pc_cpu_flush(&sc->sc_hw.root_pc); + err = xhci_do_command(sc, &trb, 50 /* ms */); + if (err) + goto done; - XWRITE4(sc, door, XHCI_DOORBELL(0), 0); + temp = le32toh(trb.dwTrb3); - i = 0; - j ^= 1; - } - } + *pslot = XHCI_TRB_3_SLOT_GET(temp); - sc->sc_command_idx = i; - sc->sc_command_ccs = j; +done: + return (err); } static usb_error_t -xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb, - uint16_t timeout_ms) +xhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id) { - XXX implement; + struct xhci_trb trb; + uint32_t temp; + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) | + XHCI_TRB_3_SLOT_SET(slot_id); + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); } static usb_error_t -xhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id) +xhci_cmd_set_address(struct xhci_softc *sc, uint64_t input_ctx, + uint8_t bsr, uint8_t slot_id) { struct xhci_trb trb; - uint32_t dword; + uint32_t temp; - trb.qwTrb0 = 0; + trb.qwTrb0 = htole64(input_ctx); trb.dwTrb2 = 0; - dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) | + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ADDRESS_DEVICE) | XHCI_TRB_3_SLOT_SET(slot_id); - trb.dwTrb3 = htole32(dword); + if (bsr) + temp |= XHCI_TRB_3_BSR_BIT; + + trb.dwTrb3 = htole32(temp); return (xhci_do_command(sc, &trb, 50 /* ms */)); } @@ -744,17 +831,17 @@ uint8_t deconfigure, uint8_t slot_id) { struct xhci_trb trb; - uint32_t dword; + uint32_t temp; trb.qwTrb0 = htole64(input_ctx); trb.dwTrb2 = 0; - dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) | + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) | XHCI_TRB_3_SLOT_SET(slot_id); if (deconfigure) - dword |= XHCI_TRB_3_DCEP_BIT; + temp |= XHCI_TRB_3_DCEP_BIT; - trb.dwTrb3 = htole32(dword); + trb.dwTrb3 = htole32(temp); return (xhci_do_command(sc, &trb, 50 /* ms */)); } @@ -764,13 +851,13 @@ uint8_t slot_id) { struct xhci_trb trb; - uint32_t dword; + uint32_t temp; trb.qwTrb0 = htole64(input_ctx); trb.dwTrb2 = 0; - dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) | + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) | XHCI_TRB_3_SLOT_SET(slot_id); - trb.dwTrb3 = htole32(dword); + trb.dwTrb3 = htole32(temp); return (xhci_do_command(sc, &trb, 50 /* ms */)); } @@ -780,18 +867,18 @@ uint8_t ep_id, uint8_t slot_id) { struct xhci_trb trb; - uint32_t dword; + uint32_t temp; trb.qwTrb0 = 0; trb.dwTrb2 = 0; - dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) | + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) | XHCI_TRB_3_SLOT_SET(slot_id) | XHCI_TRB_3_SLOT_SET(ep_id); if (preserve) - dword |= XHCI_TRB_3_PRSV_BIT; + temp |= XHCI_TRB_3_PRSV_BIT; - trb.dwTrb3 = htole32(dword); + trb.dwTrb3 = htole32(temp); return (xhci_do_command(sc, &trb, 50 /* ms */)); } @@ -801,18 +888,18 @@ uint8_t ep_id, uint8_t slot_id) { struct xhci_trb trb; - uint32_t dword; + uint32_t temp; trb.qwTrb0 = 0; trb.dwTrb2 = 0; - dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) | + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) | XHCI_TRB_3_SLOT_SET(slot_id) | XHCI_TRB_3_SLOT_SET(ep_id); if (suspend) - dword |= XHCI_TRB_3_SUSP_EP_BIT; + temp |= XHCI_TRB_3_SUSP_EP_BIT; - trb.dwTrb3 = htole32(dword); + trb.dwTrb3 = htole32(temp); return (xhci_do_command(sc, &trb, 50 /* ms */)); } @@ -821,14 +908,14 @@ xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id) { struct xhci_trb trb; - uint32_t dword; + uint32_t temp; trb.qwTrb0 = 0; trb.dwTrb2 = 0; - dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) | + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) | XHCI_TRB_3_SLOT_SET(slot_id); - trb.dwTrb3 = htole32(dword); + trb.dwTrb3 = htole32(temp); return (xhci_do_command(sc, &trb, 50 /* ms */)); } @@ -1339,7 +1426,7 @@ } static usb_error_t -xhci_set_slot_scratch(struct xhci_softc *sc, uint8_t index, +xhci_set_slot_pointers(struct xhci_softc *sc, uint8_t index, uint64_t dev_addr, uint64_t scratch_addr) { struct usb_page_search buf_res; @@ -1372,7 +1459,7 @@ } static usb_error_t -xhci_configure_endpoint(struct usb_xfer *xfer) +xhci_configure_endpoint(struct usb_xfer *xfer, uint8_t drop) { struct usb_page_search buf_inp; struct usb_page_search buf_ep; @@ -1383,6 +1470,7 @@ struct usb_device *udev; uint64_t addr; uint32_t temp; + uint32_t mask; uint8_t index; uint8_t epno; uint8_t k; @@ -1394,7 +1482,7 @@ udev = xfer->xroot->udev; - index = udev->device_index; + index = udev->controller_slot_id; edesc = xfer->endpoint->edesc; @@ -1410,9 +1498,18 @@ pinp = buf_inp.buffer; - XXX; - pinp->ctx_input.dwInCtx0 |= htole32(0xFFFFFFFC); - pinp->ctx_input.dwInCtx1 &= htole32(0x1); + mask = 1U << epno; + + if (drop) { + mask &= 0xFFFFFFFC; + pinp->ctx_input.dwInCtx0 = htole32(mask); + pinp->ctx_input.dwInCtx1 = 0; + } else { + if (mask & 2) + mask |= 1; + pinp->ctx_input.dwInCtx0 = 0; + pinp->ctx_input.dwInCtx1 = htole32(mask); + } temp = XHCI_EPCTX_0_EPSTATE_SET(0) | XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | @@ -1461,22 +1558,25 @@ pinp->ctx_ep[epno - 1].dwEpCtx1 = htole32(temp); - pepext->trb_ccs = 1; - pepext->trb_index = 0; - pepext->trb_halted = 0; + if (drop == 0) { + + pepext->trb_ccs = 1; + pepext->trb_index = 0; + pepext->trb_halted = 0; - for (k = 0; k != XHCI_MAX_TRANSFERS; k++) - pepext->trb[k].dwTrb3 = 0; + for (k = 0; k != XHCI_MAX_TRANSFERS; k++) + pepext->trb[k].dwTrb3 = 0; - usb_pc_cpu_flush(pepext->page_cache); + usb_pc_cpu_flush(pepext->page_cache); + } addr = XHCI_EPCTX_2_DCS_SET(1) | (buf_ep.physaddr + (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0]); pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(addr); - temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET() | - XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(); + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(xfer->max_frame_size) | + XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(xfer->max_frame_size); pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp); @@ -1563,7 +1663,7 @@ hubdev = udev->parent_hs_hub; if (hubdev != NULL) { - temp |= XHCI_SCTX_2_TT_HUB_SID_SET(hubdev->device_index); + temp |= XHCI_SCTX_2_TT_HUB_SID_SET(hubdev->controller_slot_id); temp |= XHCI_SCTX_2_TT_PORT_NUM_SET(hubdev->port_no); } @@ -1585,10 +1685,8 @@ usb_pc_cpu_flush(pcinp); - xhci_set_slot_scratch(sc, udev->device_index, buf_dev.physaddr, + xhci_set_slot_pointers(sc, udev->controller_slot_id, buf_dev.physaddr, buf_inp.physaddr + (uintptr_t)&((struct xhci_input_dev_ctx *)0)->ctx_sp_buf_ptr[0]); - - XXX_cmd_config(); } static usb_error_t @@ -1600,7 +1698,7 @@ uint8_t i; uint8_t index; - index = udev->device_index; + index = udev->controller_slot_id; pc = &sc->sc_hw.devs[index].device_pc; pg = &sc->sc_hw.devs[index].device_pg; @@ -1656,9 +1754,9 @@ uint8_t index; uint8_t i; - index = udev->device_index; + index = udev->controller_slot_id; - xhci_set_slot_scratch(sc, index, 0, 0); + xhci_set_slot_pointers(sc, index, 0, 0); pc = &sc->sc_hw.devs[index].device_pc; @@ -1694,7 +1792,7 @@ epno |= UE_DIR_IN; epno = XHCI_EPNO2EPID(epno); - index = xfer->xroot->udev->device_index; + index = xfer->xroot->udev->controller_slot_id; pc = &sc->sc_hw.devs[index].endpoint_pc; @@ -1720,7 +1818,7 @@ epno |= UE_DIR_IN; epno = XHCI_EPNO2EPID(epno); - index = xfer->xroot->udev->device_index; + index = xfer->xroot->udev->controller_slot_id; XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0)); } @@ -1987,7 +2085,7 @@ .bLength = sizeof(xhci_bosd.usbdcd), .bDescriptorType = UDESC_DEVICE_CAPABILITY, .bDevCapabilityType = 3, - .bmAttributes = XXX, + .bmAttributes = 0, /* XXX */ HSETW(.wSpeedsSupported, 0x000C), .bFunctionalitySupport = 8, .bU1DevExitLat = 255, /* dummy - not used */ @@ -1998,7 +2096,7 @@ .bDescriptorType = 1, .bDevCapabilityType = 4, .bReserved = 0, - .bContainerID = XXX, + .bContainerID = 0, /* XXX */ }, }; @@ -2555,6 +2653,73 @@ xfer->flags_int.curr_dma_set = 1; goto alloc_dma_set; } + + if ((parm->buf != NULL) && (parm->err == 0)) { + struct usb_page_search buf_dev; + struct usb_page_search buf_inp; + struct usb_device *udev; + struct xhci_endpoint_ext *pepext; + struct xhci_dev_ctx *pdctx; + struct usb_page_cache *pcdev; + struct usb_page_cache *pcinp; + usb_error_t err; + uint32_t temp; + uint8_t index; + + pepext = xhci_get_endpoint_ext(xfer); + udev = xfer->xroot->udev; + index = udev->controller_slot_id; + + pcdev = &sc->sc_hw.devs[index].device_pc; + pcinp = &sc->sc_hw.devs[index].input_pc; + + usbd_get_page(pcdev, 0, &buf_dev); + usbd_get_page(pcinp, 0, &buf_inp); + + pdctx = buf_dev.buffer; + + XHCI_CMD_LOCK(sc); + + err = xhci_configure_endpoint(xfer, 1); + if (err == 0) + err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index); + if (err == 0) + err = xhci_configure_endpoint(xfer, 0); + if (err == 0) + err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index); + + if (err != 0) + DPRINTFN(0, "Could not configure endpoint\n"); + + if (xfer->flags_int.control_xfr) { + + if (udev->address != 0) { + err = xhci_cmd_set_address(sc, buf_inp.physaddr, 0, index); + if (err == 0) { + usb_pc_cpu_invalidate(pcdev); + + temp = le32toh(pdctx->ctx_slot.dwSctx3); + + /* update address */ + udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp); + + if (udev->address == 0) + DPRINTFN(0, "XHCI returned address zero!\n"); + } + } else { + err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1, index); + + if (err != 0) + err = xhci_cmd_reset_dev(sc, index); + } + + if (err != 0) + DPRINTFN(0, "Could not set address\n"); + } + XHCI_CMD_UNLOCK(sc); + + parm->err = err; + } } static void @@ -2578,28 +2743,75 @@ /* not supported */ return; } - if (udev->device_index != sc->sc_addr) { + if (udev->parent_hub != NULL) + ep->methods = &xhci_device_generic_methods; +} + +static void +xhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep) +{ + +} + +static usb_error_t +xhci_device_init(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + usb_error_t err; + uint8_t temp; + + /* no init for root HUB */ + if (udev->parent_hub == NULL) + return (0); + + XHCI_CMD_LOCK(sc); + + /* set invalid default */ + + udev->controller_slot_id = sc->sc_noslot; + + /* try to get a new slot ID from the XHCI */ + + err = xhci_cmd_enable_slot(sc, &temp); - ep->methods = &xhci_device_generic_methods; + if (err) { + XHCI_CMD_UNLOCK(sc); + return (err); + } - if ((udev->speed != USB_SPEED_HIGH) && - ((udev->hs_hub_addr == 0) || - (udev->hs_port_no == 0) || - (udev->parent_hs_hub == NULL) || - (udev->parent_hs_hub->hub == NULL))) { - /* We need a transaction translator */ - goto done; - } + if (temp >= sc->sc_noslot) { + XHCI_CMD_UNLOCK(sc); + return (USB_ERR_INVAL); } -done: - return; + + /* store slot ID for later reference */ + + udev->controller_slot_id = temp; + + err = xhci_alloc_device_ext(udev); + + XHCI_CMD_UNLOCK(sc); + + return (err); } static void -xhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep) +xhci_device_uninit(struct usb_device *udev) { + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + /* no init for root HUB */ + if (udev->parent_hub == NULL) + return; + XHCI_CMD_LOCK(sc); + + if (udev->controller_slot_id < sc->sc_noslot) + xhci_cmd_disable_slot(sc, udev->controller_slot_id); + + xhci_free_device_ext(udev); + + XHCI_CMD_UNLOCK(sc); } static void @@ -2607,9 +2819,9 @@ { /* * Wait until the hardware has finished any possible use of - * the transfer descriptor(s) and QH + * the transfer descriptor(s) */ - *pus = (188); /* microseconds */ + *pus = 2048; /* microseconds */ } static void @@ -2649,6 +2861,8 @@ .xfer_setup = xhci_xfer_setup, .xfer_unsetup = xhci_xfer_unsetup, .get_dma_delay = xhci_get_dma_delay, + .device_init = xhci_device_init, + .device_uninit = xhci_device_uninit, .device_resume = xhci_device_resume, .device_suspend = xhci_device_suspend, .set_hw_power = xhci_set_hw_power, ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#12 (text+ko) ==== @@ -159,10 +159,6 @@ struct xhci_endp_ctx ctx_epN[XHCI_MAX_ENDPOINTS - 1]; } __aligned(XHCI_DEV_CTX_ALIGN); -struct xhci_dev_endpoint_trbs { - struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS]; -}; - struct xhci_stream_ctx { volatile uint64_t qwSctx0; #define XHCI_SCTX_0_DCS_GET(x) ((x) & 0x1) @@ -210,6 +206,7 @@ #define XHCI_TRB_3_BEI_BIT (1U << 9) #define XHCI_TRB_3_DCEP_BIT (1U << 9) #define XHCI_TRB_3_PRSV_BIT (1U << 9) +#define XHCI_TRB_3_BSR_BIT (1U << 9) #define XHCI_TRB_3_TRT_MASK (3U << 16) #define XHCI_TRB_3_TRT_NONE (0U << 16) #define XHCI_TRB_3_TRT_OUT (2U << 16) @@ -300,6 +297,10 @@ #define XHCI_TRB_ERROR_SPLIT_XACT 0x24 }; +struct xhci_dev_endpoint_trbs { + struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS]; +}; + #define XHCI_TD_PAGE_NBUF 5 /* units */ #define XHCI_TD_PAGE_SIZE 4096 /* bytes */ #define XHCI_TD_PAYLOAD_MAX (XHCI_TD_PAGE_SIZE * (XHCI_TD_PAGE_NBUF - 1)) @@ -342,8 +343,6 @@ }; struct xhci_endpoint_ext { - struct xhci_command ep_stop_cmd; - struct xhci_command ep_config_cmd; struct xhci_trb *trb; struct usb_page_cache *page_cache; uint64_t physaddr; @@ -404,7 +403,8 @@ union xhci_hub_desc sc_hub_desc; - TAILQ_HEAD(, xhci_command) sc_cmd_head; + struct cv sc_cmd_cv; + struct sx sc_cmd_sx; struct usb_device *sc_devices[XHCI_MAX_DEVICES]; struct resource *sc_io_res; @@ -415,8 +415,10 @@ bus_space_tag_t sc_io_tag; bus_space_handle_t sc_io_hdl; + uint64_t sc_cmd_addr; /* current pending command */ + uint32_t sc_cmd_result[2]; /* result of command */ + uint32_t sc_cmd; /* copy of cmd register */ - uint32_t sc_cmd_dp; /* copy of command dequeue pointer */ uint32_t sc_exit_lat_max; /* worst case exit latency */ uint32_t sc_oper_off; /* offset to operational registers */ @@ -431,7 +433,7 @@ uint8_t sc_event_ccs; uint8_t sc_command_ccs; - uint8_t sc_nodev; /* number of devices on root HUB */ + uint8_t sc_noslot; /* number of XHCI device slots */ uint8_t sc_noport; /* number of ports on root HUB */ uint8_t sc_noscratch; /* number of scratch pages */ uint8_t sc_addr; /* root HUB device address */ @@ -442,14 +444,18 @@ }; +#define XHCI_CMD_LOCK(sc) sx_xlock(&sc->sc_cmd_sx) +#define XHCI_CMD_UNLOCK(sc) sx_xunlock(&sc->sc_cmd_sx) +#define XHCI_CMD_ASSERT_LOCKED(sc) sx_assert(&sc->sc_cmd_sx, SA_LOCKED) + /* prototypes */ void xhci_suspend(struct xhci_softc *); void xhci_resume(struct xhci_softc *); void xhci_shutdown(struct xhci_softc *); usb_error_t xhci_init(struct xhci_softc *, device_t); +void xhci_uninit(struct xhci_softc *); usb_error_t xhci_start_controller(struct xhci_softc *); -void xhci_iterate_hw_softc(struct usb_bus *, usb_bus_mem_sub_cb_t *); usb_error_t xhci_halt_controller(struct xhci_softc *); void xhci_interrupt(struct xhci_softc *); ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#4 (text+ko) ==== @@ -268,7 +268,8 @@ sc->sc_io_res); sc->sc_io_res = NULL; } - usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc); + + xhci_uninit(sc); return (0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008031551.o73FplPM003633>