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