diff options
Diffstat (limited to 'sys/dev/usb/controller/xhci.c')
-rw-r--r-- | sys/dev/usb/controller/xhci.c | 123 |
1 files changed, 94 insertions, 29 deletions
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index 1a4e432..a20d7fa 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -128,7 +128,7 @@ 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, uint8_t, uint16_t, uint16_t); + uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, uint8_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 *, @@ -1245,7 +1245,7 @@ xhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address) &udev->ctrl_ep_desc); err = xhci_configure_endpoint(udev, &udev->ctrl_ep_desc, pepext->physaddr, - 0, 1, 1, 0, mps, mps); + 0, 1, 1, 0, mps, mps, USB_EP_MODE_DEFAULT); if (err != 0) { DPRINTF("Could not configure default endpoint\n"); @@ -1800,7 +1800,8 @@ xhci_setup_generic_chain(struct usb_xfer *xfer) /* compute multiplier for ISOCHRONOUS transfers */ mult = xfer->endpoint->ecomp ? - (xfer->endpoint->ecomp->bmAttributes & 3) : 0; + UE_GET_SS_ISO_MULT(xfer->endpoint->ecomp->bmAttributes) + : 0; /* check for USB 2.0 multiplier */ if (mult == 0) { mult = (xfer->endpoint->edesc-> @@ -2055,7 +2056,8 @@ static usb_error_t 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, - uint8_t fps_shift, uint16_t max_packet_size, uint16_t max_frame_size) + uint8_t fps_shift, uint16_t max_packet_size, + uint16_t max_frame_size, uint8_t ep_mode) { struct usb_page_search buf_inp; struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); @@ -2090,9 +2092,20 @@ xhci_configure_endpoint(struct usb_device *udev, if (mult == 0) return (USB_ERR_BAD_BUFSIZE); - temp = XHCI_EPCTX_0_EPSTATE_SET(0) | - XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | - XHCI_EPCTX_0_LSA_SET(0); + if (ep_mode == USB_EP_MODE_STREAMS) { + temp = XHCI_EPCTX_0_EPSTATE_SET(0) | + XHCI_EPCTX_0_MAXP_STREAMS_SET(XHCI_MAX_STREAMS_LOG - 1) | + XHCI_EPCTX_0_LSA_SET(1); + + ring_addr += sizeof(struct xhci_trb) * + XHCI_MAX_TRANSFERS * XHCI_MAX_STREAMS; + } else { + temp = XHCI_EPCTX_0_EPSTATE_SET(0) | + XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | + XHCI_EPCTX_0_LSA_SET(0); + + ring_addr |= XHCI_EPCTX_2_DCS_SET(1); + } switch (udev->speed) { case USB_SPEED_FULL: @@ -2160,9 +2173,6 @@ xhci_configure_endpoint(struct usb_device *udev, temp |= XHCI_EPCTX_1_EPTYPE_SET(4); xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx1, temp); - - ring_addr |= XHCI_EPCTX_2_DCS_SET(1); - xhci_ctx_set_le64(sc, &pinp->ctx_ep[epno - 1].qwEpCtx2, ring_addr); switch (edesc->bmAttributes & UE_XFERTYPE) { @@ -2195,21 +2205,42 @@ xhci_configure_endpoint_by_xfer(struct usb_xfer *xfer) { struct xhci_endpoint_ext *pepext; struct usb_endpoint_ss_comp_descriptor *ecomp; + usb_stream_t x; pepext = xhci_get_endpoint_ext(xfer->xroot->udev, xfer->endpoint->edesc); ecomp = xfer->endpoint->ecomp; - pepext->trb[0].dwTrb3 = 0; /* halt any transfers */ + for (x = 0; x != XHCI_MAX_STREAMS; x++) { + uint64_t temp; + + /* halt any transfers */ + pepext->trb[x * XHCI_MAX_TRANSFERS].dwTrb3 = 0; + + /* compute start of TRB ring for stream "x" */ + temp = pepext->physaddr + + (x * XHCI_MAX_TRANSFERS * sizeof(struct xhci_trb)) + + XHCI_SCTX_0_SCT_SEC_TR_RING; + + /* make tree structure */ + pepext->trb[(XHCI_MAX_TRANSFERS * + XHCI_MAX_STREAMS) + x].qwTrb0 = htole64(temp); + + /* reserved fields */ + pepext->trb[(XHCI_MAX_TRANSFERS * + XHCI_MAX_STREAMS) + x].dwTrb2 = 0; + pepext->trb[(XHCI_MAX_TRANSFERS * + XHCI_MAX_STREAMS) + x].dwTrb3 = 0; + } usb_pc_cpu_flush(pepext->page_cache); return (xhci_configure_endpoint(xfer->xroot->udev, xfer->endpoint->edesc, pepext->physaddr, xfer->interval, xfer->max_packet_count, - (ecomp != NULL) ? (ecomp->bmAttributes & 3) + 1 : 1, + (ecomp != NULL) ? UE_GET_SS_ISO_MULT(ecomp->bmAttributes) + 1 : 1, usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size, - xfer->max_frame_size)); + xfer->max_frame_size, xfer->endpoint->ep_mode)); } static usb_error_t @@ -2500,7 +2531,8 @@ xhci_get_endpoint_ext(struct usb_device *udev, struct usb_endpoint_descriptor *e pc = &sc->sc_hw.devs[index].endpoint_pc; - usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0], &buf_ep); + usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)-> + trb[epno][0], &buf_ep); pepext = &sc->sc_hw.devs[index].endp[epno]; pepext->page_cache = pc; @@ -2539,7 +2571,7 @@ xhci_transfer_remove(struct usb_xfer *xfer, usb_error_t error) pepext = xhci_get_endpoint_ext(xfer->xroot->udev, xfer->endpoint->edesc); - pepext->trb_used--; + pepext->trb_used[xfer->stream_id]--; pepext->xfer[xfer->qh_pos] = NULL; @@ -2557,12 +2589,15 @@ xhci_transfer_insert(struct usb_xfer *xfer) struct xhci_td *td_last; struct xhci_endpoint_ext *pepext; uint64_t addr; + usb_stream_t id; uint8_t i; uint8_t inext; uint8_t trb_limit; DPRINTFN(8, "\n"); + id = xfer->stream_id; + /* check if already inserted */ if (xfer->flags_int.bandwidth_reclaimed) { DPRINTFN(8, "Already in schedule\n"); @@ -2588,7 +2623,7 @@ xhci_transfer_insert(struct usb_xfer *xfer) break; } - if (pepext->trb_used >= trb_limit) { + if (pepext->trb_used[id] >= trb_limit) { DPRINTFN(8, "Too many TDs queued.\n"); return (USB_ERR_NOMEM); } @@ -2605,10 +2640,10 @@ xhci_transfer_insert(struct usb_xfer *xfer) return (0); } - pepext->trb_used++; + pepext->trb_used[id]++; /* get current TRB index */ - i = pepext->trb_index; + i = pepext->trb_index[id]; /* get next TRB index */ inext = (i + 1); @@ -2617,8 +2652,12 @@ xhci_transfer_insert(struct usb_xfer *xfer) if (inext >= (XHCI_MAX_TRANSFERS - 1)) inext = 0; + /* offset for stream */ + i += id * XHCI_MAX_TRANSFERS; + inext += id * XHCI_MAX_TRANSFERS; + /* compute terminating return address */ - addr += inext * sizeof(struct xhci_trb); + addr += (inext * sizeof(struct xhci_trb)); /* update next pointer of last link TRB */ td_last->td_trb[td_last->ntrb].qwTrb0 = htole64(addr); @@ -2662,7 +2701,7 @@ xhci_transfer_insert(struct usb_xfer *xfer) xfer->flags_int.bandwidth_reclaimed = 1; - pepext->trb_index = inext; + pepext->trb_index[id] = inext; xhci_endpoint_doorbell(xfer); @@ -2750,12 +2789,12 @@ xhci_device_generic_close(struct usb_xfer *xfer) static void xhci_device_generic_multi_enter(struct usb_endpoint *ep, - struct usb_xfer *enter_xfer) + usb_stream_t stream_id, struct usb_xfer *enter_xfer) { struct usb_xfer *xfer; /* check if there is a current transfer */ - xfer = ep->endpoint_q.curr; + xfer = ep->endpoint_q[stream_id].curr; if (xfer == NULL) return; @@ -2767,7 +2806,7 @@ xhci_device_generic_multi_enter(struct usb_endpoint *ep, if (!xfer->flags_int.bandwidth_reclaimed) return; - xfer = TAILQ_FIRST(&ep->endpoint_q.head); + xfer = TAILQ_FIRST(&ep->endpoint_q[stream_id].head); if (xfer == NULL) { /* * In case of enter we have to consider that the @@ -2792,7 +2831,8 @@ xhci_device_generic_enter(struct usb_xfer *xfer) /* setup TD's and QH */ xhci_setup_generic_chain(xfer); - xhci_device_generic_multi_enter(xfer->endpoint, xfer); + xhci_device_generic_multi_enter(xfer->endpoint, + xfer->stream_id, xfer); } static void @@ -2804,7 +2844,8 @@ xhci_device_generic_start(struct usb_xfer *xfer) xhci_transfer_insert(xfer); /* try to multi buffer */ - xhci_device_generic_multi_enter(xfer->endpoint, NULL); + xhci_device_generic_multi_enter(xfer->endpoint, + xfer->stream_id, NULL); /* add transfer last on interrupt queue */ usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); @@ -3465,6 +3506,7 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer) struct usb_endpoint_descriptor *edesc; struct usb_page_cache *pcinp; usb_error_t err; + usb_stream_t stream_id; uint8_t index; uint8_t epno; @@ -3481,6 +3523,7 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer) edesc = xfer->endpoint->edesc; epno = edesc->bEndpointAddress; + stream_id = xfer->stream_id; if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) epno |= UE_DIR_IN; @@ -3516,8 +3559,10 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer) if (err != 0) DPRINTF("Could not reset endpoint %u\n", epno); - err = xhci_cmd_set_tr_dequeue_ptr(sc, pepext->physaddr | - XHCI_EPCTX_2_DCS_SET(1), 0, epno, index); + err = xhci_cmd_set_tr_dequeue_ptr(sc, + (pepext->physaddr + (stream_id * sizeof(struct xhci_trb) * + XHCI_MAX_TRANSFERS)) | XHCI_EPCTX_2_DCS_SET(1), + stream_id, epno, index); if (err != 0) DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno); @@ -3615,7 +3660,8 @@ restart: /* check if halted is still cleared */ if (pepext->trb_halted == 0) { pepext->trb_running = 1; - pepext->trb_index = 0; + memset(pepext->trb_index, 0, + sizeof(pepext->trb_index)); } goto restart; } @@ -3639,7 +3685,8 @@ restart: xhci_transfer_insert(xfer); /* try to multi buffer */ - xhci_device_generic_multi_enter(xfer->endpoint, NULL); + xhci_device_generic_multi_enter(xfer->endpoint, + xfer->stream_id, NULL); } } @@ -3946,6 +3993,23 @@ xhci_device_state_change(struct usb_device *udev) XHCI_CMD_UNLOCK(sc); } +static usb_error_t +xhci_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep, + uint8_t ep_mode) +{ + switch (ep_mode) { + case USB_EP_MODE_DEFAULT: + return (0); + case USB_EP_MODE_STREAMS: + if ((ep->edesc->bmAttributes & UE_XFERTYPE) != UE_BULK || + udev->speed != USB_SPEED_SUPER) + return (USB_ERR_INVAL); + return (0); + default: + return (USB_ERR_INVAL); + } +} + struct usb_bus_methods xhci_bus_methods = { .endpoint_init = xhci_ep_init, .endpoint_uninit = xhci_ep_uninit, @@ -3964,4 +4028,5 @@ struct usb_bus_methods xhci_bus_methods = { .clear_stall = xhci_ep_clear_stall, .device_state_change = xhci_device_state_change, .set_hw_power_sleep = xhci_set_hw_power_sleep, + .set_endpoint_mode = xhci_set_endpoint_mode, }; |