Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Aug 2010 19:07:03 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 181692 for review
Message-ID:  <201008011907.o71J739I037130@repoman.freebsd.org>

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

Change 181692 by hselasky@hselasky_laptop001 on 2010/08/01 19:06:24

	
	USB controller (XHCI):
		- implement endpoint extension and transfer
		insertion and removal from hardware DMA queue.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#7 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#9 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#10 edit

Differences ...

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

@@ -639,7 +639,8 @@
 	i = sc->sc_command_idx;
 	j = sc->sc_command_ccs;
 
-	while (1) {
+	/* check if there are any commands on the queue */
+	while ((pcmd = TAILQ_FIRST(&sc->sc_cmd_head)) != NULL) {
 
 		k = (phwr->hwr_events[i].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT)) ? 1 : 0;
 
@@ -649,11 +650,6 @@
 		if ((sc->sc_cmd_dp == temp) && (j == k))
 			break;
 
-		/* check if there are any commands on the queue */
-		pcmd = TAILQ_FIRST(&sc->sc_cmd_head);
-		if (pcmd == NULL)
-			break;
-
 		TAILQ_REMOVE(&sc->sc_cmd_head, pcmd, entry);
 		pcmd->entry.tqe_prev = NULL;
 
@@ -662,7 +658,7 @@
 
 		usb_pc_cpu_flush(&sc->sc_hw.root_pc);
 
-		temp = pcmd->trb.dwTrb3 | htole32(XHCI_TRB_3_IOC_BIT);
+		temp = pcmd->trb.dwTrb3;
 
 		if (j)
 			temp |= htole32(XHCI_TRB_3_CYCLE_BIT);
@@ -706,6 +702,123 @@
 	sc->sc_command_ccs = j;
 }
 
+static usb_error_t
+xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb, 
+    uint16_t timeout_ms)
+{
+	XXX implement;
+}
+
+static usb_error_t
+xhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id)
+{
+	struct xhci_trb trb;
+	uint32_t dword;
+
+	trb.qwTrb0 = 0;
+	trb.dwTrb2 = 0;
+	dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) |
+	    XHCI_TRB_3_SLOT_SET(slot_id);
+
+	trb.dwTrb3 = htole32(dword);
+
+	return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
+static usb_error_t
+xhci_cmd_configure_ep(struct xhci_softc *sc, uint64_t input_ctx,
+    uint8_t deconfigure, uint8_t slot_id)
+{
+	struct xhci_trb trb;
+	uint32_t dword;
+
+	trb.qwTrb0 = htole64(input_ctx);
+	trb.dwTrb2 = 0;
+	dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) |
+	    XHCI_TRB_3_SLOT_SET(slot_id);
+
+	if (deconfigure)
+		dword |= XHCI_TRB_3_DCEP_BIT;
+
+	trb.dwTrb3 = htole32(dword);
+
+	return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
+static usb_error_t
+xhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx,
+    uint8_t slot_id)
+{
+	struct xhci_trb trb;
+	uint32_t dword;
+
+	trb.qwTrb0 = htole64(input_ctx);
+	trb.dwTrb2 = 0;
+	dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) |
+	    XHCI_TRB_3_SLOT_SET(slot_id);
+	trb.dwTrb3 = htole32(dword);
+
+	return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
+static usb_error_t
+xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve,
+    uint8_t ep_id, uint8_t slot_id)
+{
+	struct xhci_trb trb;
+	uint32_t dword;
+
+	trb.qwTrb0 = 0;
+	trb.dwTrb2 = 0;
+	dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) |
+	    XHCI_TRB_3_SLOT_SET(slot_id) |
+	    XHCI_TRB_3_SLOT_SET(ep_id);
+
+	if (preserve)
+		dword |= XHCI_TRB_3_PRSV_BIT;
+
+	trb.dwTrb3 = htole32(dword);
+
+	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)
+{
+	struct xhci_trb trb;
+	uint32_t dword;
+
+	trb.qwTrb0 = 0;
+	trb.dwTrb2 = 0;
+	dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) |
+	    XHCI_TRB_3_SLOT_SET(slot_id) |
+	    XHCI_TRB_3_SLOT_SET(ep_id);
+
+	if (suspend)
+		dword |= XHCI_TRB_3_SUSP_EP_BIT;
+
+	trb.dwTrb3 = htole32(dword);
+
+	return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
+static usb_error_t
+xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id)
+{
+	struct xhci_trb trb;
+	uint32_t dword;
+
+	trb.qwTrb0 = 0;
+	trb.dwTrb2 = 0;
+	dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) |
+	    XHCI_TRB_3_SLOT_SET(slot_id);
+
+	trb.dwTrb3 = htole32(dword);
+
+	return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
 /*------------------------------------------------------------------------*
  *	xhci_interrupt - XHCI interrupt handler
  *------------------------------------------------------------------------*/
@@ -1195,9 +1308,6 @@
 	td->td_trb[td->ntrb].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
 	td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
 
-	/* link the current TD with the next one */
-	td->td_trb[td->ntrb].qwTrb0 = XXX;
-
 	usb_pc_cpu_flush(td->page_cache);
 
 	/* must have at least one frame! */
@@ -1205,7 +1315,224 @@
 	xfer->td_transfer_last = td;
 }
 
+static usb_error_t
+xhci_alloc_endpoint_ext(struct xhci_softc *sc, uint8_t index, 
+    struct usb_endpoint_descriptor *edesc)
+{
+	struct usb_page_search buf_res;
+	struct xhci_endpoint_ext *pepext;
+	struct usb_page_cache *pc;
+	struct usb_page *pg;
+	uint8_t epno;
+
+	epno = edesc->bEndpointAddress;
+
+	if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL)
+		epno |= UE_DIR_IN;
+
+	epno = XHCI_EPNO2EPID(epno);
+	pc = &sc->sc_hw.devs[index].endpoint_pc[epno];
+	pg = &sc->sc_hw.devs[index].endpoint_pg[epno];
+
+	/* need to initialize the page cache */
+	pc->tag_parent = sc->sc_bus.dma_parent_tag;
+
+	if (usb_pc_alloc_mem(pc, pg, sizeof(*pepext), XHCI_TRB_ALIGN)) {
+		return (USB_ERR_NOMEM);     /* failure */
+	}
+
+	/* the allocated memory is zeroed */
+
+	usbd_get_page(pc, 0, &buf_res);
+
+	pepext = buf_res.buffer;
+
+	pepext->page_cache = pc;
+	pepext->trb_ccs = 1;
+
+	usb_pc_cpu_flush(pepext->page_cache);
+
+	return (0);
+}
+
 static void
+xhci_free_endpoint_ext(struct xhci_softc *sc, uint8_t index, 
+    struct usb_endpoint_descriptor *edesc)
+{
+	struct usb_page_cache *pc;
+	uint8_t epno;
+
+	epno = edesc->bEndpointAddress;
+
+	if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL)
+		epno |= UE_DIR_IN;
+
+	epno = XHCI_EPNO2EPID(epno);
+	pc = &sc->sc_hw.devs[index].endpoint_pc[epno];
+
+	usb_pc_free_mem(pc);
+}
+
+static void
+xhci_get_endpoint_ext(struct usb_xfer *xfer, struct usb_page_search *buf)
+{
+	struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+	uint8_t epno;
+	uint8_t index;
+
+	epno = xfer->endpointno;
+	if (xfer->flags_int.control_xfr)
+		epno |= UE_DIR_IN;
+
+	epno = XHCI_EPNO2EPID(epno);
+	index = xfer->xroot->udev->device_index;
+
+	usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc[epno], 0, buf);
+}
+
+static void
+xhci_endpoint_doorbell(struct usb_xfer *xfer)
+{
+	struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+	uint8_t epno;
+	uint8_t index;
+
+	epno = xfer->endpointno;
+	if (xfer->flags_int.control_xfr)
+		epno |= UE_DIR_IN;
+
+	epno = XHCI_EPNO2EPID(epno);
+	index = xfer->xroot->udev->device_index;
+
+	XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0));
+}
+
+static void
+xhci_transfer_remove(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct usb_page_search buf_res;
+	struct xhci_endpoint_ext *pepext;
+
+	if (xfer->flags_int.bandwidth_reclaimed) {
+		xfer->flags_int.bandwidth_reclaimed = 0;
+
+		xhci_get_endpoint_ext(xfer, &buf_res);
+
+		pepext = buf_res.buffer;
+
+		pepext->trb_used--;
+
+		usb_pc_cpu_flush(pepext->page_cache);
+
+		if (error)
+			xhci_transfer_stop_endpoint(xfer);
+	}
+}
+
+static usb_error_t
+xhci_transfer_insert(struct usb_xfer *xfer)
+{
+	struct usb_page_search buf_res;
+	struct xhci_td *td_first;
+	struct xhci_td *td_last;
+	struct xhci_endpoint_ext *pepext;
+	uint64_t addr;
+	uint32_t temp;
+	uint8_t i;
+	uint8_t j;
+
+	/* check if already inserted */
+	if (xfer->flags_int.bandwidth_reclaimed)
+		return (0);
+
+	xhci_get_endpoint_ext(xfer, &buf_res);
+
+	td_first = xfer->td_transfer_first;
+	td_last = xfer->td_transfer_last;
+	pepext = buf_res.buffer;
+	addr = buf_res.physaddr;
+
+	if (pepext->trb_used >= (XHCI_MAX_TRANSFERS - 1))
+		return (USB_ERR_NOMEM);
+
+	pepext->trb_used++;
+
+	xfer->flags_int.bandwidth_reclaimed = 1;
+
+	i = pepext->trb_index;
+	j = pepext->trb_ccs;
+
+	/* update TC and next pointer of last link TRB */
+
+	temp = td_last->td_trb[td_last->ntrb].dwTrb3;
+
+	if (j)
+		temp |= htole32(XHCI_TRB_3_TC_BIT);
+	else
+		temp &= ~htole32(XHCI_TRB_3_TC_BIT);
+
+	addr += (uintptr_t)&((struct xhci_endpoint_ext *)0)->trb[i + 1];
+
+	td_last->td_trb[td_last->ntrb].dwTrb3 = temp;
+	td_last->td_trb[td_last->ntrb].qwTrb0 = htole64(addr);
+
+	usb_pc_cpu_flush(td_last->page_cache);
+
+	/* update next pointer of link TRB */
+
+	pepext->trb[i].qwTrb0 = td_first->td_self;
+	pepext->trb[i].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0));
+
+	usb_pc_cpu_flush(pepext->page_cache);
+
+	if (j)
+		temp = htole32(XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_TC_BIT | 
+		    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
+	else
+		temp = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
+
+	pepext->trb[i].dwTrb3 = temp;
+
+	usb_pc_cpu_flush(pepext->page_cache);
+
+	/* advance queue */
+
+	i++;
+
+	if (i == (XHCI_MAX_TRANSFERS - 1)) {
+
+		addr = buf_res.physaddr;
+
+		/* update next pointer of link TRB */
+
+		pepext->trb[i].qwTrb0 = htole64(addr);
+		pepext->trb[i].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0));
+
+		usb_pc_cpu_flush(pepext->page_cache);
+
+		if (j)
+			temp = htole32(XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_TC_BIT | 
+			    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
+		else
+			temp = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
+
+		pepext->trb[i].dwTrb3 = temp;
+
+		usb_pc_cpu_flush(pepext->page_cache);
+
+		xhci_endpoint_doorbell(xfer);
+
+		i = 0;
+		j ^= 1;
+	}
+
+	pepext->trb_index = i;
+	pepext->trb_ccs = j;
+
+	return (0);
+}
+
+static void
 xhci_root_intr(struct xhci_softc *sc)
 {
 	uint16_t i;
@@ -1242,6 +1569,9 @@
 	DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n",
 	    xfer, xfer->endpoint, error);
 
+	/* remove transfer from HW queue */
+	xhci_transfer_remove(xfer, error);
+
 	/* dequeue transfer and start next transfer */
 	usbd_transfer_done(xfer, error);
 }
@@ -1273,11 +1603,20 @@
 
 	/* 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);
 }
 
 static void
 xhci_device_generic_start(struct usb_xfer *xfer)
 {
+	/* try to insert xfer on HW queue */
+	if (xhci_transfer_insert(xfer) != 0) {
+		DPRINTFN(0, "Failed to insert "
+		    "transfer %p into HW queue.\n", xfer);
+	}
+
 	/* start timeout, if any */
 	if (xfer->timeout != 0)
 		usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout);

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

@@ -27,11 +27,12 @@
 #define	_XHCI_H_
 
 #define	XHCI_MAX_DEVICES	MIN(USB_MAX_DEVICES, 128)
-#define	XHCI_MAX_ENDPOINTS	32
+#define	XHCI_MAX_ENDPOINTS	32	/* hardcoded - do not change */
 #define	XHCI_MAX_SCRATCHPADS	32
-#define	XHCI_MAX_EVENTS		(16 * 7)
-#define	XHCI_MAX_COMMANDS	(16 * 7)
+#define	XHCI_MAX_EVENTS		(16 * 13)
+#define	XHCI_MAX_COMMANDS	(16 * 1)
 #define	XHCI_MAX_RSEG		1
+#define	XHCI_MAX_TRANSFERS	4
 
 #define	XHCI_DEV_CTX_ADDR_ALIGN		64	/* bytes */
 #define	XHCI_DEV_CTX_ALIGN		64	/* bytes */
@@ -55,6 +56,8 @@
 #define	XHCI_BAA_MASK	0xFFFFFFFFFFFFFFE0ULL
 };
 
+#define	XHCI_EPNO2EPID(x) ((((x) & UE_DIR_IN) ? 1 : 0) | (2 * ((x) & UE_ADDR)))
+
 struct xhci_slot_ctx {
 	volatile uint32_t	dwSctx0;
 #define	XHCI_SCTX_0_ROUTE_SET(x)		((x) & 0xFFFFF)
@@ -197,6 +200,8 @@
 #define	XHCI_TRB_3_IOC_BIT		(1U << 5)
 #define	XHCI_TRB_3_IDT_BIT		(1U << 6)
 #define	XHCI_TRB_3_BEI_BIT		(1U << 9)
+#define	XHCI_TRB_3_DCEP_BIT		(1U << 9)
+#define	XHCI_TRB_3_PRSV_BIT		(1U << 9)
 #define	XHCI_TRB_3_TRT_MASK		(3U << 16)
 #define	XHCI_TRB_3_TRT_NONE		(0U << 16)
 #define	XHCI_TRB_3_TRT_OUT		(2U << 16)
@@ -207,6 +212,11 @@
 #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)
 
 /* Commands */
 #define	XHCI_TRB_TYPE_RESERVED		0x00
@@ -324,23 +334,26 @@
 };
 
 struct xhci_endpoint_ext {
-	TAILQ_HEAD(, xhci_qh) head;
 
-	struct usb_page_cache root_pc;
+	struct xhci_trb	trb[XHCI_MAX_TRANSFERS];
 
-	struct usb_page root_pg;
+	struct xhci_command ep_stop_cmd;
 
-  //XXX data for QH!;
+	struct usb_page_cache *page_cache;
 
-	uint8_t pstreams;
+	uint8_t trb_used;
+	uint8_t trb_ccs;
+	uint8_t trb_index;
 };
 
 struct xhci_hw_dev {
 	struct usb_page_cache device_pc;
+	struct usb_page_cache endpoint_pc[XHCI_MAX_ENDPOINTS];
 	struct usb_page_cache input_pc;
 	struct usb_page_cache scratch_pc[XHCI_MAX_SCRATCHPADS];
 
 	struct usb_page device_pg;
+	struct usb_page endpoint_pg[XHCI_MAX_ENDPOINTS];
 	struct usb_page input_pg;
 	struct usb_page scratch_pg[XHCI_MAX_SCRATCHPADS];
 };

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




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