Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Aug 2010 12:41:42 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 182075 for review
Message-ID:  <201008081241.o78Cfg3h090927@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@182075?ac=10

Change 182075 by hselasky@hselasky_laptop001 on 2010/08/08 12:41:08

	USB controller (XHCI):
		- fixes for double buffering and endpoint configuration.
		- correct some wrong definitions in xhci.h

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#16 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#18 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#16 (text+ko) ====

@@ -121,11 +121,8 @@
 static void xhci_free_device_ext(struct usb_device *udev);
 static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, struct usb_endpoint_descriptor *);
 static usb_proc_callback_t xhci_configure_msg;
-static usb_error_t xhci_configure_reset_endpoint(struct usb_xfer *);
 static usb_error_t xhci_configure_device(struct usb_device *);
 static usb_error_t xhci_configure_endpoint(struct usb_device *, struct usb_endpoint_descriptor *, uint64_t, uint16_t, uint8_t, uint16_t, uint16_t);
-static usb_error_t xhci_configure_endpoint_by_xfer(struct usb_xfer *);
-static usb_error_t xhci_set_address(struct usb_device *, struct mtx *, uint16_t);
 static usb_error_t xhci_configure_mask(struct usb_device *, uint32_t, uint8_t);
 
 extern struct usb_bus_methods xhci_bus_methods;
@@ -628,6 +625,7 @@
 		err = xhci_generic_done_sub(xfer);
 
 done:
+	/* transfer is complete */
 	xhci_device_done(xfer, err);
 }
 
@@ -637,14 +635,14 @@
 static void
 xhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb)
 {
-	struct usb_xfer *xfer;
-	struct xhci_td *td;
-	struct xhci_endpoint_ext *pepext;
 	uint64_t td_event;
 	uint32_t temp;
 	uint32_t remainder;
 	uint8_t status;
 	uint8_t halted;
+	uint8_t epno;
+	uint8_t index;
+	uint8_t i;
 
 	/* decode TRB */
 	td_event = le64toh(trb->qwTrb0);
@@ -653,29 +651,44 @@
 	remainder = XHCI_TRB_2_REM_GET(temp);
 	status = XHCI_TRB_2_ERROR_GET(temp);
 
+	temp = le32toh(trb->dwTrb3);
+	epno = XHCI_TRB_3_EP_GET(temp) + 1;
+	index = XHCI_TRB_3_SLOT_GET(temp);
+
 	/* check if error means halted */
 	halted = (status != XHCI_TRB_ERROR_SHORT_PKT) &&
 	    (status != XHCI_TRB_ERROR_SUCCESS);
 
-	DPRINTF("remainder=%u status=%u\n", remainder, status);
+	DPRINTF("slot=%u epno=%u remainder=%u status=%u\n",
+	    index, epno, remainder, status);
+
+	if (index > sc->sc_noslot) {
+		DPRINTF("Invalid slot.\n");
+		return;
+	}
+
+	epno++;
+
+	if (epno >= XHCI_MAX_ENDPOINTS) {
+		DPRINTF("Invalid endpoint.\n");
+		return;
+	}
 
 	/* try to find the USB transfer that generated the event */
-	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+	for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) {
+		struct usb_xfer *xfer;
+		struct xhci_td *td;
+		struct xhci_endpoint_ext *pepext;
 
-		/* check if transfer is cancelling */
-		if (xfer->flags_int.did_dma_delay)
-			continue;
+		pepext = &sc->sc_hw.devs[index].endp[epno];
 
-		pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
-		    xfer->endpoint->edesc);
-
-		/* check if endpoint is halted */
-		if (pepext->trb_halted != 0)
+		xfer = pepext->xfer[i];
+		if (xfer == NULL)
 			continue;
 
 		td = xfer->td_transfer_cache;
 
-		DPRINTF("0x%08llx == (0x%08llx .. 0x%08llx)\n",
+		DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n",
 			(long long)td_event,
 			(long long)td->td_self,
 			(long long)td->td_event_last);
@@ -684,13 +697,15 @@
 		    (halted && (td_event >= td->td_self) &&
 		    (td_event < td->td_event_last))) {
 
-			struct xhci_endpoint_ext *pepext;
+			usb_pc_cpu_invalidate(td->page_cache);
 
-			pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
-			    xfer->endpoint->edesc);
+			if (xfer->flags_int.isochronous_xfr) {
+				if (halted) {
+					halted = 0;
+					remainder = td->len;
+				}
+			}
 
-			usb_pc_cpu_invalidate(td->page_cache);
-
 			/* "td->remainder" is verified later */
 			td->remainder = remainder;
 			td->status = status;
@@ -1126,7 +1141,6 @@
 		err = USB_ERR_IOERROR;
 		break;
 	}
-
 	XHCI_CMD_UNLOCK(sc);
 
 	if (mtx != NULL)
@@ -1190,7 +1204,7 @@
 	trb.dwTrb2 = 0;
 	temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) |
 	    XHCI_TRB_3_SLOT_SET(slot_id) |
-	    XHCI_TRB_3_SLOT_SET(ep_id);
+	    XHCI_TRB_3_EP_SET(ep_id);
 
 	if (preserve)
 		temp |= XHCI_TRB_3_PRSV_BIT;
@@ -1201,6 +1215,28 @@
 }
 
 static usb_error_t
+xhci_cmd_set_tr_dequeue_ptr(struct xhci_softc *sc, uint64_t dequeue_ptr,
+    uint16_t stream_id, uint8_t ep_id, uint8_t slot_id)
+{
+	struct xhci_trb trb;
+	uint32_t temp;
+
+	DPRINTF("\n");
+
+	trb.qwTrb0 = htole64(dequeue_ptr);
+
+	temp = XHCI_TRB_2_STREAM_SET(stream_id);
+	trb.dwTrb2 = htole32(temp);
+
+	temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE) |
+	    XHCI_TRB_3_SLOT_SET(slot_id) |
+	    XHCI_TRB_3_EP_SET(ep_id);
+	trb.dwTrb3 = htole32(temp);
+
+	return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
+static usb_error_t
 xhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend,
     uint8_t ep_id, uint8_t slot_id)
 {
@@ -1213,7 +1249,7 @@
 	trb.dwTrb2 = 0;
 	temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) |
 	    XHCI_TRB_3_SLOT_SET(slot_id) |
-	    XHCI_TRB_3_SLOT_SET(ep_id);
+	    XHCI_TRB_3_EP_SET(ep_id);
 
 	if (suspend)
 		temp |= XHCI_TRB_3_SUSP_EP_BIT;
@@ -1223,6 +1259,7 @@
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
 
+#if 0
 static usb_error_t
 xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id)
 {
@@ -1240,6 +1277,7 @@
 
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
+#endif
 
 /*------------------------------------------------------------------------*
  *	xhci_interrupt - XHCI interrupt handler
@@ -1300,21 +1338,11 @@
 xhci_timeout(void *arg)
 {
 	struct usb_xfer *xfer = arg;
-	struct xhci_endpoint_ext *pepext;
 
 	DPRINTF("xfer=%p\n", xfer);
 
 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
 
-	pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
-	    xfer->endpoint->edesc);
-
-#if 0
-	/* check if endpoint is halted */
-	if (pepext->trb_halted != 0)
-		return;
-#endif
-
 	/* transfer is transferred */
 	xhci_device_done(xfer, USB_ERR_TIMEOUT);
 }
@@ -2018,7 +2046,7 @@
 			route |= rh_port;
 	}
 
-	temp = XHCI_SCTX_0_CTX_NUM_SET(1) | /* XXX XHCI_MAX_ENDPOINTS - 1) | */
+	temp = XHCI_SCTX_0_CTX_NUM_SET(XHCI_MAX_ENDPOINTS - 1) |
 	    XHCI_SCTX_0_ROUTE_SET(route);
 
 	switch (udev->speed) {
@@ -2252,8 +2280,12 @@
 
 		pepext->trb_used--;
 
-		if (error)
+		pepext->xfer[xfer->qh_pos] = NULL;
+
+		if (error && (pepext->trb_running != 0)) {
 			pepext->trb_halted = 1;
+			pepext->trb_running = 0;
+		}
 	}
 }
 
@@ -2274,10 +2306,6 @@
 	pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
 	    xfer->endpoint->edesc);
 
-	/* check for halt condition */
-	if (pepext->trb_halted != 0)
-		return (0);
-
 	td_first = xfer->td_transfer_first;
 	td_last = xfer->td_transfer_last;
 	addr = pepext->physaddr;
@@ -2287,10 +2315,30 @@
 		return (USB_ERR_NOMEM);
 	}
 
+	/* check if transfer is not already on interrupt queue */
+	if (xfer->wait_queue != &xfer->xroot->bus->intr_q) {
+
+		/* remove transfer from pipe queue, if any */
+
+		usbd_transfer_dequeue(xfer);
+
+		/* add transfer last on interrupt queue */
+
+		usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
+	}
+
+	/* check for stopped condition, after putting transfer on interrupt queue */
+	if (pepext->trb_running == 0) {
+		struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+
+		/* start configuration */
+		(void)usb_proc_msignal(&sc->sc_config_proc,
+		    &sc->sc_config_msg[0], &sc->sc_config_msg[1]);
+		return (0);
+	}
+
 	pepext->trb_used++;
 
-	xfer->flags_int.bandwidth_reclaimed = 1;
-
 	/* get current TRB index */
 	i = pepext->trb_index;
 
@@ -2338,6 +2386,12 @@
 
 	usb_pc_cpu_flush(pepext->page_cache);
 
+	pepext->xfer[i] = xfer;
+
+	xfer->qh_pos = i;
+
+	xfer->flags_int.bandwidth_reclaimed = 1;
+
 	pepext->trb_index = inext;
 
 	xhci_endpoint_doorbell(xfer);
@@ -2418,13 +2472,8 @@
 	/* setup TD's and QH */
 	xhci_setup_generic_chain(xfer);
 
-#ifdef NOTYET
-	/* put transfer on interrupt queue */
-	usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
-
 	/* try to insert xfer on HW queue */
 	xhci_transfer_insert(xfer);
-#endif
 }
 
 static void
@@ -2438,9 +2487,6 @@
 		    "transfer %p into HW queue.\n", xfer);
 	}
 
-	/* put transfer on interrupt queue */
-	usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
-
 	/* start timeout, if any */
 	if (xfer->timeout != 0)
 		usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout);
@@ -3067,10 +3113,6 @@
 		xfer->flags_int.curr_dma_set = 1;
 		goto alloc_dma_set;
 	}
-
-	if ((parm->buf != NULL) && (parm->err == 0)) {
-		parm->err = xhci_configure_reset_endpoint(xfer);
-	}
 }
 
 static usb_error_t
@@ -3092,6 +3134,7 @@
 
 	pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
 	    xfer->endpoint->edesc);
+
 	udev = xfer->xroot->udev;
 	index = udev->controller_slot_id;
 
@@ -3155,18 +3198,12 @@
 			DPRINTF("Could not update parent HS HUB context.\n");
 	}
 
-	if (0) {
-
-
-	  err = xhci_cmd_reset_dev(sc, index);
-	}
-
 	/* configure endpoint */
 
 	err = xhci_configure_endpoint_by_xfer(xfer);
 
 	if (err == 0) {
-		err = xhci_cmd_stop_ep(sc, 0, epno, index);
+		err = xhci_cmd_stop_ep(sc, 0, epno - 1, index);
 
 		if (err != 0)
 			DPRINTF("Could not stop endpoint\n");
@@ -3190,10 +3227,15 @@
 
 	if (err == 0) {
 		if ((edesc->bmAttributes & UE_XFERTYPE) == UE_BULK)
-			err = xhci_cmd_reset_ep(sc, 0, epno, index);
+			err = xhci_cmd_reset_ep(sc, 0, epno - 1, index);
 
 		if (err != 0)
 			DPRINTF("Could not reset endpoint %u\n", epno);
+
+		err = xhci_cmd_set_tr_dequeue_ptr(sc, pepext->physaddr, 0, epno - 1, index);
+
+		if (err != 0)
+			DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno);
 	}
 	XHCI_CMD_UNLOCK(sc);
 
@@ -3227,42 +3269,46 @@
 
 	sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus);
 
-	/* make sure everything that is halted is gone, else we can loop */
-
-restart0:
+restart:
 	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
 
 		pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
 		    xfer->endpoint->edesc);
 
-		if ((pepext->trb_halted != 0) &&
-		    (xfer->flags_int.bandwidth_reclaimed != 0)) {
-			xhci_device_done(xfer, USB_ERR_IOERROR);
-			goto restart0;
-		}
-	}
+		if ((pepext->trb_halted != 0) ||
+		    (pepext->trb_running == 0)) {
 
-restart1:
-	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+			uint8_t i;
 
-		pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
-		    xfer->endpoint->edesc);
+			/* clear halted and running */
+			pepext->trb_halted = 0;
+			pepext->trb_running = 0;
 
-		if (xfer->flags_int.did_dma_delay) {
+			/* nuke remaining buffered transfers */
 
-			if (pepext->trb_halted != 0) {
+			for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) {
+				if (pepext->xfer[i] != NULL)
+					xhci_device_done(pepext->xfer[i], USB_ERR_IOERROR);
+			}
 
-				/* NOTE: The USB transfer cannot vanish in this state! */
+			/* NOTE: The USB transfer cannot vanish in this state! */
 
-				USB_BUS_UNLOCK(&sc->sc_bus);
+			USB_BUS_UNLOCK(&sc->sc_bus);
 
-				xhci_configure_reset_endpoint(xfer);
+			xhci_configure_reset_endpoint(xfer);
 
-				USB_BUS_LOCK(&sc->sc_bus);
+			USB_BUS_LOCK(&sc->sc_bus);
 
-				pepext->trb_reset = 1;
+			/* check if halted is still cleared */
+			if (pepext->trb_halted == 0) {
+				pepext->trb_running = 1;
+				pepext->trb_index = 1;
 			}
+			goto restart;
+		}
 
+		if (xfer->flags_int.did_dma_delay) {
+
 			/* remove transfer from interrupt queue (again) */
 			usbd_transfer_dequeue(xfer);
 
@@ -3270,22 +3316,14 @@
 			usb_dma_delay_done_cb(xfer);
 
 			/* queue changed - restart */
-			goto restart1;
+			goto restart;
+
 		}
 	}
 
-	/* queue up leftover transfers, if any */
-
 	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
-		pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
-		    xfer->endpoint->edesc);
-
-		if ((pepext->trb_halted != 0) &&
-		    (pepext->trb_reset != 0)) {
-			pepext->trb_halted = 0;
-			pepext->trb_reset = 0;
-		}
-		xhci_transfer_insert(xfer);
+			/* try to insert transfer in hardware schedule */
+			xhci_transfer_insert(xfer);
 	}
 }
 
@@ -3293,17 +3331,28 @@
 xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
     struct usb_endpoint *ep)
 {
+	struct xhci_endpoint_ext *pepext;
+
 	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n",
-	    ep, udev->address,
-	    edesc->bEndpointAddress, udev->flags.usb_mode);
+	    ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode);
 
 	if (udev->flags.usb_mode != USB_MODE_HOST) {
 		/* not supported */
 		return;
 	}
-	/* check if not root HUB */
-	if (udev->parent_hub != NULL)
-		ep->methods = &xhci_device_generic_methods;
+	if (udev->parent_hub == NULL) {
+		/* root HUB has special endpoint handling */
+		return;
+	}
+
+	ep->methods = &xhci_device_generic_methods;
+
+	pepext = xhci_get_endpoint_ext(udev, edesc);
+
+	USB_BUS_LOCK(udev->bus);
+	pepext->trb_halted = 1;
+	pepext->trb_running = 0;
+	USB_BUS_UNLOCK(udev->bus);
 }
 
 static void
@@ -3312,6 +3361,30 @@
 
 }
 
+static void
+xhci_ep_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
+{
+	struct xhci_endpoint_ext *pepext;
+
+	DPRINTF("\n");
+
+	if (udev->flags.usb_mode != USB_MODE_HOST) {
+		/* not supported */
+		return;
+	}
+	if (udev->parent_hub == NULL) {
+		/* root HUB has special endpoint handling */
+		return;
+	}
+
+	pepext = xhci_get_endpoint_ext(udev, ep->edesc);
+
+	USB_BUS_LOCK(udev->bus);
+	pepext->trb_halted = 1;
+	pepext->trb_running = 0;
+	USB_BUS_UNLOCK(udev->bus);
+}
+
 static usb_error_t
 xhci_device_init(struct usb_device *udev)
 {
@@ -3452,4 +3525,5 @@
 	.xfer_poll = xhci_do_poll,
 	.start_dma_delay = xhci_start_dma_delay,
 	.set_address = xhci_set_address,
+	.clear_stall = xhci_ep_clear_stall,
 };

==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#18 (text+ko) ====

@@ -192,6 +192,8 @@
 #define	XHCI_TRB_2_BYTES_SET(x)		((x) & 0x1FFFF)
 #define	XHCI_TRB_2_IRQ_GET(x)		(((x) >> 22) & 0x3FF)
 #define	XHCI_TRB_2_IRQ_SET(x)		(((x) & 0x3FF) << 22)
+#define	XHCI_TRB_2_STREAM_GET(x)	(((x) >> 16) & 0xFFFF)
+#define	XHCI_TRB_2_STREAM_SET(x)	(((x) & 0xFFFF) << 16)
 
 	volatile uint32_t	dwTrb3;
 #define	XHCI_TRB_3_TYPE_GET(x)		(((x) >> 10) & 0x3F)
@@ -215,11 +217,11 @@
 #define	XHCI_TRB_3_DIR_IN		(1U << 16)
 #define	XHCI_TRB_3_TLBPC_GET(x)		(((x) >> 16) & 0xF)
 #define	XHCI_TRB_3_TLBPC_SET(x)		(((x) & 0xF) << 16)
+#define	XHCI_TRB_3_EP_GET(x)		(((x) >> 16) & 0x1F)
+#define	XHCI_TRB_3_EP_SET(x)		(((x) & 0x1F) << 16)
 #define	XHCI_TRB_3_FRID_GET(x)		(((x) >> 20) & 0x7FF)
 #define	XHCI_TRB_3_FRID_SET(x)		(((x) & 0x7FF) << 20)
 #define	XHCI_TRB_3_ISO_SIA_BIT		(1U << 31)
-#define	XHCI_TRB_3_EP_GET(x)		(((x) >> 20) & 0x1F)
-#define	XHCI_TRB_3_EP_SET(x)		(((x) & 0x1F) << 20)
 #define	XHCI_TRB_3_SUSP_EP_BIT		(1U << 23)
 #define	XHCI_TRB_3_SLOT_GET(x)		(((x) >> 24) & 0xFF)
 #define	XHCI_TRB_3_SLOT_SET(x)		(((x) & 0xFF) << 24)
@@ -347,13 +349,13 @@
 
 struct xhci_endpoint_ext {
 	struct xhci_trb *trb;
+	struct usb_xfer *xfer[XHCI_MAX_TRANSFERS - 1];
 	struct usb_page_cache *page_cache;
 	uint64_t physaddr;
 	uint8_t trb_used;
 	uint8_t trb_index;
 	uint8_t trb_halted;
-	uint8_t trb_reset;
-	uint8_t trb_configured;
+	uint8_t trb_running;
 };
 
 enum {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008081241.o78Cfg3h090927>