Date: Sun, 8 Aug 2010 12:41:42 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 182075 for review Message-ID: <201008081241.o78Cfg3h090927@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@182075?ac=10 Change 182075 by hselasky@hselasky_laptop001 on 2010/08/08 12:41:08 USB controller (XHCI): - fixes for double buffering and endpoint configuration. - correct some wrong definitions in xhci.h Affected files ... .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#16 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#18 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#16 (text+ko) ==== @@ -121,11 +121,8 @@ static void xhci_free_device_ext(struct usb_device *udev); 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_reset_endpoint(struct usb_xfer *); 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, uint16_t, uint16_t); -static usb_error_t xhci_configure_endpoint_by_xfer(struct usb_xfer *); -static usb_error_t xhci_set_address(struct usb_device *, struct mtx *, uint16_t); static usb_error_t xhci_configure_mask(struct usb_device *, uint32_t, uint8_t); extern struct usb_bus_methods xhci_bus_methods; @@ -628,6 +625,7 @@ err = xhci_generic_done_sub(xfer); done: + /* transfer is complete */ xhci_device_done(xfer, err); } @@ -637,14 +635,14 @@ static void xhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb) { - struct usb_xfer *xfer; - struct xhci_td *td; - struct xhci_endpoint_ext *pepext; uint64_t td_event; uint32_t temp; uint32_t remainder; uint8_t status; uint8_t halted; + uint8_t epno; + uint8_t index; + uint8_t i; /* decode TRB */ td_event = le64toh(trb->qwTrb0); @@ -653,29 +651,44 @@ remainder = XHCI_TRB_2_REM_GET(temp); status = XHCI_TRB_2_ERROR_GET(temp); + temp = le32toh(trb->dwTrb3); + epno = XHCI_TRB_3_EP_GET(temp) + 1; + index = XHCI_TRB_3_SLOT_GET(temp); + /* check if error means halted */ halted = (status != XHCI_TRB_ERROR_SHORT_PKT) && (status != XHCI_TRB_ERROR_SUCCESS); - DPRINTF("remainder=%u status=%u\n", remainder, status); + DPRINTF("slot=%u epno=%u remainder=%u status=%u\n", + index, epno, remainder, status); + + if (index > sc->sc_noslot) { + DPRINTF("Invalid slot.\n"); + return; + } + + epno++; + + if (epno >= XHCI_MAX_ENDPOINTS) { + DPRINTF("Invalid endpoint.\n"); + return; + } /* try to find the USB transfer that generated the event */ - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { + for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) { + struct usb_xfer *xfer; + struct xhci_td *td; + struct xhci_endpoint_ext *pepext; - /* check if transfer is cancelling */ - if (xfer->flags_int.did_dma_delay) - continue; + pepext = &sc->sc_hw.devs[index].endp[epno]; - pepext = xhci_get_endpoint_ext(xfer->xroot->udev, - xfer->endpoint->edesc); - - /* check if endpoint is halted */ - if (pepext->trb_halted != 0) + xfer = pepext->xfer[i]; + if (xfer == NULL) continue; td = xfer->td_transfer_cache; - DPRINTF("0x%08llx == (0x%08llx .. 0x%08llx)\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); @@ -684,13 +697,15 @@ (halted && (td_event >= td->td_self) && (td_event < td->td_event_last))) { - struct xhci_endpoint_ext *pepext; + usb_pc_cpu_invalidate(td->page_cache); - pepext = xhci_get_endpoint_ext(xfer->xroot->udev, - xfer->endpoint->edesc); + if (xfer->flags_int.isochronous_xfr) { + if (halted) { + halted = 0; + remainder = td->len; + } + } - usb_pc_cpu_invalidate(td->page_cache); - /* "td->remainder" is verified later */ td->remainder = remainder; td->status = status; @@ -1126,7 +1141,6 @@ err = USB_ERR_IOERROR; break; } - XHCI_CMD_UNLOCK(sc); if (mtx != NULL) @@ -1190,7 +1204,7 @@ trb.dwTrb2 = 0; 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); + XHCI_TRB_3_EP_SET(ep_id); if (preserve) temp |= XHCI_TRB_3_PRSV_BIT; @@ -1201,6 +1215,28 @@ } static usb_error_t +xhci_cmd_set_tr_dequeue_ptr(struct xhci_softc *sc, uint64_t dequeue_ptr, + uint16_t stream_id, uint8_t ep_id, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = htole64(dequeue_ptr); + + temp = XHCI_TRB_2_STREAM_SET(stream_id); + trb.dwTrb2 = htole32(temp); + + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE) | + XHCI_TRB_3_SLOT_SET(slot_id) | + XHCI_TRB_3_EP_SET(ep_id); + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t xhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend, uint8_t ep_id, uint8_t slot_id) { @@ -1213,7 +1249,7 @@ trb.dwTrb2 = 0; 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); + XHCI_TRB_3_EP_SET(ep_id); if (suspend) temp |= XHCI_TRB_3_SUSP_EP_BIT; @@ -1223,6 +1259,7 @@ return (xhci_do_command(sc, &trb, 50 /* ms */)); } +#if 0 static usb_error_t xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id) { @@ -1240,6 +1277,7 @@ return (xhci_do_command(sc, &trb, 50 /* ms */)); } +#endif /*------------------------------------------------------------------------* * xhci_interrupt - XHCI interrupt handler @@ -1300,21 +1338,11 @@ xhci_timeout(void *arg) { struct usb_xfer *xfer = arg; - struct xhci_endpoint_ext *pepext; DPRINTF("xfer=%p\n", xfer); USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - pepext = xhci_get_endpoint_ext(xfer->xroot->udev, - xfer->endpoint->edesc); - -#if 0 - /* check if endpoint is halted */ - if (pepext->trb_halted != 0) - return; -#endif - /* transfer is transferred */ xhci_device_done(xfer, USB_ERR_TIMEOUT); } @@ -2018,7 +2046,7 @@ route |= rh_port; } - temp = XHCI_SCTX_0_CTX_NUM_SET(1) | /* XXX XHCI_MAX_ENDPOINTS - 1) | */ + temp = XHCI_SCTX_0_CTX_NUM_SET(XHCI_MAX_ENDPOINTS - 1) | XHCI_SCTX_0_ROUTE_SET(route); switch (udev->speed) { @@ -2252,8 +2280,12 @@ pepext->trb_used--; - if (error) + pepext->xfer[xfer->qh_pos] = NULL; + + if (error && (pepext->trb_running != 0)) { pepext->trb_halted = 1; + pepext->trb_running = 0; + } } } @@ -2274,10 +2306,6 @@ pepext = xhci_get_endpoint_ext(xfer->xroot->udev, xfer->endpoint->edesc); - /* check for halt condition */ - if (pepext->trb_halted != 0) - return (0); - td_first = xfer->td_transfer_first; td_last = xfer->td_transfer_last; addr = pepext->physaddr; @@ -2287,10 +2315,30 @@ return (USB_ERR_NOMEM); } + /* check if transfer is not already on interrupt queue */ + if (xfer->wait_queue != &xfer->xroot->bus->intr_q) { + + /* remove transfer from pipe queue, if any */ + + usbd_transfer_dequeue(xfer); + + /* add transfer last on interrupt queue */ + + usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); + } + + /* check for stopped condition, after putting transfer on interrupt queue */ + if (pepext->trb_running == 0) { + struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); + + /* start configuration */ + (void)usb_proc_msignal(&sc->sc_config_proc, + &sc->sc_config_msg[0], &sc->sc_config_msg[1]); + return (0); + } + pepext->trb_used++; - xfer->flags_int.bandwidth_reclaimed = 1; - /* get current TRB index */ i = pepext->trb_index; @@ -2338,6 +2386,12 @@ usb_pc_cpu_flush(pepext->page_cache); + pepext->xfer[i] = xfer; + + xfer->qh_pos = i; + + xfer->flags_int.bandwidth_reclaimed = 1; + pepext->trb_index = inext; xhci_endpoint_doorbell(xfer); @@ -2418,13 +2472,8 @@ /* setup TD's and QH */ xhci_setup_generic_chain(xfer); -#ifdef NOTYET - /* put transfer on interrupt queue */ - usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - /* try to insert xfer on HW queue */ xhci_transfer_insert(xfer); -#endif } static void @@ -2438,9 +2487,6 @@ "transfer %p into HW queue.\n", xfer); } - /* put transfer on interrupt queue */ - usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - /* start timeout, if any */ if (xfer->timeout != 0) usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout); @@ -3067,10 +3113,6 @@ xfer->flags_int.curr_dma_set = 1; goto alloc_dma_set; } - - if ((parm->buf != NULL) && (parm->err == 0)) { - parm->err = xhci_configure_reset_endpoint(xfer); - } } static usb_error_t @@ -3092,6 +3134,7 @@ pepext = xhci_get_endpoint_ext(xfer->xroot->udev, xfer->endpoint->edesc); + udev = xfer->xroot->udev; index = udev->controller_slot_id; @@ -3155,18 +3198,12 @@ DPRINTF("Could not update parent HS HUB context.\n"); } - if (0) { - - - err = xhci_cmd_reset_dev(sc, index); - } - /* configure endpoint */ err = xhci_configure_endpoint_by_xfer(xfer); if (err == 0) { - err = xhci_cmd_stop_ep(sc, 0, epno, index); + err = xhci_cmd_stop_ep(sc, 0, epno - 1, index); if (err != 0) DPRINTF("Could not stop endpoint\n"); @@ -3190,10 +3227,15 @@ if (err == 0) { if ((edesc->bmAttributes & UE_XFERTYPE) == UE_BULK) - err = xhci_cmd_reset_ep(sc, 0, epno, index); + err = xhci_cmd_reset_ep(sc, 0, epno - 1, index); if (err != 0) DPRINTF("Could not reset endpoint %u\n", epno); + + err = xhci_cmd_set_tr_dequeue_ptr(sc, pepext->physaddr, 0, epno - 1, index); + + if (err != 0) + DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno); } XHCI_CMD_UNLOCK(sc); @@ -3227,42 +3269,46 @@ sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus); - /* make sure everything that is halted is gone, else we can loop */ - -restart0: +restart: TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { pepext = xhci_get_endpoint_ext(xfer->xroot->udev, xfer->endpoint->edesc); - if ((pepext->trb_halted != 0) && - (xfer->flags_int.bandwidth_reclaimed != 0)) { - xhci_device_done(xfer, USB_ERR_IOERROR); - goto restart0; - } - } + if ((pepext->trb_halted != 0) || + (pepext->trb_running == 0)) { -restart1: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { + uint8_t i; - pepext = xhci_get_endpoint_ext(xfer->xroot->udev, - xfer->endpoint->edesc); + /* clear halted and running */ + pepext->trb_halted = 0; + pepext->trb_running = 0; - if (xfer->flags_int.did_dma_delay) { + /* nuke remaining buffered transfers */ - if (pepext->trb_halted != 0) { + for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) { + if (pepext->xfer[i] != NULL) + xhci_device_done(pepext->xfer[i], USB_ERR_IOERROR); + } - /* NOTE: The USB transfer cannot vanish in this state! */ + /* NOTE: The USB transfer cannot vanish in this state! */ - USB_BUS_UNLOCK(&sc->sc_bus); + USB_BUS_UNLOCK(&sc->sc_bus); - xhci_configure_reset_endpoint(xfer); + xhci_configure_reset_endpoint(xfer); - USB_BUS_LOCK(&sc->sc_bus); + USB_BUS_LOCK(&sc->sc_bus); - pepext->trb_reset = 1; + /* check if halted is still cleared */ + if (pepext->trb_halted == 0) { + pepext->trb_running = 1; + pepext->trb_index = 1; } + goto restart; + } + if (xfer->flags_int.did_dma_delay) { + /* remove transfer from interrupt queue (again) */ usbd_transfer_dequeue(xfer); @@ -3270,22 +3316,14 @@ usb_dma_delay_done_cb(xfer); /* queue changed - restart */ - goto restart1; + goto restart; + } } - /* queue up leftover transfers, if any */ - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - pepext = xhci_get_endpoint_ext(xfer->xroot->udev, - xfer->endpoint->edesc); - - if ((pepext->trb_halted != 0) && - (pepext->trb_reset != 0)) { - pepext->trb_halted = 0; - pepext->trb_reset = 0; - } - xhci_transfer_insert(xfer); + /* try to insert transfer in hardware schedule */ + xhci_transfer_insert(xfer); } } @@ -3293,17 +3331,28 @@ xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, struct usb_endpoint *ep) { + struct xhci_endpoint_ext *pepext; + DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n", - ep, udev->address, - edesc->bEndpointAddress, udev->flags.usb_mode); + ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode); if (udev->flags.usb_mode != USB_MODE_HOST) { /* not supported */ return; } - /* check if not root HUB */ - if (udev->parent_hub != NULL) - ep->methods = &xhci_device_generic_methods; + if (udev->parent_hub == NULL) { + /* root HUB has special endpoint handling */ + return; + } + + ep->methods = &xhci_device_generic_methods; + + pepext = xhci_get_endpoint_ext(udev, edesc); + + USB_BUS_LOCK(udev->bus); + pepext->trb_halted = 1; + pepext->trb_running = 0; + USB_BUS_UNLOCK(udev->bus); } static void @@ -3312,6 +3361,30 @@ } +static void +xhci_ep_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) +{ + struct xhci_endpoint_ext *pepext; + + DPRINTF("\n"); + + if (udev->flags.usb_mode != USB_MODE_HOST) { + /* not supported */ + return; + } + if (udev->parent_hub == NULL) { + /* root HUB has special endpoint handling */ + return; + } + + pepext = xhci_get_endpoint_ext(udev, ep->edesc); + + USB_BUS_LOCK(udev->bus); + pepext->trb_halted = 1; + pepext->trb_running = 0; + USB_BUS_UNLOCK(udev->bus); +} + static usb_error_t xhci_device_init(struct usb_device *udev) { @@ -3452,4 +3525,5 @@ .xfer_poll = xhci_do_poll, .start_dma_delay = xhci_start_dma_delay, .set_address = xhci_set_address, + .clear_stall = xhci_ep_clear_stall, }; ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#18 (text+ko) ==== @@ -192,6 +192,8 @@ #define XHCI_TRB_2_BYTES_SET(x) ((x) & 0x1FFFF) #define XHCI_TRB_2_IRQ_GET(x) (((x) >> 22) & 0x3FF) #define XHCI_TRB_2_IRQ_SET(x) (((x) & 0x3FF) << 22) +#define XHCI_TRB_2_STREAM_GET(x) (((x) >> 16) & 0xFFFF) +#define XHCI_TRB_2_STREAM_SET(x) (((x) & 0xFFFF) << 16) volatile uint32_t dwTrb3; #define XHCI_TRB_3_TYPE_GET(x) (((x) >> 10) & 0x3F) @@ -215,11 +217,11 @@ #define XHCI_TRB_3_DIR_IN (1U << 16) #define XHCI_TRB_3_TLBPC_GET(x) (((x) >> 16) & 0xF) #define XHCI_TRB_3_TLBPC_SET(x) (((x) & 0xF) << 16) +#define XHCI_TRB_3_EP_GET(x) (((x) >> 16) & 0x1F) +#define XHCI_TRB_3_EP_SET(x) (((x) & 0x1F) << 16) #define XHCI_TRB_3_FRID_GET(x) (((x) >> 20) & 0x7FF) #define XHCI_TRB_3_FRID_SET(x) (((x) & 0x7FF) << 20) #define XHCI_TRB_3_ISO_SIA_BIT (1U << 31) -#define XHCI_TRB_3_EP_GET(x) (((x) >> 20) & 0x1F) -#define XHCI_TRB_3_EP_SET(x) (((x) & 0x1F) << 20) #define XHCI_TRB_3_SUSP_EP_BIT (1U << 23) #define XHCI_TRB_3_SLOT_GET(x) (((x) >> 24) & 0xFF) #define XHCI_TRB_3_SLOT_SET(x) (((x) & 0xFF) << 24) @@ -347,13 +349,13 @@ struct xhci_endpoint_ext { struct xhci_trb *trb; + struct usb_xfer *xfer[XHCI_MAX_TRANSFERS - 1]; struct usb_page_cache *page_cache; uint64_t physaddr; uint8_t trb_used; uint8_t trb_index; uint8_t trb_halted; - uint8_t trb_reset; - uint8_t trb_configured; + uint8_t trb_running; }; enum {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008081241.o78Cfg3h090927>