tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[patch] xhci patch 20150911
Hello,
Here is xhci patches for nick-nhusb branch.
nhusb-xhci-lock.diff
+ Fix lock error. Same as
https://mail-index.netbsd.org/tech-kern/2015/07/15/msg019170.html
nhusb-xhci-evh.diff
+ Split xhci_handle_event() into 3 functions. Whitespace.
nhusb-xhci-evh2.diff
+ Improve xhci_configure_endpoint().
+ Split off maxburst and interval calculation.
+ Start interval calculation with 10, not 11.
+ Put correct maxburst value.
+ Split off constructing endpoint context.
+ Improve xhci_event_transfer()
+ Remove case of unlikely completion codes I added.
+ Clear xr_cookies too when xhci_set_dequeue() clears xr_trb.
+ Return USBD_NO_ADDR if xhci_address_device fails with
XHCI_TRB_ERROR_NO_SLOTS.
+ Add aprint_debug xhci capability registers.
+ Add & update comments.
--
t-hash
--- sys/dev/usb/xhci.c.orig 2015-08-31 18:05:22.000000000 +0900
+++ sys/dev/usb/xhci.c 2015-08-31 20:13:34.000000000 +0900
@@ -1587,7 +1587,7 @@ xhci_close_pipe(struct usbd_pipe *pipe)
trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
- (void)xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ (void)xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
}
--- sys/dev/usb/xhci.c.orig 2015-08-31 19:44:26.000000000 +0900
+++ sys/dev/usb/xhci.c 2015-08-31 23:08:31.000000000 +0900
@@ -1678,9 +1678,7 @@ xhci_clear_endpoint_stall_async(struct u
#endif /* XXX experimental */
-/*
- * Notify roothub port status/change to uhub_intr.
- */
+/* Process roothub port status/change events and notify to uhub_intr. */
static void
xhci_rhpsc(struct xhci_softc * const sc, u_int port)
{
@@ -1705,176 +1703,221 @@ xhci_rhpsc(struct xhci_softc * const sc,
usb_transfer_complete(xfer);
}
-/*
- * Process events:
- * + Transfer comeplete
- * + Command complete
- * + Roothub Port status/change
- */
+/* Process Transfer Events */
static void
-xhci_handle_event(struct xhci_softc * const sc,
+xhci_event_transfer(struct xhci_softc * const sc,
const struct xhci_trb * const trb)
{
uint64_t trb_0;
uint32_t trb_2, trb_3;
- uint8_t trberr;
+ uint8_t trbcode;
+ u_int slot, dci;
+ struct xhci_slot *xs;
+ struct xhci_ring *xr;
+ struct xhci_xfer *xx;
+ struct usbd_xfer *xfer;
+ usbd_status err;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
trb_0 = le64toh(trb->trb_0);
trb_2 = le32toh(trb->trb_2);
trb_3 = le32toh(trb->trb_3);
- trberr = XHCI_TRB_2_ERROR_GET(trb_2);
-
- DPRINTFN(14, "event: %p 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
- trb, trb_0, trb_2, trb_3);
-
- switch (XHCI_TRB_3_TYPE_GET(trb_3)) {
- case XHCI_TRB_EVENT_TRANSFER: {
- u_int slot, dci;
- struct xhci_slot *xs;
- struct xhci_ring *xr;
- struct xhci_xfer *xx;
- struct usbd_xfer *xfer;
- usbd_status err;
-
- slot = XHCI_TRB_3_SLOT_GET(trb_3);
- dci = XHCI_TRB_3_EP_GET(trb_3);
+ trbcode = XHCI_TRB_2_ERROR_GET(trb_2);
+ slot = XHCI_TRB_3_SLOT_GET(trb_3);
+ dci = XHCI_TRB_3_EP_GET(trb_3);
+ xs = &sc->sc_slots[slot];
+ xr = &xs->xs_ep[dci].xe_tr;
- xs = &sc->sc_slots[slot];
- xr = &xs->xs_ep[dci].xe_tr;
- /* sanity check */
- if (xs->xs_idx == 0 || xs->xs_idx >= sc->sc_maxslots) {
- DPRINTFN(1, "invalid slot %u", xs->xs_idx, 0, 0, 0);
- break;
- }
+ /* sanity check */
+ if (xs->xs_idx == 0 || xs->xs_idx >= sc->sc_maxslots) {
+ DPRINTFN(1, "invalid slot %u", xs->xs_idx, 0, 0, 0);
+ return;
+ }
- if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
- bus_addr_t trbp = xhci_ring_trbp(xr, 0);
-
- /* trb_0 range sanity check */
- if (trb_0 < trbp ||
- (trb_0 - trbp) % sizeof(struct xhci_trb) != 0 ||
- (trb_0 - trbp) / sizeof(struct xhci_trb) >=
- xr->xr_ntrb) {
- DPRINTFN(1,
- "invalid trb_0 0x%"PRIx64" trbp 0x%"PRIx64,
- trb_0, trbp, 0, 0);
- break;
- }
- int idx = (trb_0 - trbp) / sizeof(struct xhci_trb);
- xx = xr->xr_cookies[idx];
- } else {
- xx = (void *)(uintptr_t)(trb_0 & ~0x3);
- }
- /* XXX this may not happen */
- if (xx == NULL) {
- DPRINTFN(1, "xfer done: xx is NULL", 0, 0, 0, 0);
- break;
- }
- xfer = &xx->xx_xfer;
- /* XXX this may happen when detaching */
- if (xfer == NULL) {
- DPRINTFN(1, "xfer done: xfer is NULL", 0, 0, 0, 0);
- break;
- }
- DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
- /* XXX I dunno why this happens */
- KASSERT(xfer->ux_pipe != NULL);
+ if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
+ bus_addr_t trbp = xhci_ring_trbp(xr, 0);
- if (!xfer->ux_pipe->up_repeat &&
- SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
- DPRINTFN(1, "xfer done: xfer not started", 0, 0, 0, 0);
- break;
+ /* trb_0 range sanity check */
+ if (trb_0 < trbp ||
+ (trb_0 - trbp) % sizeof(struct xhci_trb) != 0 ||
+ (trb_0 - trbp) / sizeof(struct xhci_trb) >=
+ xr->xr_ntrb) {
+ DPRINTFN(1, "invalid trb_0 0x%"PRIx64" trbp 0x%"PRIx64,
+ trb_0, trbp, 0, 0);
+ return;
}
+ int idx = (trb_0 - trbp) / sizeof(struct xhci_trb);
+ xx = xr->xr_cookies[idx];
+ } else {
+ xx = (void *)(uintptr_t)(trb_0 & ~0x3);
+ }
+ /* XXX this may not happen */
+ if (xx == NULL) {
+ DPRINTFN(1, "xfer done: xx is NULL", 0, 0, 0, 0);
+ return;
+ }
+ xfer = &xx->xx_xfer;
+ /* XXX this may happen when detaching */
+ if (xfer == NULL) {
+ DPRINTFN(1, "xfer done: xfer is NULL", 0, 0, 0, 0);
+ return;
+ }
+ DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
+ /* XXX I dunno why this happens */
+ KASSERT(xfer->ux_pipe != NULL);
+
+ if (!xfer->ux_pipe->up_repeat &&
+ SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
+ DPRINTFN(1, "xfer done: xfer not started", 0, 0, 0, 0);
+ return;
+ }
- if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
- DPRINTFN(14, "transfer event data: "
- "0x%016"PRIx64" 0x%08"PRIx32" %02x",
- trb_0, XHCI_TRB_2_REM_GET(trb_2),
- XHCI_TRB_2_ERROR_GET(trb_2), 0);
- if ((trb_0 & 0x3) == 0x3) {
- xfer->ux_actlen = XHCI_TRB_2_REM_GET(trb_2);
- }
+ if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
+ DPRINTFN(14, "transfer event data: "
+ "0x%016"PRIx64" 0x%08"PRIx32" %02x",
+ trb_0, XHCI_TRB_2_REM_GET(trb_2),
+ XHCI_TRB_2_ERROR_GET(trb_2), 0);
+ if ((trb_0 & 0x3) == 0x3) {
+ xfer->ux_actlen = XHCI_TRB_2_REM_GET(trb_2);
}
+ }
- switch (trberr) {
- case XHCI_TRB_ERROR_SHORT_PKT:
- case XHCI_TRB_ERROR_SUCCESS:
- xfer->ux_actlen =
- xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
- err = USBD_NORMAL_COMPLETION;
- break;
- case XHCI_TRB_ERROR_STALL:
- case XHCI_TRB_ERROR_BABBLE:
- DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
- trberr, slot, dci, 0);
- xr->is_halted = true;
- err = USBD_STALLED;
+ switch (trbcode) {
+ case XHCI_TRB_ERROR_SHORT_PKT:
+ case XHCI_TRB_ERROR_SUCCESS:
+ xfer->ux_actlen =
+ xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
+ err = USBD_NORMAL_COMPLETION;
+ break;
+ case XHCI_TRB_ERROR_STALL:
+ case XHCI_TRB_ERROR_BABBLE:
+ DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
+ trbcode, slot, dci, 0);
+ xr->is_halted = true;
+ err = USBD_STALLED;
#if 1 /* XXX experimental */
- /*
- * Stalled endpoints can be recoverd by issuing
- * command TRB TYPE_RESET_EP on xHCI instead of
- * issuing request CLEAR_PORT_FEATURE UF_ENDPOINT_HALT
- * on the endpoint. However, this function may be
- * called from softint context (e.g. from umass),
- * in that case driver gets KASSERT in cv_timedwait
- * in xhci_do_command.
- * To avoid this, this runs reset_endpoint and
- * usb_transfer_complete in usb task thread
- * asynchronously (and then umass issues clear
- * UF_ENDPOINT_HALT).
- */
- xfer->ux_status = err;
- xhci_clear_endpoint_stall_async(xfer);
- return;
+ /*
+ * Stalled endpoints can be recoverd by issuing
+ * command TRB TYPE_RESET_EP on xHCI instead of
+ * issuing request CLEAR_PORT_FEATURE UF_ENDPOINT_HALT
+ * on the endpoint. However, this function may be
+ * called from softint context (e.g. from umass),
+ * in that case driver gets KASSERT in cv_timedwait
+ * in xhci_do_command.
+ * To avoid this, this runs reset_endpoint and
+ * usb_transfer_complete in usb task thread
+ * asynchronously (and then umass issues clear
+ * UF_ENDPOINT_HALT).
+ */
+ xfer->ux_status = err;
+ xhci_clear_endpoint_stall_async(xfer);
+ return;
#else
- break;
+ break;
#endif
- case XHCI_TRB_ERROR_CMD_ABORTED:
- case XHCI_TRB_ERROR_STOPPED:
- err = USBD_CANCELLED;
- break;
- case XHCI_TRB_ERROR_NO_SLOTS:
- err = USBD_NO_ADDR;
- break;
- default:
- DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
- trberr, slot, dci, 0);
- err = USBD_IOERROR;
- break;
- }
- xfer->ux_status = err;
+ case XHCI_TRB_ERROR_CMD_ABORTED:
+ case XHCI_TRB_ERROR_STOPPED:
+ err = USBD_CANCELLED;
+ break;
+ case XHCI_TRB_ERROR_NO_SLOTS:
+ err = USBD_NO_ADDR;
+ break;
+ default:
+ DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
+ trbcode, slot, dci, 0);
+ err = USBD_IOERROR;
+ break;
+ }
+ xfer->ux_status = err;
- //mutex_enter(&sc->sc_lock); /* XXX ??? */
- if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
- if ((trb_0 & 0x3) == 0x0) {
- usb_transfer_complete(xfer);
- }
- } else {
+ //mutex_enter(&sc->sc_lock); /* XXX ??? */
+ if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
+ if ((trb_0 & 0x3) == 0x0) {
usb_transfer_complete(xfer);
}
- //mutex_exit(&sc->sc_lock); /* XXX ??? */
+ } else {
+ usb_transfer_complete(xfer);
+ }
+ //mutex_exit(&sc->sc_lock); /* XXX ??? */
+}
+/* Process Command complete events */
+static void
+xhci_event_cmd(struct xhci_softc * const sc,
+ const struct xhci_trb * const trb)
+{
+ uint64_t trb_0;
+ uint32_t trb_2, trb_3;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ trb_0 = le64toh(trb->trb_0);
+ trb_2 = le32toh(trb->trb_2);
+ trb_3 = le32toh(trb->trb_3);
+
+ if (trb_0 == sc->sc_command_addr) {
+ sc->sc_result_trb.trb_0 = trb_0;
+ sc->sc_result_trb.trb_2 = trb_2;
+ sc->sc_result_trb.trb_3 = trb_3;
+ if (XHCI_TRB_2_ERROR_GET(trb_2) !=
+ XHCI_TRB_ERROR_SUCCESS) {
+ DPRINTFN(1, "command completion "
+ "failure: 0x%016"PRIx64" 0x%08"PRIx32" "
+ "0x%08"PRIx32, trb_0, trb_2, trb_3, 0);
+ }
+ cv_signal(&sc->sc_command_cv);
+ } else {
+ DPRINTFN(1, "spurious event: %p 0x%016"PRIx64" "
+ "0x%08"PRIx32" 0x%08"PRIx32, trb, trb_0,
+ trb_2, trb_3);
+ }
+}
+
+/*
+ * Process events.
+ * called from xhci_softintr
+ */
+static void
+xhci_handle_event(struct xhci_softc * const sc,
+ const struct xhci_trb * const trb)
+{
+ uint64_t trb_0;
+ uint32_t trb_2, trb_3;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ trb_0 = le64toh(trb->trb_0);
+ trb_2 = le32toh(trb->trb_2);
+ trb_3 = le32toh(trb->trb_3);
+
+ DPRINTFN(14, "event: %p 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
+ trb, trb_0, trb_2, trb_3);
+
+ /*
+ * 4.11.3.1, 6.4.2.1
+ * TRB Pointer is invalid for these completion codes.
+ */
+ switch (XHCI_TRB_2_ERROR_GET(trb_2)) {
+ case XHCI_TRB_ERROR_RING_UNDERRUN:
+ case XHCI_TRB_ERROR_RING_OVERRUN:
+ case XHCI_TRB_ERROR_VF_RING_FULL:
+ return;
+ default:
+ if (trb_0 == 0) {
+ return;
}
break;
+ }
+
+ switch (XHCI_TRB_3_TYPE_GET(trb_3)) {
+ case XHCI_TRB_EVENT_TRANSFER:
+ xhci_event_transfer(sc, trb);
+ break;
case XHCI_TRB_EVENT_CMD_COMPLETE:
- if (trb_0 == sc->sc_command_addr) {
- sc->sc_result_trb.trb_0 = trb_0;
- sc->sc_result_trb.trb_2 = trb_2;
- sc->sc_result_trb.trb_3 = trb_3;
- if (XHCI_TRB_2_ERROR_GET(trb_2) !=
- XHCI_TRB_ERROR_SUCCESS) {
- DPRINTFN(1, "command completion "
- "failure: 0x%016"PRIx64" 0x%08"PRIx32" "
- "0x%08"PRIx32, trb_0, trb_2, trb_3, 0);
- }
- cv_signal(&sc->sc_command_cv);
- } else {
- DPRINTFN(1, "spurious event: %p 0x%016"PRIx64" "
- "0x%08"PRIx32" 0x%08"PRIx32, trb, trb_0,
- trb_2, trb_3);
- }
+ xhci_event_cmd(sc, trb);
break;
case XHCI_TRB_EVENT_PORT_STS_CHANGE:
xhci_rhpsc(sc, (uint32_t)((trb_0 >> 24) & 0xff));
--- sys/dev/usb/xhci.c.orig 2015-09-01 09:08:55.000000000 +0900
+++ sys/dev/usb/xhci.c 2015-09-01 23:58:18.000000000 +0900
@@ -660,8 +660,22 @@ xhci_init(struct xhci_softc *sc)
sc->sc_ac64 = XHCI_HCC_AC64(hcc);
sc->sc_ctxsz = XHCI_HCC_CSZ(hcc) ? 64 : 32;
- aprint_debug_dev(sc->sc_dev, "ac64 %d ctxsz %d\n", sc->sc_ac64,
- sc->sc_ctxsz);
+ char sbuf[128];
+ if (hciversion < 0x0100)
+ snprintb(sbuf, sizeof sbuf, "\177\020"
+ "f\020\020XECP\0f\014\4MAXPSA\0"
+ "b\013CFC\0b\012SEC\0b\011SBD\0b\010FSE\0"
+ "b\7NSS\0b\6LTC\0b\5LHRC\0b\4PIND\0b\3PPC\0"
+ "b\2CZC\0b\1BNC\0b\0AC64\0\0",
+ hcc);
+ else
+ snprintb(sbuf, sizeof sbuf, "\177\020"
+ "f\020\020XECP\0f\014\4MAXPSA\0"
+ "b\013CFC\0b\012SEC\0b\011SPC\0b\010PAE\0"
+ "b\7NSS\0b\6LTC\0b\5LHRC\0b\4PIND\0b\3PPC\0"
+ "b\2CZC\0b\1BNC\0b\0AC64\0\0",
+ hcc);
+ aprint_debug_dev(sc->sc_dev, "hcc1=%s\n", sbuf);
aprint_debug_dev(sc->sc_dev, "xECP %x\n", XHCI_HCC_XECP(hcc) * 4);
ecp = XHCI_HCC_XECP(hcc) * 4;
@@ -1073,8 +1087,8 @@ xhci_setup_sctx(struct usbd_device *dev,
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- /* 6.2.2 */
/*
+ * 6.2.2, Table 57-60, 6.2.2.1, 6.2.2.2
* tthubslot:
* This is the slot ID of parent HS hub
* if LS/FS device is connected && connected through HS hub.
@@ -1094,7 +1108,6 @@ xhci_setup_sctx(struct usbd_device *dev,
dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
(speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
ttportnum = dev->ud_myhsport->up_portno;
- /* XXX addr == slot ? */
tthubslot = dev->ud_myhsport->up_parent->ud_addr;
} else {
ttportnum = 0;
@@ -1157,177 +1170,206 @@ xhci_setup_sctx(struct usbd_device *dev,
cp[3] |= htole32(0);
}
+static uint32_t
+xhci_get_maxburst(struct usbd_pipe *pipe)
+{
+ usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+ usbd_desc_iter_t iter;
+ const usb_cdc_descriptor_t *cdcd;
+ const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
+ uint32_t maxb = 0;
+ uint8_t ep;
+
+ cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(
+ pipe->up_dev, UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
+ usb_desc_iter_init(pipe->up_dev, &iter);
+ iter.cur = (const void *)cdcd;
+
+ /* find endpoint_ss_comp desc for ep of this pipe */
+ for(ep = 0;;) {
+ cdcd = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
+ if (cdcd == NULL)
+ break;
+ if (ep == 0 && cdcd->bDescriptorType == UDESC_ENDPOINT) {
+ ep = ((const usb_endpoint_descriptor_t *)cdcd)->
+ bEndpointAddress;
+ if (UE_GET_ADDR(ep) ==
+ UE_GET_ADDR(ed->bEndpointAddress)) {
+ cdcd = (const usb_cdc_descriptor_t *)
+ usb_desc_iter_next(&iter);
+ break;
+ }
+ ep = 0;
+ }
+ }
+ if (cdcd != NULL && cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
+ esscd = (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
+ maxb = esscd->bMaxBurst;
+ }
+
+ return maxb;
+}
+
/*
- * called
- * from xhci_open
- * from usbd_setup_pipe_flags
- * from usbd_open_pipe_ival
+ * Convert endpoint bInterval value to endpoint context interval value
+ * for Interrupt pipe.
+ * xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6
*/
-static usbd_status
-xhci_configure_endpoint(struct usbd_pipe *pipe)
+static uint32_t
+xhci_bival2ival(uint32_t ival, int speed)
+{
+ if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
+ int i;
+
+ /*
+ * round ival down to "the nearest base 2 multiple of
+ * bInterval * 8".
+ * bInterval is at most 255 as its type is uByte.
+ * 255(ms) = 2040(x 125us) < 2^11, so start with 10.
+ */
+ for (i = 10; i > 0; i--) {
+ if ((ival * 8) >= (1 << i))
+ break;
+ }
+ ival = i;
+ } else {
+ /* Interval = bInterval-1 for SS/HS */
+ ival--;
+ }
+
+ return ival;
+}
+
+/*
+ * 4.8.2, 6.2.3.2
+ * construct common endpoint parameters
+ */
+static void
+xhci_setup_endp_ctx(struct usbd_pipe *pipe, uint32_t *cp)
{
- struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
- const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+ const u_int dci = xhci_ep_get_dci(ed);
const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
- struct xhci_trb trb;
- usbd_status err;
- uint32_t *cp;
uint32_t mps = UGETW(ed->wMaxPacketSize);
uint32_t maxb = 0;
int speed = pipe->up_dev->ud_speed;
uint32_t ival = ed->bInterval;
- XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "slot %u dci %u epaddr 0x%02x attr 0x%02x",
- xs->xs_idx, dci, ed->bEndpointAddress, ed->bmAttributes);
-
- /* XXX ensure input context is available? */
-
- memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);
-
- cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
- cp[0] = htole32(0);
- cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(dci));
-
- /* set up input slot context */
- cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
- xhci_setup_sctx(pipe->up_dev, cp);
- cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
-
- cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
cp[0] = htole32(
XHCI_EPCTX_0_EPSTATE_SET(0) |
+ XHCI_EPCTX_0_MULT_SET(0) | /* always 0 except SS iscoh */
XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
- XHCI_EPCTX_0_LSA_SET(0)
+ XHCI_EPCTX_0_LSA_SET(0) |
+ XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(0)
);
cp[1] = htole32(
XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(ed)) |
+ XHCI_EPCTX_1_HID_SET(0) |
XHCI_EPCTX_1_MAXB_SET(0)
);
if (xfertype != UE_ISOCHRONOUS)
cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
+ /* 6.2.3.4, 4.8.2.4 */
if (USB_IS_SS(speed)) {
- usbd_desc_iter_t iter;
- const usb_cdc_descriptor_t *cdcd;
- const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
- uint8_t ep;
-
- cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(
- pipe->up_dev, UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
- usb_desc_iter_init(pipe->up_dev, &iter);
- iter.cur = (const void *)cdcd;
-
- /* find endpoint_ss_comp desc for ep of this pipe */
- for(ep = 0;;) {
- cdcd = (const usb_cdc_descriptor_t *)
- usb_desc_iter_next(&iter);
- if (cdcd == NULL)
- break;
- if (ep == 0 &&
- cdcd->bDescriptorType == UDESC_ENDPOINT) {
- ep = ((const usb_endpoint_descriptor_t *)cdcd)->
- bEndpointAddress;
- if (UE_GET_ADDR(ep) ==
- UE_GET_ADDR(ed->bEndpointAddress)) {
- cdcd = (const usb_cdc_descriptor_t *)
- usb_desc_iter_next(&iter);
- break;
- }
- ep = 0;
- }
- }
- if (cdcd != NULL &&
- cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
- esscd = (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
- maxb = esscd->bMaxBurst;
- cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
- DPRINTFN(4, "setting SS MaxBurst %u", maxb, 0, 0, 0);
+ /* UBS 3.1 9.6.6 */
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+ /* UBS 3.1 9.6.7 */
+ maxb = xhci_get_maxburst(pipe);
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+ } else {
+ /* UBS 2.0 9.6.6 */
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(UE_GET_SIZE(mps)));
+
+ /* 6.2.3.4 */
+ if (speed == USB_SPEED_HIGH &&
+ (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
+ maxb = UE_GET_TRANS(mps);
+ } else {
+ /* LS/FS or HS CTRL or HS BULK */
+ maxb = 0;
}
- }
- if (speed == USB_SPEED_HIGH &&
- (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
- maxb = UE_GET_TRANS(UGETW(ed->wMaxPacketSize));
cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
- DPRINTFN(4, "setting HS MaxBurst %u", maxb, 0, 0, 0);
}
+ if (xfertype == UE_CONTROL)
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)); /* 6.2.3 */
+ else if (USB_IS_SS(speed))
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(mps));
+ else
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(UE_GET_SIZE(mps)));
+
switch (xfertype) {
+ case UE_CONTROL:
+ break;
+ case UE_BULK:
+ /* XXX Set MaxPStreams, HID, and LSA if streams enabled */
+ break;
case UE_INTERRUPT:
if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
ival = pipe->up_interval;
- /* xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6 */
- if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
- int i;
-
- /*
- * round ival down to "the nearest base 2 multiple of
- * bInterval * 8".
- * bInterval is at most 255 as its type is uByte.
- * 255(ms) = 2040(x 125us) < 2^11, so start with 11.
- */
- for (i = 11; i > 0; i--) {
- if ((ival * 8) >= (1 << i))
- break;
- }
- ival = i;
- } else {
- /* Interval = bInterval-1 for SS/HS */
- ival--;
- }
- DPRINTFN(4, "ival %u", ival, 0, 0, 0);
-
- if (USB_IS_SS(speed)) {
- if (maxb > 0)
- mps = 1024;
- } else {
- mps = mps ? mps : 8;
- }
+ ival = xhci_bival2ival(ival, speed);
cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
- cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
- cp[4] = htole32(
- XHCI_EPCTX_4_AVG_TRB_LEN_SET(8) /* XXX */
- );
break;
- case UE_CONTROL:
- if (USB_IS_SS(speed))
- mps = 512;
- else
- mps = mps ? mps : 8;
- cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
- cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)); /* XXX */
- break;
-#ifdef notyet
case UE_ISOCHRONOUS:
+ if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
+ ival = pipe->up_interval;
+
+ /* xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6 */
if (speed == USB_SPEED_FULL)
ival += 3; /* 1ms -> 125us */
ival--;
- DPRINTFN(4, "ival %u", ival, 0, 0, 0);
+ cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
if (USB_IS_SS(speed)) {
- mps = 1024;
- } else {
- mps = mps ? mps : 1024;
+ /* XXX if LEC = 1, set ESIT instead */
+ cp[0] |= htole32(XHCI_EPCTX_0_MULT_SET(0));
}
- cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
- cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
break;
-#endif
default:
- if (USB_IS_SS(speed))
- mps = 1024;
- else
- mps = mps ? mps : 512;
- cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
- cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
break;
}
*(uint64_t *)(&cp[2]) = htole64(
xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
XHCI_EPCTX_2_DCS_SET(1));
+}
+
+/*
+ * Construct input contexts and issue TRB
+ */
+static usbd_status
+xhci_configure_endpoint(struct usbd_pipe *pipe)
+{
+ struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
+ struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
+ const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
+ struct xhci_trb trb;
+ usbd_status err;
+ uint32_t *cp;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ DPRINTFN(4, "slot %u dci %u epaddr 0x%02x attr 0x%02x",
+ xs->xs_idx, dci, pipe->up_endpoint->ue_edesc->bEndpointAddress,
+ pipe->up_endpoint->ue_edesc->bmAttributes);
+
+ /* XXX ensure input context is available? */
+
+ memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);
+
+ cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
+ cp[0] = htole32(0);
+ cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(dci));
+
+ /* set up input slot context */
+ cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
+ xhci_setup_sctx(pipe->up_dev, cp);
+ cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+
+ /* set up input endpoint context */
+ cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
+ xhci_setup_endp_ctx(pipe, cp);
/* sync input contexts before they are read from memory */
usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
@@ -1443,6 +1485,7 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE);
usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE,
BUS_DMASYNC_PREWRITE);
+ memset(xr->xr_cookies, 0, xr->xr_ntrb * sizeof(*xr->xr_cookies));
xr->xr_ep = 0;
xr->xr_cs = 1;
@@ -1547,7 +1590,7 @@ xhci_close_pipe(struct usbd_pipe *pipe)
/* xs is uninitialized before xhci_init_slot */
return;
- DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+ DPRINTFN(4, "pipe %p slot %u dci %u", pipe, xs->xs_idx, dci, 0);
KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
KASSERT(mutex_owned(&sc->sc_lock));
@@ -1621,11 +1664,11 @@ xhci_abort_xfer(struct usbd_xfer *xfer,
xfer->ux_status = status;
callout_stop(&xfer->ux_callout);
usb_transfer_complete(xfer);
+ DPRINTFN(14, "end", 0, 0, 0, 0);
KASSERT(mutex_owned(&sc->sc_lock));
}
-#if 1 /* XXX experimental */
/*
* Recover STALLed endpoint.
* xHCI 1.1 sect 4.10.2.1
@@ -1676,8 +1719,6 @@ xhci_clear_endpoint_stall_async(struct u
return USBD_NORMAL_COMPLETION;
}
-#endif /* XXX experimental */
-
/* Process roothub port status/change events and notify to uhub_intr. */
static void
xhci_rhpsc(struct xhci_softc * const sc, u_int port)
@@ -1730,12 +1771,14 @@ xhci_event_transfer(struct xhci_softc *
xr = &xs->xs_ep[dci].xe_tr;
/* sanity check */
- if (xs->xs_idx == 0 || xs->xs_idx >= sc->sc_maxslots) {
- DPRINTFN(1, "invalid slot %u", xs->xs_idx, 0, 0, 0);
- return;
- }
+ KASSERTMSG(xs->xs_idx != 0 && xs->xs_idx < sc->sc_maxslots,
+ "invalid xs_idx %u slot %u", xs->xs_idx, slot);
if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
+ /*
+ * When ED == 0, trb_0 is physical address of the TRB
+ * that caused this event. (6.4.2.1)
+ */
bus_addr_t trbp = xhci_ring_trbp(xr, 0);
/* trb_0 range sanity check */
@@ -1749,7 +1792,20 @@ xhci_event_transfer(struct xhci_softc *
}
int idx = (trb_0 - trbp) / sizeof(struct xhci_trb);
xx = xr->xr_cookies[idx];
+
+ /*
+ * If endpoint is stopped between TDs, TRB pointer points at
+ * next TRB, however, it is not put yet or is a garbage TRB.
+ * That's why xr_cookies may be NULL or look like broken.
+ * Note: this ev happens only when hciversion >= 1.0 or
+ * hciversion == 0.96 and FSE of hcc1 is set.
+ */
+ if (xx == NULL || trbcode == XHCI_TRB_ERROR_LENGTH) {
+ DPRINTFN(1, "xx NULL: #%u: cookie %p: code %u trb_0 %"
+ PRIx64, idx, xx, trbcode, trb_0);
+ }
} else {
+ /* When ED != 0, trb_0 is kaddr of struct xhci_xfer. */
xx = (void *)(uintptr_t)(trb_0 & ~0x3);
}
/* XXX this may not happen */
@@ -1760,24 +1816,24 @@ xhci_event_transfer(struct xhci_softc *
xfer = &xx->xx_xfer;
/* XXX this may happen when detaching */
if (xfer == NULL) {
- DPRINTFN(1, "xfer done: xfer is NULL", 0, 0, 0, 0);
+ DPRINTFN(1, "xx(%p)->xx_xfer is NULL trb_0 %#"PRIx64,
+ xx, trb_0, 0, 0);
return;
}
DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
/* XXX I dunno why this happens */
- KASSERT(xfer->ux_pipe != NULL);
+ KASSERTMSG(xfer->ux_pipe != NULL, "xfer(%p)->ux_pipe is NULL", xfer);
if (!xfer->ux_pipe->up_repeat &&
SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
- DPRINTFN(1, "xfer done: xfer not started", 0, 0, 0, 0);
+ DPRINTFN(1, "xfer(%p)->pipe not queued", xfer, 0, 0, 0);
return;
}
+ /* 4.11.5.2 Event Data TRB */
if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
- DPRINTFN(14, "transfer event data: "
- "0x%016"PRIx64" 0x%08"PRIx32" %02x",
- trb_0, XHCI_TRB_2_REM_GET(trb_2),
- XHCI_TRB_2_ERROR_GET(trb_2), 0);
+ DPRINTFN(14, "transfer Event Data: 0x%016"PRIx64" 0x%08"PRIx32
+ " %02x", trb_0, XHCI_TRB_2_REM_GET(trb_2), trbcode, 0);
if ((trb_0 & 0x3) == 0x3) {
xfer->ux_actlen = XHCI_TRB_2_REM_GET(trb_2);
}
@@ -1792,15 +1848,13 @@ xhci_event_transfer(struct xhci_softc *
break;
case XHCI_TRB_ERROR_STALL:
case XHCI_TRB_ERROR_BABBLE:
- DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
- trbcode, slot, dci, 0);
+ DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0);
xr->is_halted = true;
err = USBD_STALLED;
-#if 1 /* XXX experimental */
/*
* Stalled endpoints can be recoverd by issuing
* command TRB TYPE_RESET_EP on xHCI instead of
- * issuing request CLEAR_PORT_FEATURE UF_ENDPOINT_HALT
+ * issuing request CLEAR_FEATURE UF_ENDPOINT_HALT
* on the endpoint. However, this function may be
* called from softint context (e.g. from umass),
* in that case driver gets KASSERT in cv_timedwait
@@ -1813,25 +1867,13 @@ xhci_event_transfer(struct xhci_softc *
xfer->ux_status = err;
xhci_clear_endpoint_stall_async(xfer);
return;
-#else
- break;
-#endif
- case XHCI_TRB_ERROR_CMD_ABORTED:
- case XHCI_TRB_ERROR_STOPPED:
- err = USBD_CANCELLED;
- break;
- case XHCI_TRB_ERROR_NO_SLOTS:
- err = USBD_NO_ADDR;
- break;
default:
- DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
- trbcode, slot, dci, 0);
+ DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0);
err = USBD_IOERROR;
break;
}
xfer->ux_status = err;
- //mutex_enter(&sc->sc_lock); /* XXX ??? */
if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
if ((trb_0 & 0x3) == 0x0) {
usb_transfer_complete(xfer);
@@ -1839,7 +1881,6 @@ xhci_event_transfer(struct xhci_softc *
} else {
usb_transfer_complete(xfer);
}
- //mutex_exit(&sc->sc_lock); /* XXX ??? */
}
/* Process Command complete events */
@@ -2314,6 +2355,7 @@ xhci_ring_put(struct xhci_softc * const
XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ KASSERT(ntrbs <= XHCI_XFER_NTRB);
for (i = 0; i < ntrbs; i++) {
DPRINTFN(12, "xr %p trbs %p num %zu", xr, trbs, i, 0);
DPRINTFN(12, " %016"PRIx64" %08"PRIx32" %08"PRIx32,
@@ -2563,6 +2605,10 @@ xhci_address_device(struct xhci_softc *
(bsr ? XHCI_TRB_3_BSR_BIT : 0);
err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+
+ if (XHCI_TRB_2_ERROR_GET(trb.trb_2) == XHCI_TRB_ERROR_NO_SLOTS)
+ err = USBD_NO_ADDR;
+
return err;
}
@@ -3099,6 +3145,7 @@ xhci_device_ctrl_start(struct usbd_xfer
req->bmRequestType | (req->bRequest << 8), UGETW(req->wValue),
UGETW(req->wIndex), UGETW(req->wLength));
+#if 0 /* event handler does this */
/* XXX */
if (tr->is_halted) {
DPRINTFN(1, "ctrl xfer %p halted: slot %u dci %u",
@@ -3107,6 +3154,7 @@ xhci_device_ctrl_start(struct usbd_xfer
tr->is_halted = false;
xhci_set_dequeue(xfer->ux_pipe);
}
+#endif
/* we rely on the bottom bits for extra info */
KASSERT(((uintptr_t)xfer & 0x3) == 0x0);
--- sys/dev/usb/xhcireg.h.orig 2015-06-07 01:42:36.000000000 +0900
+++ sys/dev/usb/xhcireg.h 2015-08-31 03:11:04.000000000 +0900
@@ -344,6 +344,7 @@ struct xhci_trb {
#define XHCI_TRB_ERROR_CMD_ABORTED 0x19
#define XHCI_TRB_ERROR_STOPPED 0x1A
#define XHCI_TRB_ERROR_LENGTH 0x1B
+#define XHCI_TRB_ERROR_STOPPED_SHORT 0x1C
#define XHCI_TRB_ERROR_BAD_MELAT 0x1D
#define XHCI_TRB_ERROR_ISOC_OVERRUN 0x1F
#define XHCI_TRB_ERROR_EVENT_LOST 0x20
@@ -407,6 +408,8 @@ struct xhci_trb {
#define XHCI_EPCTX_0_LSA_GET(x) (((x) >> 15) & 0x1)
#define XHCI_EPCTX_0_IVAL_SET(x) (((x) & 0xFF) << 16)
#define XHCI_EPCTX_0_IVAL_GET(x) (((x) >> 16) & 0xFF)
+#define XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(x) __SHIFTIN(x, __BITS(31,24))
+#define XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_GET(x) __SHIFTOUT(x, __BITS(31,24))
#define XHCI_EPCTX_1_CERR_SET(x) (((x) & 0x3) << 1)
#define XHCI_EPCTX_1_CERR_GET(x) (((x) >> 1) & 0x3)
Home |
Main Index |
Thread Index |
Old Index