Module Name: src
Committed By: skrll
Date: Sun Jun 5 10:50:36 UTC 2016
Modified Files:
src/sys/dev/usb [nick-nhusb]: xhci.c
Log Message:
Sync with HEAD
To generate a diff of this commit:
cvs rdiff -u -r1.28.2.70 -r1.28.2.71 src/sys/dev/usb/xhci.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.28.2.70 src/sys/dev/usb/xhci.c:1.28.2.71
--- src/sys/dev/usb/xhci.c:1.28.2.70 Mon May 30 06:48:46 2016
+++ src/sys/dev/usb/xhci.c Sun Jun 5 10:50:36 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: xhci.c,v 1.28.2.70 2016/05/30 06:48:46 skrll Exp $ */
+/* $NetBSD: xhci.c,v 1.28.2.71 2016/06/05 10:50:36 skrll Exp $ */
/*
* Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.70 2016/05/30 06:48:46 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.71 2016/06/05 10:50:36 skrll Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -142,13 +142,16 @@ static usbd_status xhci_configure_endpoi
static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
+static void xhci_host_dequeue(struct xhci_ring * const);
static usbd_status xhci_set_dequeue(struct usbd_pipe *);
static usbd_status xhci_do_command(struct xhci_softc * const,
struct xhci_trb * const, int);
static usbd_status xhci_do_command_locked(struct xhci_softc * const,
struct xhci_trb * const, int);
-static usbd_status xhci_init_slot(struct usbd_device *, uint32_t, uint32_t, int);
+static usbd_status xhci_init_slot(struct usbd_device *, uint32_t);
+static void xhci_free_slot(struct xhci_softc *, struct xhci_slot *, int, int);
+static usbd_status xhci_set_address(struct usbd_device *, uint32_t, bool);
static usbd_status xhci_enable_slot(struct xhci_softc * const,
uint8_t * const);
static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t);
@@ -161,6 +164,12 @@ static usbd_status xhci_ring_init(struct
struct xhci_ring * const, size_t, size_t);
static void xhci_ring_free(struct xhci_softc * const, struct xhci_ring * const);
+static void xhci_setup_ctx(struct usbd_pipe *);
+static void xhci_setup_route(struct usbd_pipe *, uint32_t *);
+static void xhci_setup_tthub(struct usbd_pipe *, uint32_t *);
+static void xhci_setup_maxburst(struct usbd_pipe *, uint32_t *);
+static uint32_t xhci_bival2ival(uint32_t, uint32_t);
+
static void xhci_noop(struct usbd_pipe *);
static usbd_status xhci_root_intr_transfer(struct usbd_xfer *);
@@ -559,7 +568,6 @@ xhci_detach(struct xhci_softc *sc, int f
mutex_destroy(&sc->sc_lock);
mutex_destroy(&sc->sc_intr_lock);
- cv_destroy(&sc->sc_softwake_cv);
pool_cache_destroy(sc->sc_xferpool);
@@ -1020,7 +1028,6 @@ xhci_init(struct xhci_softc *sc)
cv_init(&sc->sc_cmdbusy_cv, "xhcicmdq");
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
- cv_init(&sc->sc_softwake_cv, "xhciab");
/* Set up the bus struct. */
sc->sc_bus.ub_methods = &xhci_bus_methods;
@@ -1029,7 +1036,7 @@ xhci_init(struct xhci_softc *sc)
struct xhci_erste *erst;
erst = KERNADDR(&sc->sc_eventst_dma, 0);
erst[0].erste_0 = htole64(xhci_ring_trbp(&sc->sc_er, 0));
- erst[0].erste_2 = htole32(XHCI_EVENT_RING_TRBS);
+ erst[0].erste_2 = htole32(sc->sc_er.xr_ntrb);
erst[0].erste_3 = htole32(0);
usb_syncmem(&sc->sc_eventst_dma, 0,
XHCI_ERSTE_SIZE * XHCI_EVENT_RING_SEGMENTS, BUS_DMASYNC_PREWRITE);
@@ -1053,7 +1060,7 @@ xhci_init(struct xhci_softc *sc)
xhci_rt_write_4(sc, XHCI_IMOD(0), XHCI_IMOD_DEFAULT_LP);
else
xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
- aprint_debug_dev(sc->sc_dev, "setting IMOD %u\n",
+ aprint_debug_dev(sc->sc_dev, "current IMOD %u\n",
xhci_rt_read_4(sc, XHCI_IMOD(0)));
xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
@@ -1216,269 +1223,8 @@ xhci_xspeed2psspeed(int xspeed)
}
}
-/* construct slot context */
-static void
-xhci_setup_sctx(struct usbd_device *dev, uint32_t *cp)
-{
- usb_device_descriptor_t * const dd = &dev->ud_ddesc;
- int speed = dev->ud_speed;
- int tthubslot, ttportnum;
- bool ishub;
- bool usemtt;
-
- XHCIHIST_FUNC(); XHCIHIST_CALLED();
-
- /*
- * 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.
- * This is 0 if device is not LS/FS device ||
- * parent hub is not HS hub ||
- * attached to root hub.
- * ttportnum:
- * This is the downstream facing port of parent HS hub
- * if LS/FS device is connected.
- * This is 0 if device is not LS/FS device ||
- * parent hub is not HS hub ||
- * attached to root hub.
- */
- if (dev->ud_myhsport != NULL &&
- dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
- (dev->ud_myhub != NULL &&
- dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
- (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
- ttportnum = dev->ud_myhsport->up_portno;
- tthubslot = dev->ud_myhsport->up_parent->ud_addr;
- } else {
- ttportnum = 0;
- tthubslot = 0;
- }
- DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
- dev->ud_myhsport, ttportnum, tthubslot, 0);
-
- /* ishub is valid after reading UDESC_DEVICE */
- ishub = (dd->bDeviceClass == UDCLASS_HUB);
-
- /* dev->ud_hub is valid after reading UDESC_HUB */
- if (ishub && dev->ud_hub) {
- usb_hub_descriptor_t *hd = &dev->ud_hub->uh_hubdesc;
-
- cp[1] |= htole32(XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts));
- cp[2] |= htole32(XHCI_SCTX_2_TT_THINK_TIME_SET(
- __SHIFTOUT(UGETW(hd->wHubCharacteristics), UHD_TT_THINK)));
- DPRINTFN(4, "nports=%d ttt=%d",
- hd->bNbrPorts, XHCI_SCTX_2_TT_THINK_TIME_GET(cp[2]), 0, 0);
- }
-
-#define IS_TTHUB(dd) \
- ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \
- (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT)
-
- /*
- * MTT flag is set if
- * 1. this is HS hub && MTT is enabled
- * or
- * 2. this is not hub && this is LS or FS device &&
- * MTT of parent HS hub (and its parent, too) is enabled
- */
- if (ishub && speed == USB_SPEED_HIGH && IS_TTHUB(dd))
- usemtt = true;
- else if (!ishub &&
- (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) &&
- dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
- (dev->ud_myhub != NULL &&
- dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
- dev->ud_myhsport != NULL &&
- IS_TTHUB(&dev->ud_myhsport->up_parent->ud_ddesc))
- usemtt = true;
- else
- usemtt = false;
- DPRINTFN(4, "class %u proto %u ishub %d usemtt %d",
- dd->bDeviceClass, dd->bDeviceProtocol, ishub, usemtt);
-
- cp[0] |= htole32(
- XHCI_SCTX_0_SPEED_SET(xhci_speed2xspeed(speed)) |
- XHCI_SCTX_0_HUB_SET(ishub ? 1 : 0) |
- XHCI_SCTX_0_MTT_SET(usemtt ? 1 : 0)
- );
- cp[1] |= htole32(0);
- cp[2] |= htole32(
- XHCI_SCTX_2_IRQ_TARGET_SET(0) |
- XHCI_SCTX_2_TT_HUB_SID_SET(tthubslot) |
- XHCI_SCTX_2_TT_PORT_NUM_SET(ttportnum)
- );
- 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;
-}
-
-/*
- * 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 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_slot * const xs = pipe->up_dev->ud_hcpriv;
- 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);
- uint32_t mps = UGETW(ed->wMaxPacketSize);
- uint32_t maxb = 0;
- int speed = pipe->up_dev->ud_speed;
- uint32_t ival = ed->bInterval;
-
- 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_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)) {
- /* 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;
- }
- cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
- }
-
- 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;
-
- ival = xhci_bival2ival(ival, speed);
- cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
- break;
- 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--;
- cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
-
- if (USB_IS_SS(speed)) {
- /* XXX if LEC = 1, set ESIT instead */
- cp[0] |= htole32(XHCI_EPCTX_0_MULT_SET(0));
- }
- break;
- default:
- 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
+ * Construct input contexts and issue TRB to open pipe.
*/
static usbd_status
xhci_configure_endpoint(struct usbd_pipe *pipe)
@@ -1488,32 +1234,21 @@ xhci_configure_endpoint(struct usbd_pipe
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);
+ KASSERT(!mutex_owned(&sc->sc_lock));
+
/* 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);
+ /* set up context */
+ xhci_setup_ctx(pipe);
- /* sync input contexts before they are read from memory */
- usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
hexdump("input control context", xhci_slot_get_icv(sc, xs, 0),
sc->sc_ctxsz * 1);
hexdump("input endpoint context", xhci_slot_get_icv(sc, xs,
@@ -1606,9 +1341,11 @@ xhci_stop_endpoint(struct usbd_pipe *pip
/*
* Set TR Dequeue Pointer.
- * xCHI 1.1 4.6.10 6.4.3.9
- * Purge all of the transfer requests on ring.
- * EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
+ * xHCI 1.1 4.6.10 6.4.3.9
+ * Purge all of the TRBs on ring and reinitialize ring.
+ * Set TR dequeue Pointr to 0 and Cycle State to 1.
+ * EPSTATE of endpoint must be ERROR or STOPPED, otherwise CONTEXT_STATE
+ * error will be generated.
*/
static usbd_status
xhci_set_dequeue(struct usbd_pipe *pipe)
@@ -1623,13 +1360,7 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
XHCIHIST_FUNC(); XHCIHIST_CALLED();
DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
- 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;
+ xhci_host_dequeue(xr);
/* set DCS */
trb.trb_0 = xhci_ring_trbp(xr, 0) | 1; /* XXX */
@@ -1657,9 +1388,13 @@ xhci_open(struct usbd_pipe *pipe)
const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(1, "addr %d depth %d port %d speed %d",
- dev->ud_addr, dev->ud_depth, dev->ud_powersrc->up_portno,
- dev->ud_speed);
+ DPRINTFN(1, "addr %d depth %d port %d speed %d", dev->ud_addr,
+ dev->ud_depth, dev->ud_powersrc->up_portno, dev->ud_speed);
+ DPRINTFN(1, " dci %u type 0x%02x epaddr 0x%02x attr 0x%02x",
+ xhci_ep_get_dci(ed), ed->bDescriptorType, ed->bEndpointAddress,
+ ed->bmAttributes);
+ DPRINTFN(1, " mps %u ival %u", UGETW(ed->wMaxPacketSize), ed->bInterval,
+ 0, 0);
if (sc->sc_dying)
return USBD_IOERROR;
@@ -1764,6 +1499,9 @@ xhci_close_pipe(struct usbd_pipe *pipe)
cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+ /* configure ep context performs an implicit dequeue */
+ xhci_host_dequeue(&xs->xs_ep[dci].xe_tr);
+
/* sync input contexts before they are read from memory */
usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
@@ -1778,7 +1516,6 @@ xhci_close_pipe(struct usbd_pipe *pipe)
/*
* Abort transfer.
- * Called with sc_lock held.
* May be called from softintr context.
*/
static void
@@ -1794,8 +1531,8 @@ xhci_abort_xfer(struct usbd_xfer *xfer,
if (sc->sc_dying) {
/* If we're dying, just do the software part. */
- DPRINTFN(4, "dying", 0, 0, 0, 0);
- xfer->ux_status = status; /* make software ignore it */
+ DPRINTFN(4, "xfer %p dying %u", xfer, xfer->ux_status, 0, 0);
+ xfer->ux_status = status;
callout_stop(&xfer->ux_callout);
usb_transfer_complete(xfer);
return;
@@ -1810,6 +1547,19 @@ xhci_abort_xfer(struct usbd_xfer *xfer,
KASSERT(mutex_owned(&sc->sc_lock));
}
+static void
+xhci_host_dequeue(struct xhci_ring * const xr)
+{
+ /* When dequeueing the controller, update our struct copy too */
+ 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;
+}
+
/*
* Recover STALLed endpoint.
* xHCI 1.1 sect 4.10.2.1
@@ -1931,11 +1681,14 @@ xhci_event_transfer(struct xhci_softc *
* 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);
+ DPRINTFN(1, "Ignore #%u: cookie %p cc %u dci %u",
+ idx, xx, trbcode, dci);
+ DPRINTFN(1, " orig TRB %"PRIx64" type %u", trb_0,
+ XHCI_TRB_3_TYPE_GET(le32toh(xr->xr_trb[idx].trb_3)),
+ 0, 0);
}
} else {
- /* When ED != 0, trb_0 is kaddr of struct xhci_xfer. */
+ /* When ED != 0, trb_0 is virtual addr of struct xhci_xfer. */
xx = (void *)(uintptr_t)(trb_0 & ~0x3);
}
/* XXX this may not happen */
@@ -1972,6 +1725,26 @@ xhci_event_transfer(struct xhci_softc *
switch (trbcode) {
case XHCI_TRB_ERROR_SHORT_PKT:
case XHCI_TRB_ERROR_SUCCESS:
+ /*
+ * A ctrl transfer generates two events if it has a Data stage.
+ * After a successful Data stage we cannot call call
+ * usb_transfer_complete - this can only happen after the Data
+ * stage.
+ *
+ * Note: Data and Status stage events point at same xfer.
+ * ux_actlen and ux_dmabuf will be passed to
+ * usb_transfer_complete after the Status stage event.
+ *
+ * It can be distingished which stage generates the event:
+ * + by checking least 3 bits of trb_0 if ED==1.
+ * (see xhci_device_ctrl_start).
+ * + by checking the type of original TRB if ED==0.
+ *
+ * In addition, intr, bulk, and isoc transfer currently
+ * consists of single TD, so the "skip" is not needed.
+ * ctrl xfer uses EVENT_DATA, and others do not.
+ * Thus driver can switch the flow by checking ED bit.
+ */
xfer->ux_actlen =
xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
err = USBD_NORMAL_COMPLETION;
@@ -2017,8 +1790,7 @@ xhci_event_transfer(struct xhci_softc *
/* Process Command complete events */
static void
-xhci_event_cmd(struct xhci_softc * const sc,
- const struct xhci_trb * const trb)
+xhci_event_cmd(struct xhci_softc * const sc, const struct xhci_trb * const trb)
{
uint64_t trb_0;
uint32_t trb_2, trb_3;
@@ -2118,7 +1890,7 @@ xhci_softintr(void *v)
i = er->xr_ep;
j = er->xr_cs;
- DPRINTFN(16, "xr_ep %d xr_cs %d", i, j, 0, 0);
+ DPRINTFN(16, "er: xr_ep %d xr_cs %d", i, j, 0, 0);
while (1) {
usb_syncmem(&er->xr_dma, XHCI_TRB_SIZE * i, XHCI_TRB_SIZE,
@@ -2132,7 +1904,7 @@ xhci_softintr(void *v)
xhci_handle_event(sc, trb);
i++;
- if (i == XHCI_EVENT_RING_TRBS) {
+ if (i == er->xr_ntrb) {
i = 0;
j ^= 1;
}
@@ -2222,6 +1994,7 @@ extern uint32_t usb_cookie_no;
* Determine initial MaxPacketSize (mps) by speed.
* Read full device descriptor.
* Register this device.
+ * Finally state of device transitions ADDRESSED.
*/
static usbd_status
xhci_new_device(device_t parent, struct usbd_bus *bus, int depth,
@@ -2231,33 +2004,39 @@ xhci_new_device(device_t parent, struct
struct usbd_device *dev;
usbd_status err;
usb_device_descriptor_t *dd;
- struct usbd_device *hub;
- struct usbd_device *adev;
- int rhport = 0;
struct xhci_slot *xs;
uint32_t *cp;
- uint32_t route = 0;
- uint8_t slot = 0;
- uint8_t addr;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "port=%d depth=%d speed=%d upport %d",
- port, depth, speed, up->up_portno);
+ DPRINTFN(4, "port %u depth %u speed %u up %p", port, depth, speed, up);
dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
if (dev == NULL)
return USBD_NOMEM;
dev->ud_bus = bus;
-
- /* Set up default endpoint handle. */
- dev->ud_ep0.ue_edesc = &dev->ud_ep0desc;
-
- /* Set up default endpoint descriptor. */
- dev->ud_ep0desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
+ dev->ud_quirks = &usbd_no_quirk;
+ dev->ud_addr = 0;
+ dev->ud_ddesc.bMaxPacketSize = 0;
+ dev->ud_depth = depth;
+ dev->ud_powersrc = up;
+ dev->ud_myhub = up->up_parent;
+ dev->ud_speed = speed;
+ dev->ud_langid = USBD_NOLANG;
+ dev->ud_cookie.cookie = ++usb_cookie_no;
+
+ /* Set up default endpoint handle. */
+ dev->ud_ep0.ue_edesc = &dev->ud_ep0desc;
+ /* doesn't matter, just don't let it uninitialized */
+ dev->ud_ep0.ue_toggle = 0;
+
+ /* Set up default endpoint descriptor. */
+ dev->ud_ep0desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT;
dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
dev->ud_ep0desc.bmAttributes = UE_CONTROL;
+ dev->ud_ep0desc.bInterval = 0;
+
/* 4.3, 4.8.2.1 */
switch (speed) {
case USB_SPEED_SUPER:
@@ -2274,70 +2053,9 @@ xhci_new_device(device_t parent, struct
USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET);
break;
}
- dev->ud_ep0desc.bInterval = 0;
-
- /* doesn't matter, just don't let it uninitialized */
- dev->ud_ep0.ue_toggle = 0;
-
- DPRINTFN(4, "up %p portno %d", up, up->up_portno, 0, 0);
-
- dev->ud_quirks = &usbd_no_quirk;
- dev->ud_addr = 0;
- dev->ud_ddesc.bMaxPacketSize = 0;
- dev->ud_depth = depth;
- dev->ud_powersrc = up;
- dev->ud_myhub = up->up_parent;
up->up_dev = dev;
- /* Locate root hub port */
- for (hub = dev; hub != NULL; hub = hub->ud_myhub) {
- uint32_t dep;
-
- DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
- hub, hub->ud_depth, hub->ud_powersrc,
- hub->ud_powersrc ? hub->ud_powersrc->up_portno : -1);
-
- if (hub->ud_powersrc == NULL)
- break;
- dep = hub->ud_depth;
- if (dep == 0)
- break;
- rhport = hub->ud_powersrc->up_portno;
- if (dep > USB_HUB_MAX_DEPTH)
- continue;
-
- route |=
- (rhport > UHD_SS_NPORTS_MAX ? UHD_SS_NPORTS_MAX : rhport)
- << ((dep - 1) * 4);
- }
- route = route >> 4;
- DPRINTFN(4, "rhport %d Route %05x hub %p", rhport, route, hub, 0);
-
- /* Locate port on upstream high speed hub */
- for (adev = dev, hub = up->up_parent;
- hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
- adev = hub, hub = hub->ud_myhub)
- ;
- if (hub) {
- int p;
- for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
- if (hub->ud_hub->uh_ports[p].up_dev == adev) {
- dev->ud_myhsport = &hub->ud_hub->uh_ports[p];
- goto found;
- }
- }
- panic("xhci_new_device: cannot find HS port");
- found:
- DPRINTFN(4, "high speed port %d", p, 0, 0, 0);
- } else {
- dev->ud_myhsport = NULL;
- }
-
- dev->ud_speed = speed;
- dev->ud_langid = USBD_NOLANG;
- dev->ud_cookie.cookie = ++usb_cookie_no;
-
/* Establish the default pipe. */
err = usbd_setup_pipe(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
&dev->ud_pipe0);
@@ -2357,12 +2075,18 @@ xhci_new_device(device_t parent, struct
if (err)
goto bad;
} else {
+ uint8_t slot = 0;
+
+ /* 4.3.2 */
err = xhci_enable_slot(sc, &slot);
if (err)
goto bad;
+
xs = &sc->sc_slots[slot];
dev->ud_hcpriv = xs;
- err = xhci_init_slot(dev, slot, route, rhport);
+
+ /* 4.3.3 initialize slot structure */
+ err = xhci_init_slot(dev, slot);
if (err) {
dev->ud_hcpriv = NULL;
/*
@@ -2376,11 +2100,17 @@ xhci_new_device(device_t parent, struct
goto bad;
}
+ /* 4.3.4 Address Assignment */
+ err = xhci_set_address(dev, slot, false);
+ if (err)
+ goto bad;
+
/* Allow device time to set new address */
usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
+
cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT);
//hexdump("slot context", cp, sc->sc_ctxsz);
- addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]);
+ uint8_t addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]);
DPRINTFN(4, "device address %u", addr, 0, 0, 0);
/* XXX ensure we know when the hardware does something
we can't yet cope with */
@@ -2393,6 +2123,7 @@ xhci_new_device(device_t parent, struct
err = usbd_get_initial_ddesc(dev, dd);
if (err)
goto bad;
+
/* 4.8.2.1 */
if (USB_IS_SS(speed)) {
if (dd->bMaxPacketSize != 9) {
@@ -2410,6 +2141,7 @@ xhci_new_device(device_t parent, struct
DPRINTFN(4, "bMaxPacketSize %u", dd->bMaxPacketSize, 0, 0, 0);
xhci_update_ep0_mps(sc, xs,
UGETW(dev->ud_ep0desc.wMaxPacketSize));
+
err = usbd_reload_device_desc(dev);
if (err)
goto bad;
@@ -2460,11 +2192,8 @@ xhci_ring_init(struct xhci_softc * const
xr->xr_cookies = kmem_zalloc(sizeof(*xr->xr_cookies) * ntrb, KM_SLEEP);
xr->xr_trb = xhci_ring_trbv(xr, 0);
xr->xr_ntrb = ntrb;
- xr->xr_ep = 0;
- xr->xr_cs = 1;
- memset(xr->xr_trb, 0, size);
- usb_syncmem(&xr->xr_dma, 0, size, BUS_DMASYNC_PREWRITE);
xr->is_halted = false;
+ xhci_host_dequeue(xr);
return USBD_NORMAL_COMPLETION;
}
@@ -2567,7 +2296,7 @@ xhci_ring_put(struct xhci_softc * const
}
xhci_trb_put(&xr->xr_trb[xr->xr_ep], parameter, status, control);
- usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,
+ usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * xr->xr_ep, XHCI_TRB_SIZE * 1,
BUS_DMASYNC_PREWRITE);
xr->xr_cookies[xr->xr_ep] = cookie;
@@ -2579,7 +2308,7 @@ xhci_ring_put(struct xhci_softc * const
/*
* Stop execution commands, purge all commands on command ring, and
- * rewind enqueue pointer.
+ * rewind dequeue pointer.
*/
static void
xhci_abort_command(struct xhci_softc *sc)
@@ -2619,14 +2348,14 @@ xhci_abort_command(struct xhci_softc *sc
/*
* Put a command on command ring, ring bell, set timer, and cv_timedwait.
- * Command completion is notified by cv_signal from xhci_handle_event
- * (called from interrupt from xHCI), or timed-out.
- * Command validation is performed in xhci_handle_event by checking if
- * trb_0 in CMD_COMPLETE TRB and sc->sc_command_addr are identical.
+ * Command completion is notified by cv_signal from xhci_event_cmd()
+ * (called from xhci_softint), or timed-out.
+ * The completion code is copied to sc->sc_result_trb in xhci_event_cmd(),
+ * then do_command examines it.
*/
static usbd_status
-xhci_do_command_locked(struct xhci_softc * const sc, struct xhci_trb * const trb,
- int timeout)
+xhci_do_command_locked(struct xhci_softc * const sc,
+ struct xhci_trb * const trb, int timeout)
{
struct xhci_ring * const cr = &sc->sc_cr;
usbd_status err;
@@ -2750,12 +2479,7 @@ xhci_disable_slot(struct xhci_softc * co
if (!err) {
xs = &sc->sc_slots[slot];
if (xs->xs_idx != 0) {
- for (int i = XHCI_DCI_SLOT + 1; i < 32; i++) {
- xhci_ring_free(sc, &xs->xs_ep[i].xe_tr);
- memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i]));
- }
- usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
- usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
+ xhci_free_slot(sc, xs, XHCI_DCI_SLOT + 1, 32);
xhci_set_dcba(sc, 0, slot);
memset(xs, 0, sizeof(*xs));
}
@@ -2842,23 +2566,19 @@ xhci_set_dcba(struct xhci_softc * const
}
/*
- * Allocate DMA buffer and ring buffer for specified slot
- * and set Device Context Base Address
- * and issue Set Address device command.
+ * Allocate device and input context DMA buffer, and
+ * TRB DMA buffer for each endpoint.
*/
static usbd_status
-xhci_init_slot(struct usbd_device *dev, uint32_t slot, uint32_t route, int rhport)
+xhci_init_slot(struct usbd_device *dev, uint32_t slot)
{
struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus);
struct xhci_slot *xs;
usbd_status err;
u_int dci;
- uint32_t *cp;
- uint32_t mps = UGETW(dev->ud_ep0desc.wMaxPacketSize);
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "slot %u speed %d route %05x rhport %d",
- slot, dev->ud_speed, route, rhport);
+ DPRINTFN(4, "slot %u", slot, 0, 0, 0);
xs = &sc->sc_slots[slot];
@@ -2888,64 +2608,463 @@ xhci_init_slot(struct usbd_device *dev,
}
}
+ bad2:
+ if (err == USBD_NORMAL_COMPLETION) {
+ xs->xs_idx = slot;
+ } else {
+ xhci_free_slot(sc, xs, XHCI_DCI_SLOT + 1, dci);
+ }
+
+ return err;
+
+ bad1:
+ usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
+ xs->xs_idx = 0;
+ return err;
+}
+
+static void
+xhci_free_slot(struct xhci_softc *sc, struct xhci_slot *xs, int start_dci,
+ int end_dci)
+{
+ u_int dci;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ DPRINTFN(4, "slot %u start %u end %u", xs->xs_idx, start_dci, end_dci,
+ 0);
+
+ for (dci = start_dci; dci < end_dci; dci++) {
+ xhci_ring_free(sc, &xs->xs_ep[dci].xe_tr);
+ memset(&xs->xs_ep[dci], 0, sizeof(xs->xs_ep[dci]));
+ }
+ usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
+ usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
+ xs->xs_idx = 0;
+}
+
+/*
+ * Setup slot context, set Device Context Base Address, and issue
+ * Set Address Device command.
+ */
+static usbd_status
+xhci_set_address(struct usbd_device *dev, uint32_t slot, bool bsr)
+{
+ struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus);
+ struct xhci_slot *xs;
+ usbd_status err;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ DPRINTFN(4, "slot %u bsr %u", slot, bsr, 0, 0);
+
+ xs = &sc->sc_slots[slot];
+
+ xhci_setup_ctx(dev->ud_pipe0);
+
+ hexdump("input context", xhci_slot_get_icv(sc, xs, 0),
+ sc->sc_ctxsz * 3);
+
+ xhci_set_dcba(sc, DMAADDR(&xs->xs_dc_dma, 0), slot);
+
+ err = xhci_address_device(sc, xhci_slot_get_icp(sc, xs, 0), slot, bsr);
+
+ usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
+ hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),
+ sc->sc_ctxsz * 2);
+
+ return err;
+}
+
+/*
+ * 4.8.2, 6.2.3.2
+ * construct slot/endpoint context parameters and do syncmem
+ */
+static void
+xhci_setup_ctx(struct usbd_pipe *pipe)
+{
+ struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
+ struct usbd_device *dev = pipe->up_dev;
+ struct xhci_slot * const xs = dev->ud_hcpriv;
+ 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);
+ uint32_t *cp;
+ uint16_t mps = UGETW(ed->wMaxPacketSize);
+ uint8_t speed = dev->ud_speed;
+ uint8_t ival = ed->bInterval;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ DPRINTFN(4, "pipe %p: slot %u dci %u speed %u", pipe, xs->xs_idx, dci,
+ speed);
+
/* set up initial input control context */
cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
cp[0] = htole32(0);
- cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(XHCI_DCI_EP_CONTROL)|
- XHCI_INCTX_1_ADD_MASK(XHCI_DCI_SLOT));
+ cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(dci));
+ if (dci == XHCI_DCI_EP_CONTROL)
+ cp[1] |= htole32(XHCI_INCTX_1_ADD_MASK(XHCI_DCI_SLOT));
+ cp[7] = htole32(0);
/* set up input slot context */
cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
- xhci_setup_sctx(dev, cp);
- cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(1));
- cp[0] |= htole32(XHCI_SCTX_0_ROUTE_SET(route));
- cp[1] |= htole32(XHCI_SCTX_1_RH_PORT_SET(rhport));
+ cp[0] =
+ XHCI_SCTX_0_CTX_NUM_SET(dci) |
+ XHCI_SCTX_0_SPEED_SET(xhci_speed2xspeed(speed));
+ cp[1] = 0;
+ cp[2] = XHCI_SCTX_2_IRQ_TARGET_SET(0);
+ cp[3] = 0;
+ xhci_setup_route(pipe, cp);
+ xhci_setup_tthub(pipe, cp);
+
+ cp[0] = htole32(cp[0]);
+ cp[1] = htole32(cp[1]);
+ cp[2] = htole32(cp[2]);
+ cp[3] = htole32(cp[3]);
- /* set up input EP0 context */
- cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_EP_CONTROL));
- cp[0] = htole32(0);
- cp[1] = htole32(
- XHCI_EPCTX_1_MAXP_SIZE_SET(mps) |
- XHCI_EPCTX_1_EPTYPE_SET(4) |
- XHCI_EPCTX_1_CERR_SET(3)
- );
+ /* set up input endpoint context */
+ cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
+ cp[0] =
+ XHCI_EPCTX_0_EPSTATE_SET(0) |
+ XHCI_EPCTX_0_MULT_SET(0) |
+ XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
+ XHCI_EPCTX_0_LSA_SET(0) |
+ XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(0);
+ cp[1] =
+ 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] |= XHCI_EPCTX_1_CERR_SET(3);
+
+ if (xfertype == UE_CONTROL)
+ cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); /* 6.2.3 */
+ else if (USB_IS_SS(speed))
+ cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(mps);
+ else
+ cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(UE_GET_SIZE(mps));
+
+ xhci_setup_maxburst(pipe, cp);
+
+ 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;
+
+ ival = xhci_bival2ival(ival, speed);
+ cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
+ break;
+ 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--;
+ cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
+ break;
+ default:
+ break;
+ }
+ DPRINTFN(4, "setting ival %u MaxBurst %#x",
+ XHCI_EPCTX_0_IVAL_GET(cp[0]), XHCI_EPCTX_1_MAXB_GET(cp[1]), 0, 0);
+
+ /* rewind TR dequeue pointer in xHC */
/* can't use xhci_ep_get_dci() yet? */
*(uint64_t *)(&cp[2]) = htole64(
- xhci_ring_trbp(&xs->xs_ep[XHCI_DCI_EP_CONTROL].xe_tr, 0) |
+ xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
XHCI_EPCTX_2_DCS_SET(1));
- cp[4] = htole32(
- XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)
- );
+
+ cp[0] = htole32(cp[0]);
+ cp[1] = htole32(cp[1]);
+ cp[4] = htole32(cp[4]);
+
+ /* rewind TR dequeue pointer in driver */
+ struct xhci_ring *xr = &xs->xs_ep[dci].xe_tr;
+ mutex_enter(&xr->xr_lock);
+ xhci_host_dequeue(xr);
+ mutex_exit(&xr->xr_lock);
/* sync input contexts before they are read from memory */
usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
- hexdump("input context", xhci_slot_get_icv(sc, xs, 0),
- sc->sc_ctxsz * 3);
+}
- xhci_set_dcba(sc, DMAADDR(&xs->xs_dc_dma, 0), slot);
+/*
+ * Setup route string and roothub port of given device for slot context
+ */
+static void
+xhci_setup_route(struct usbd_pipe *pipe, uint32_t *cp)
+{
+ struct usbd_device *dev = pipe->up_dev;
+ struct usbd_port *up = dev->ud_powersrc;
+ struct usbd_device *hub;
+ struct usbd_device *adev;
+ uint8_t rhport = 0;
+ uint32_t route = 0;
- err = xhci_address_device(sc, xhci_slot_get_icp(sc, xs, 0), slot,
- false);
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
- usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
- hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),
- sc->sc_ctxsz * 2);
+ /* Locate root hub port and Determine route string */
+ /* 4.3.3 route string does not include roothub port */
+ for (hub = dev; hub != NULL; hub = hub->ud_myhub) {
+ uint32_t dep;
- bad2:
- if (err == USBD_NORMAL_COMPLETION) {
- xs->xs_idx = slot;
+ DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
+ hub, hub->ud_depth, hub->ud_powersrc,
+ hub->ud_powersrc ? hub->ud_powersrc->up_portno : -1);
+
+ if (hub->ud_powersrc == NULL)
+ break;
+ dep = hub->ud_depth;
+ if (dep == 0)
+ break;
+ rhport = hub->ud_powersrc->up_portno;
+ if (dep > USB_HUB_MAX_DEPTH)
+ continue;
+
+ route |=
+ (rhport > UHD_SS_NPORTS_MAX ? UHD_SS_NPORTS_MAX : rhport)
+ << ((dep - 1) * 4);
+ }
+ route = route >> 4;
+ DPRINTFN(4, "rhport %u Route %05x hub %p", rhport, route, hub, 0);
+
+ /* Locate port on upstream high speed hub */
+ for (adev = dev, hub = up->up_parent;
+ hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
+ adev = hub, hub = hub->ud_myhub)
+ ;
+ if (hub) {
+ int p;
+ for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
+ if (hub->ud_hub->uh_ports[p].up_dev == adev) {
+ dev->ud_myhsport = &hub->ud_hub->uh_ports[p];
+ goto found;
+ }
+ }
+ panic("xhci_setup_route: cannot find HS port");
+ found:
+ DPRINTFN(4, "high speed port %d", p, 0, 0, 0);
+ } else {
+ dev->ud_myhsport = NULL;
+ }
+
+ cp[0] |= XHCI_SCTX_0_ROUTE_SET(route);
+ cp[1] |= XHCI_SCTX_1_RH_PORT_SET(rhport);
+}
+
+/*
+ * Setup whether device is hub, whether device uses MTT, and
+ * TT informations if it uses MTT.
+ */
+static void
+xhci_setup_tthub(struct usbd_pipe *pipe, uint32_t *cp)
+{
+ struct usbd_device *dev = pipe->up_dev;
+ usb_device_descriptor_t * const dd = &dev->ud_ddesc;
+ uint32_t speed = dev->ud_speed;
+ uint8_t tthubslot, ttportnum;
+ bool ishub;
+ bool usemtt;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ /*
+ * 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.
+ * This is 0 if device is not LS/FS device ||
+ * parent hub is not HS hub ||
+ * attached to root hub.
+ * ttportnum:
+ * This is the downstream facing port of parent HS hub
+ * if LS/FS device is connected.
+ * This is 0 if device is not LS/FS device ||
+ * parent hub is not HS hub ||
+ * attached to root hub.
+ */
+ if (dev->ud_myhsport != NULL &&
+ dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+ (dev->ud_myhub != NULL &&
+ dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+ (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
+ ttportnum = dev->ud_myhsport->up_portno;
+ tthubslot = dev->ud_myhsport->up_parent->ud_addr;
} else {
- for (int i = 1; i < dci; i++) {
- xhci_ring_free(sc, &xs->xs_ep[i].xe_tr);
- memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i]));
+ ttportnum = 0;
+ tthubslot = 0;
+ }
+ DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
+ dev->ud_myhsport, ttportnum, tthubslot, 0);
+
+ /* ishub is valid after reading UDESC_DEVICE */
+ ishub = (dd->bDeviceClass == UDCLASS_HUB);
+
+ /* dev->ud_hub is valid after reading UDESC_HUB */
+ if (ishub && dev->ud_hub) {
+ usb_hub_descriptor_t *hd = &dev->ud_hub->uh_hubdesc;
+ uint8_t ttt =
+ __SHIFTOUT(UGETW(hd->wHubCharacteristics), UHD_TT_THINK);
+
+ cp[1] |= XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts);
+ cp[2] |= XHCI_SCTX_2_TT_THINK_TIME_SET(ttt);
+ DPRINTFN(4, "nports=%d ttt=%d", hd->bNbrPorts, ttt, 0, 0);
+ }
+
+#define IS_TTHUB(dd) \
+ ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \
+ (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT)
+
+ /*
+ * MTT flag is set if
+ * 1. this is HS hub && MTT is enabled
+ * or
+ * 2. this is not hub && this is LS or FS device &&
+ * MTT of parent HS hub (and its parent, too) is enabled
+ */
+ if (ishub && speed == USB_SPEED_HIGH && IS_TTHUB(dd))
+ usemtt = true;
+ else if (!ishub &&
+ (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) &&
+ dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+ (dev->ud_myhub != NULL &&
+ dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+ dev->ud_myhsport != NULL &&
+ IS_TTHUB(&dev->ud_myhsport->up_parent->ud_ddesc))
+ usemtt = true;
+ else
+ usemtt = false;
+ DPRINTFN(4, "class %u proto %u ishub %d usemtt %d",
+ dd->bDeviceClass, dd->bDeviceProtocol, ishub, usemtt);
+
+#undef IS_TTHUB
+
+ cp[0] |=
+ XHCI_SCTX_0_HUB_SET(ishub ? 1 : 0) |
+ XHCI_SCTX_0_MTT_SET(usemtt ? 1 : 0);
+ cp[2] |=
+ XHCI_SCTX_2_TT_HUB_SID_SET(tthubslot) |
+ XHCI_SCTX_2_TT_PORT_NUM_SET(ttportnum);
+}
+
+/* set up params for periodic endpoint */
+static void
+xhci_setup_maxburst(struct usbd_pipe *pipe, uint32_t *cp)
+{
+ struct usbd_device *dev = pipe->up_dev;
+ usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+ const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+ usbd_desc_iter_t iter;
+ const usb_cdc_descriptor_t *cdcd;
+ uint32_t maxb = 0;
+ uint16_t mps = UGETW(ed->wMaxPacketSize);
+ uint8_t speed = dev->ud_speed;
+ uint8_t ep;
+
+ /* config desc is NULL when opening ep0 */
+ if (dev == NULL || dev->ud_cdesc == NULL)
+ goto no_cdcd;
+ cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(dev,
+ UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
+ if (cdcd == NULL)
+ goto no_cdcd;
+ usb_desc_iter_init(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;
}
- usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
- bad1:
- usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
- xs->xs_idx = 0;
+ }
+ if (cdcd != NULL && cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
+ const usb_endpoint_ss_comp_descriptor_t * esscd =
+ (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
+ maxb = esscd->bMaxBurst;
}
- return err;
+ no_cdcd:
+ /* 6.2.3.4, 4.8.2.4 */
+ if (USB_IS_SS(speed)) {
+ /* UBS 3.1 9.6.6 */
+ cp[1] |= XHCI_EPCTX_1_MAXP_SIZE_SET(mps);
+ /* UBS 3.1 9.6.7 */
+ cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
+#ifdef notyet
+ if (xfertype == UE_ISOCHRONOUS) {
+ }
+ if (XHCI_HCC2_LEC(sc->sc_hcc2) != 0) {
+ /* use ESIT */
+ cp[4] |= XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(x);
+ cp[0] |= XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(x);
+
+ /* XXX if LEC = 1, set ESIT instead */
+ cp[0] |= XHCI_EPCTX_0_MULT_SET(0);
+ } else {
+ /* use ival */
+ }
+#endif
+ } else {
+ /* UBS 2.0 9.6.6 */
+ cp[1] |= 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;
+ }
+ cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
+ }
+}
+
+/*
+ * 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 uint32_t
+xhci_bival2ival(uint32_t ival, uint32_t 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;
}
/* ----- */