Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Aug 2010 19:38:52 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 182044 for review
Message-ID:  <201008071938.o77JcqUS044796@repoman.freebsd.org>

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

Change 182044 by hselasky@hselasky_laptop001 on 2010/08/07 19:38:13

	USB controller (XHCI):
		- fix a bunch of misunderstandings about the XHCI chip.
		- driver has reached a state where device enumeration
		is possible.
		- some issues are still left

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#15 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#17 edit

Differences ...

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

@@ -32,6 +32,12 @@
  * http://www.usb.org/developers/docs/usb_30_spec_060910.zip
  */
 
+/*
+ * A few words about the design implementation: This driver emulates
+ * the concept about TDs which is found in EHCI specification. This
+ * way we avoid too much diveration among USB drivers.
+ */
+
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/dev/usb/controller/xhci.c $");
 
@@ -79,7 +85,7 @@
     ((uint8_t *)&(((struct xhci_softc *)0)->sc_bus))))
 
 #ifdef USB_DEBUG
-static int xhcidebug = 15;
+static int xhcidebug = 17;
 
 SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI");
 SYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW,
@@ -113,40 +119,50 @@
 static void xhci_device_done(struct usb_xfer *, usb_error_t);
 static void xhci_root_intr(struct xhci_softc *);
 static void xhci_free_device_ext(struct usb_device *udev);
-static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_xfer *xfer);
+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 *xfer, uint8_t set_address);
+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;
 
 #ifdef USB_DEBUG
-#if 0
 static void
-xhci_dump_device(struct usb_device *udev)
+xhci_dump_trb(struct xhci_trb *trb)
 {
-	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
-	struct usb_page_search buf_dev;
-	struct usb_page_cache *pcdev;
-	struct xhci_dev_ctx *pdev;
-	uint8_t index;
+	DPRINTFN(5, "trb = %p\n", trb);
+	DPRINTFN(5, "qwTrb0 = 0x%016llx\n", (long long)le64toh(trb->qwTrb0));
+	DPRINTFN(5, "dwTrb2 = 0x%08x\n", le32toh(trb->dwTrb2));
+	DPRINTFN(5, "dwTrb3 = 0x%08x\n", le32toh(trb->dwTrb3));
+}
 
-	index = udev->controller_slot_id;
+static void
+xhci_dump_endpoint(struct xhci_endp_ctx *pep)
+{
+	DPRINTFN(5, "pep = %p\n", pep);
+	DPRINTFN(5, "dwEpCtx0=0x%08x\n", pep->dwEpCtx0);
+	DPRINTFN(5, "dwEpCtx1=0x%08x\n", pep->dwEpCtx1);
+	DPRINTFN(5, "qwEpCtx2=0x%016llx\n", (long long)pep->qwEpCtx2);
+	DPRINTFN(5, "dwEpCtx4=0x%08x\n", pep->dwEpCtx4);
+	DPRINTFN(5, "dwEpCtx5=0x%08x\n", pep->dwEpCtx5);
+	DPRINTFN(5, "dwEpCtx6=0x%08x\n", pep->dwEpCtx6);
+	DPRINTFN(5, "dwEpCtx7=0x%08x\n", pep->dwEpCtx7);
+}
 
-	pcdev = &sc->sc_hw.devs[index].device_pc;
-
-	usbd_get_page(pcdev, 0, &buf_dev);
-
-	usb_pc_cpu_invalidate(pcdev);
-
-	pdev = buf_dev.buffer;
-
-	DPRINTF("SCTX0=0x%08x\n", pdev->ctx_slot.dwSctx0);
-	DPRINTF("SCTX1=0x%08x\n", pdev->ctx_slot.dwSctx1);
-	DPRINTF("SCTX2=0x%08x\n", pdev->ctx_slot.dwSctx2);
-	DPRINTF("SCTX3=0x%08x\n", pdev->ctx_slot.dwSctx3);
+static void
+xhci_dump_device(struct xhci_slot_ctx *psl)
+{
+	DPRINTFN(5, "psl = %p\n", psl);
+	DPRINTFN(5, "dwSctx0=0x%08x\n", psl->dwSctx0);
+	DPRINTFN(5, "dwSctx1=0x%08x\n", psl->dwSctx1);
+	DPRINTFN(5, "dwSctx2=0x%08x\n", psl->dwSctx2);
+	DPRINTFN(5, "dwSctx3=0x%08x\n", psl->dwSctx3);
 }
 #endif
-#endif
 
 static void
 xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
@@ -208,7 +224,7 @@
 
 	for (i = 0; i != 100; i++) {
 		usb_pause_mtx(NULL, hz / 1000);
-		temp = XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST;
+		temp = XREAD4(sc, oper, XHCI_USBCMD) & (XHCI_CMD_HCRST | XHCI_STS_CNR);
 		if (!temp)
 			break;
 	}
@@ -242,6 +258,9 @@
 
 	/* setup number of device slots */
 
+	DPRINTF("CONFIG=0x%08x -> 0x%08x\n",
+	    XREAD4(sc, oper, XHCI_CONFIG), sc->sc_noslot);
+
 	XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot);
 
 	DPRINTF("Max slots: %u\n", sc->sc_noslot);
@@ -279,10 +298,11 @@
 
 	memset(pdctxa, 0, sizeof(*pdctxa));
 
-	addr = buf_res.physaddr + (uintptr_t)&((struct xhci_dev_ctx_addr *)0)->qwSpBufPtr[0];
+	addr = buf_res.physaddr;
+	addr += (uintptr_t)&((struct xhci_dev_ctx_addr *)0)->qwSpBufPtr[0];
 
 	/* slot 0 points to the table of scratchpad pointers */
-	pdctxa->qwBaaDevCtxAddr[0] = htole64(buf_res.physaddr);
+	pdctxa->qwBaaDevCtxAddr[0] = htole64(addr);
 
 	for (i = 0; i != sc->sc_noscratch; i++) {
 
@@ -298,11 +318,26 @@
 	XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr);
 	XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32));
 
-	/* Setup interrupter registers */
+	XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr);
+	XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32));
+
+	/* Setup event table size */
+
+	temp = XREAD4(sc, capa, XHCI_HCSPARAMS2);
+
+	DPRINTF("HCS2=0x%08x\n", temp);
+
+	temp = XHCI_HCS2_ERST_MAX(temp);
+	temp = 1U << temp;
+	if (temp > XHCI_MAX_RSEG)
+		temp = XHCI_MAX_RSEG;
+
+	sc->sc_erst_max = temp;
+
+	DPRINTF("ERSTSZ=0x%08x -> 0x%08x\n",
+	    XREAD4(sc, runt, XHCI_ERSTSZ(0)), temp);
 
-	temp = XREAD4(sc, runt, XHCI_IMAN(0));
-	temp |= XHCI_IMAN_INTR_ENA;
-	XWRITE4(sc, runt, XHCI_IMAN(0), temp);
+	XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(temp));
 
 	/* Setup interrupt rate */
 
@@ -311,7 +346,8 @@
 	usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res);
 
 	phwr = buf_res.buffer;
-	addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0];
+	addr = buf_res.physaddr;
+	addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0];
 
 	/* reset hardware root structure */
 
@@ -320,21 +356,6 @@
 	phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr);
 	phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS);
 
-	/* Setup event table size */
-
-	temp = XREAD4(sc, capa, XHCI_HCSPARAMS2);
-
-	DPRINTF("HCS2=0x%08x\n", temp);
-
-	temp = XHCI_HCS2_ERST_MAX(temp);
-	temp = 1U << temp;
-	if (temp > XHCI_MAX_RSEG)
-		temp = XHCI_MAX_RSEG;
-
-	sc->sc_erst_max = temp;
-
-	XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(temp));
-
 	DPRINTF("ERDP(0)=0x%016llx\n", (unsigned long long)addr);
 
 	XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr);
@@ -347,9 +368,16 @@
 	XWRITE4(sc, runt, XHCI_ERSTBA_LO(0), (uint32_t)addr);
 	XWRITE4(sc, runt, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32));
 
+	/* Setup interrupter registers */
+
+	temp = XREAD4(sc, runt, XHCI_IMAN(0));
+	temp |= XHCI_IMAN_INTR_ENA;
+	XWRITE4(sc, runt, XHCI_IMAN(0), temp);
+
 	/* setup command ring control base address */
 
-	addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0];
+	addr = buf_res.physaddr;
+	addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0];
 
 	DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr);
 
@@ -428,12 +456,6 @@
 	sc->sc_bus.devices = sc->sc_devices;
 	sc->sc_bus.devices_max = XHCI_MAX_DEVICES;
 
-	/*
-	 * The XHCI is very high level at this point and requires
-	 * special handling.
-	 */
-	sc->sc_bus.no_set_address = 1;
-
 	/* setup command queue mutex and condition varible */
 	cv_init(&sc->sc_cmd_cv, "CMDQ");
 	sx_init(&sc->sc_cmd_sx, "CMDQ lock");
@@ -509,7 +531,7 @@
 		status = td->status;
 		len = td->remainder;
 
-		DPRINTFN(4, "xfer=%p[%u/%u] len=%u/%u status=%u\n",
+		DPRINTFN(4, "xfer=%p[%u/%u] rem=%u/%u status=%u\n",
 		    xfer, (unsigned int)xfer->aframes,
 		    (unsigned int)xfer->nframes,
 		    (unsigned int)len, (unsigned int)td->len,
@@ -620,13 +642,23 @@
 	struct xhci_endpoint_ext *pepext;
 	uint64_t td_event;
 	uint32_t temp;
-	uint32_t actlen;
+	uint32_t remainder;
 	uint8_t status;
+	uint8_t halted;
 
 	/* decode TRB */
-	td_event = trb->qwTrb0;
+	td_event = le64toh(trb->qwTrb0);
 	temp = le32toh(trb->dwTrb2);
 
+	remainder = XHCI_TRB_2_REM_GET(temp);
+	status = XHCI_TRB_2_ERROR_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);
+
 	/* try to find the USB transfer that generated the event */
 	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
 
@@ -634,7 +666,8 @@
 		if (xfer->flags_int.did_dma_delay)
 			continue;
 
-		pepext = xhci_get_endpoint_ext(xfer);
+		pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
+		    xfer->endpoint->edesc);
 
 		/* check if endpoint is halted */
 		if (pepext->trb_halted != 0)
@@ -642,19 +675,24 @@
 
 		td = xfer->td_transfer_cache;
 
-		if (td_event == td->td_event) {
+		DPRINTF("0x%08llx == (0x%08llx .. 0x%08llx)\n",
+			(long long)td_event,
+			(long long)td->td_self,
+			(long long)td->td_event_last);
+
+		if ((td_event == td->td_event_last) ||
+		    (halted && (td_event >= td->td_self) &&
+		    (td_event < td->td_event_last))) {
 
 			struct xhci_endpoint_ext *pepext;
 
-			pepext = xhci_get_endpoint_ext(xfer);
-
-			actlen = XHCI_TRB_2_ACTLEN_GET(temp);
-			status = XHCI_TRB_2_ERROR_GET(temp);
+			pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
+			    xfer->endpoint->edesc);
 
 			usb_pc_cpu_invalidate(td->page_cache);
 
 			/* "td->remainder" is verified later */
-			td->remainder -= actlen;
+			td->remainder = remainder;
 			td->status = status;
 
 			usb_pc_cpu_flush(td->page_cache);
@@ -664,6 +702,7 @@
 			 * transfer done
 			 */
 			if (((void *)td) == xfer->td_transfer_last) {
+				DPRINTF("TD is last\n");
 				xhci_generic_done(xfer);
 				break;
 			}
@@ -672,8 +711,8 @@
 			 * 2) Any kind of error makes the transfer
 			 * done
 			 */
-			if ((status != XHCI_TRB_ERROR_SHORT_PKT) &&
-			    (status != XHCI_TRB_ERROR_SUCCESS)) {
+			if (halted) {
+				DPRINTF("TD has I/O error\n");
 				xhci_generic_done(xfer);
 				break;
 			}
@@ -683,6 +722,7 @@
 			 * a short packet also makes the transfer done
 			 */
 			if (td->remainder > 0) {
+				DPRINTF("TD has short pkt\n");
 				if (xfer->flags_int.short_frames_ok) {
 					/* follow alt next */
 					if (td->alt_next != NULL) {
@@ -697,6 +737,7 @@
 			/*
 			 * 4) Transfer complete - go to next TD
 			 */
+			DPRINTF("Following next TD\n");
 			xfer->td_transfer_cache = td->obj_next;
 			break;		/* there should only be one match */
 		}
@@ -719,6 +760,7 @@
 {
 	struct usb_page_search buf_res;
 	struct xhci_hw_root *phwr;
+	uint64_t addr;
 	uint32_t temp;
 	uint16_t i;
 	uint8_t event;
@@ -741,6 +783,7 @@
 	while (1) {
 
 		temp = le32toh(phwr->hwr_events[i].dwTrb3);
+
 		k = (temp & XHCI_TRB_3_CYCLE_BIT) ? 1 : 0;
 
 		if (j != k)
@@ -761,7 +804,7 @@
 			xhci_check_command(sc, &phwr->hwr_events[i]);
 			break;
 		default:
-			DPRINTF("Received event = 0x%x\n", event);
+			DPRINTF("Unhandled event = %u\n", event);
 			break;
 		}
 
@@ -777,16 +820,24 @@
 		}
 	}
 
-	temp = buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i];
+	sc->sc_event_idx = i;
+	sc->sc_event_ccs = j;
 
-	/* we are within a PAGE - no need to update the high bits */
+	/*
+	 * NOTE: The Event Ring Dequeue Pointer Register is 64-bit
+	 * latched. That means to activate the register we need to
+	 * write both the low and high double word of the 64-bit
+	 * register.
+	 */
 
-	temp |= XHCI_ERDP_LO_SINDEX(i) | XHCI_ERDP_LO_BUSY;
+	addr = (uint32_t)buf_res.physaddr;
+	addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i];
 
-	XWRITE4(sc, runt, XHCI_ERDP_LO(0), temp);
+	/* try to clear busy bit */
+	addr |= XHCI_ERDP_LO_BUSY;
 
-	sc->sc_event_idx = i;
-	sc->sc_event_ccs = j;
+	XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr);
+	XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32));
 }
 
 static usb_error_t
@@ -817,7 +868,7 @@
 	j = sc->sc_command_ccs;
 
 	DPRINTFN(10, "command[%u] = %u (0x%016llx, 0x%08lx, 0x%08lx)\n",
-	    i, XHCI_TRB_3_TYPE_GET(le32toh(trb->qwTrb0)),
+	    i, XHCI_TRB_3_TYPE_GET(le32toh(trb->dwTrb3)),
 	    (long long)le64toh(trb->qwTrb0),
 	    (long)le32toh(trb->dwTrb2),
 	    (long)le32toh(trb->dwTrb3));
@@ -840,8 +891,8 @@
 
 	usb_pc_cpu_flush(&sc->sc_hw.root_pc);
 
-	addr = (uint64_t)buf_res.physaddr + 
-	  (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i];
+	addr = buf_res.physaddr;
+	addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i];
 
 	sc->sc_cmd_addr = htole64(addr);
 
@@ -850,12 +901,12 @@
 	if (i == (XHCI_MAX_COMMANDS - 1)) {
 
 		if (j) {
-			temp |= htole32(XHCI_TRB_3_CYCLE_BIT |
+			temp = htole32(XHCI_TRB_3_TC_BIT |
 			    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
-			    XHCI_TRB_3_TC_BIT);
+			    XHCI_TRB_3_CYCLE_BIT);
 		} else {
-			temp &= htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
-			    XHCI_TRB_3_TC_BIT);
+			temp = htole32(XHCI_TRB_3_TC_BIT |
+			    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
 		}
 
 		phwr->hwr_commands[i].dwTrb3 = temp;
@@ -882,7 +933,7 @@
 	} else {
 		temp = le32toh(sc->sc_cmd_result[0]);
 		if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS)
-			err = USB_ERR_INVAL;
+			err = USB_ERR_IOERROR;
 
 		trb->dwTrb2 = sc->sc_cmd_result[0];
 		trb->dwTrb3 = sc->sc_cmd_result[1];
@@ -974,9 +1025,117 @@
 
 	trb.dwTrb3 = htole32(temp);
 
-	return (xhci_do_command(sc, &trb, 50 /* ms */));
+	return (xhci_do_command(sc, &trb, 500 /* ms */));
+}
+
+static usb_error_t
+xhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address)
+{
+	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
+	struct xhci_hw_dev *hdev;
+	usb_error_t err;
+	uint8_t index;
+
+	/* the root HUB case is not handled here */
+	if (udev->parent_hub == NULL)
+		return (USB_ERR_INVAL);
+
+	index = udev->controller_slot_id;
+
+	hdev = 	&sc->sc_hw.devs[index];
+
+	if (mtx != NULL)
+		mtx_unlock(mtx);
+
+	XHCI_CMD_LOCK(sc);
+
+	switch (hdev->state) {
+	case XHCI_ST_ADDRESSED:
+		err = 0;
+		break;
+
+	case XHCI_ST_ENABLED:
+		if (address == 0) {
+			err = 0;
+			break;
+		}
+		/* FALLTHROUGH */
+
+	case XHCI_ST_DEFAULT:
+
+		/* set configure mask to slot and EP0 */
+		xhci_configure_mask(udev, 3, 0);
+
+		/* configure input slot context structure */
+		err = xhci_configure_device(udev);
+
+		/* configure input endpoint context structure */
+		if (err == 0) {
+			struct xhci_endpoint_ext *pepext;
+			uint16_t mps;
+
+			switch (udev->speed) {
+			case USB_SPEED_LOW:
+			case USB_SPEED_FULL:
+				mps = 8;
+				break;
+			case USB_SPEED_HIGH:
+				mps = 64;
+				break;
+			default:
+				mps = 512;
+				break;
+			}
+
+			pepext = xhci_get_endpoint_ext(udev,
+			    &udev->ctrl_ep_desc);
+			err = xhci_configure_endpoint(udev,
+			    &udev->ctrl_ep_desc, pepext->physaddr,
+			    0, 1, mps, mps);
+		}
+
+		/* execute set address command */
+		if (err == 0) {
+			struct usb_page_search buf_inp;
+
+			usbd_get_page(&hdev->input_pc, 0, &buf_inp);
+
+			err = xhci_cmd_set_address(sc, buf_inp.physaddr,
+			    (address == 0), index);
+		}
+
+		/* update device address and state to new value */
+		if (err == 0) {
+			struct usb_page_search buf_dev;
+			struct xhci_dev_ctx *pdev;
+
+			if (address == 0)
+				hdev->state = XHCI_ST_DEFAULT;
+			else
+				hdev->state = XHCI_ST_ADDRESSED;
+
+			usbd_get_page(&hdev->device_pc, 0, &buf_dev);
+			pdev = buf_dev.buffer;
+			usb_pc_cpu_invalidate(&hdev->device_pc);
+			udev->address = XHCI_SCTX_3_DEV_ADDR_GET(pdev->ctx_slot.dwSctx3);
+		}
+		break;
+
+	default:
+		DPRINTF("Wrong state for set address.\n");
+		err = USB_ERR_IOERROR;
+		break;
+	}
+
+	XHCI_CMD_UNLOCK(sc);
+
+	if (mtx != NULL)
+		mtx_lock(mtx);
+
+	return (err);
 }
 
+#if 0
 static usb_error_t
 xhci_cmd_configure_ep(struct xhci_softc *sc, uint64_t input_ctx,
     uint8_t deconfigure, uint8_t slot_id)
@@ -998,8 +1157,8 @@
 
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
+#endif
 
-#if 0
 static usb_error_t
 xhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx,
     uint8_t slot_id)
@@ -1017,7 +1176,6 @@
 
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
-#endif
 
 static usb_error_t
 xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve,
@@ -1042,7 +1200,6 @@
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
 
-#if 0
 static usb_error_t
 xhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend,
     uint8_t ep_id, uint8_t slot_id)
@@ -1065,7 +1222,6 @@
 
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
-#endif
 
 static usb_error_t
 xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id)
@@ -1105,9 +1261,11 @@
 	temp = XREAD4(sc, runt, XHCI_IMAN(0));
 
 	/* acknowledge pending event */
+
 	XWRITE4(sc, runt, XHCI_IMAN(0), temp);
 
-	DPRINTFN(16, "real interrupt (sts=0x%08x, iman=0x%08x)\n", status, temp);
+	DPRINTFN(16, "real interrupt (sts=0x%08x, "
+	    "iman=0x%08x)\n", status, temp);
 
 	if (status != 0) {
 		if (status & XHCI_STS_PCD) {
@@ -1148,7 +1306,8 @@
 
 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
 
-	pepext = xhci_get_endpoint_ext(xfer);
+	pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
+	    xfer->endpoint->edesc);
 
 #if 0
 	/* check if endpoint is halted */
@@ -1177,6 +1336,7 @@
 	struct xhci_td *td;
 	struct xhci_td *td_next;
 	struct xhci_td *td_alt_next;
+	uint64_t addr;
 	uint32_t buf_offset;
 	uint32_t average;
 	uint32_t len_old;
@@ -1241,7 +1401,7 @@
 		/* fill out current TD */
 
 		td->len = average;
-		td->remainder = average;
+		td->remainder = 0;
 		td->status = 0;
 
 		/* update remaining length */
@@ -1270,7 +1430,7 @@
 			td->td_trb[0].dwTrb2 = htole32(dword);
 
 			dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SETUP_STAGE) |
-			  XHCI_TRB_3_IDT_BIT;
+			  XHCI_TRB_3_IDT_BIT | XHCI_TRB_3_CYCLE_BIT;
 
 			/* check wLength */
 			if (td->td_trb[0].qwTrb0 & htole64(0xFFFF00000000ULL)) {
@@ -1281,7 +1441,9 @@
 			}
 
 			td->td_trb[0].dwTrb3 = htole32(dword);
-
+#ifdef USB_DEBUG
+			xhci_dump_trb(&td->td_trb[x]);
+#endif
 			x++;
 
 		} else do {
@@ -1294,7 +1456,8 @@
 				npkt = 1;
 				memset(&buf_res, 0, sizeof(buf_res));
 			} else {
-				usbd_get_page(temp->pc, temp->offset + buf_offset, &buf_res);
+				usbd_get_page(temp->pc, temp->offset +
+				    buf_offset, &buf_res);
 
 				/* get length to end of page */
 				if (buf_res.length > average)
@@ -1305,7 +1468,9 @@
 					buf_res.length = XHCI_TD_PAGE_SIZE;
 
 				/* setup npkt */
-				npkt = (average + temp->max_packet_size - 1) / temp->max_packet_size;
+				npkt = (average + temp->max_packet_size - 1) /
+				    temp->max_packet_size;
+
 				if (npkt > 31)
 					npkt = 31;
 			}
@@ -1321,42 +1486,50 @@
 
 			td->td_trb[x].dwTrb2 = htole32(dword);
 
-			dword = XHCI_TRB_3_CHAIN_BIT |
+			dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
 			  XHCI_TRB_3_TYPE_SET(temp->trb_type) | 
 			  XHCI_TRB_3_FRID_SET(temp->isoc_frame);
 
 			if (temp->direction == UE_DIR_IN)
 				dword |= XHCI_TRB_3_DIR_IN;
 
+			if (average == 0)
+				dword |= XHCI_TRB_3_IDT_BIT;
+
 			td->td_trb[x].dwTrb3 = htole32(dword);
 
 			average -= buf_res.length;
 			buf_offset += buf_res.length;
+#ifdef USB_DEBUG
+			xhci_dump_trb(&td->td_trb[x]);
+#endif
 			x++;
 
 		} while (average != 0);
 
+		td->td_trb[x-1].dwTrb3 |= htole32(XHCI_TRB_3_IOC_BIT);
+
 		/* store number of data TRB's */
 
 		td->ntrb = x;
 
+		DPRINTF("NTRB=%u\n", x);
+
 		/* compute event pointer */
 
-		if (1) {
-			uint64_t td_event;
-
-			td_event = le64toh(td->td_self);
-			td_event += x * sizeof(td->td_trb[0]);
-			td->td_event = htole64(td_event);
-		}
+		addr = td->td_self;
+		addr += (x - 1) * sizeof(struct xhci_trb);
+		td->td_event_last = addr;
 
 		/* fill out link TRB */
 
 		if (td_next != NULL) {
 			/* link the current TD with the next one */
-			td->td_trb[x].qwTrb0 = td_next->td_self;
+			td->td_trb[x].qwTrb0 = htole64((uint64_t)td_next->td_self);
+			DPRINTF("LINK=0x%08llx\n", (long long)td_next->td_self);
 		} else {
 			/* this field will get updated later */
+			DPRINTF("NOLINK\n");
 		}
 
 		dword = XHCI_TRB_2_IRQ_SET(0);
@@ -1364,12 +1537,15 @@
 		td->td_trb[x].dwTrb2 = htole32(dword);
 
 		dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
-		    XHCI_TRB_3_IOC_BIT | XHCI_TRB_3_CHAIN_BIT;
+		    XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+		    XHCI_TRB_3_IOC_BIT;
 
 		td->td_trb[x].dwTrb3 = htole32(dword);
 
 		td->alt_next = td_alt_next;
-
+#ifdef USB_DEBUG
+		xhci_dump_trb(&td->td_trb[x]);
+#endif
 		usb_pc_cpu_flush(td->page_cache);
 	}
 
@@ -1388,15 +1564,15 @@
 		temp->shortpkt = shortpkt_old;
 		temp->len = len_old;
 		goto restart;
-	} else {
-		if (temp->multishort == 0) {
-			/* remove chain bit and clear TD SIZE - end of frame */
-			td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
-			td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
-			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);
-			usb_pc_cpu_flush(td->page_cache);
-		}
+	}
+
+	if (temp->multishort == 0) {
+		/* remove chain bit and clear TD SIZE - end of frame */
+		td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
+ 		td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
+		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);
+		usb_pc_cpu_flush(td->page_cache);
 	}
 	temp->td = td;
 	temp->td_next = td_next;
@@ -1605,6 +1781,8 @@
 	/* must have at least one frame! */
 
 	xfer->td_transfer_last = td;
+
+	DPRINTF("first=%p last=%p\n", xfer->td_transfer_first, td);
 }
 
 static void
@@ -1617,6 +1795,8 @@
 
 	pdctxa = buf_res.buffer;
 
+	DPRINTF("addr[%u]=0x%016llx\n", index, (long long)dev_addr);
+
 	pdctxa->qwBaaDevCtxAddr[index] = htole64(dev_addr);
 
 	usb_pc_cpu_flush(&sc->sc_hw.ctx_pc);
@@ -1640,31 +1820,49 @@
 }
 
 static usb_error_t
-xhci_configure_endpoint(struct usb_xfer *xfer, uint8_t drop)
+xhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop)
+{
+	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
+	struct usb_page_search buf_inp;
+	struct xhci_input_dev_ctx *pinp;
+	uint8_t index;
+
+	index = udev->controller_slot_id;
+
+	usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
+
+	pinp = buf_inp.buffer;
+
+	if (drop) {
+		mask &= 0xFFFFFFFC;
+		pinp->ctx_input.dwInCtx0 = htole32(mask);
+		pinp->ctx_input.dwInCtx1 = 0;
+	} else {
+		pinp->ctx_input.dwInCtx0 = 0;
+		pinp->ctx_input.dwInCtx1 = htole32(mask);
+	}
+	return (0);
+}
+
+static usb_error_t
+xhci_configure_endpoint(struct usb_device *udev,
+    struct usb_endpoint_descriptor *edesc, uint64_t ring_addr,
+    uint16_t interval, uint8_t max_packet_count,
+    uint16_t max_packet_size, uint16_t max_frame_size)
 {
 	struct usb_page_search buf_inp;
-	struct usb_page_search buf_ep;
-	struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
 	struct xhci_input_dev_ctx *pinp;
-	struct usb_endpoint_descriptor *edesc;
-	struct xhci_endpoint_ext *pepext;
-	struct usb_device *udev;
-	uint64_t addr;
 	uint32_t temp;
-	uint32_t mask;
 	uint8_t index;
 	uint8_t epno;
 	uint8_t k;
 
-	pepext = xhci_get_endpoint_ext(xfer);
-
-	udev = xfer->xroot->udev;
-
 	index = udev->controller_slot_id;
 
 	usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
 
-	edesc = xfer->endpoint->edesc;
+	pinp = buf_inp.buffer;
 
 	epno = edesc->bEndpointAddress;
 
@@ -1674,23 +1872,12 @@
 	epno = XHCI_EPNO2EPID(epno);
 
  	if (epno == 0)
-		return (USB_ERR_INVAL);		/* invalid */
+		return (USB_ERR_NO_PIPE);		/* invalid */
 
-	usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc, (XHCI_MAX_TRANSFERS * sizeof(struct xhci_trb)) * epno, &buf_ep);
+	if (max_packet_count == 0)
+		return (USB_ERR_BAD_BUFSIZE);
 
-	pinp = buf_inp.buffer;
-
-	mask = 1U << epno;
-
-	if (drop) {
-		mask &= 0xFFFFFFFC;
-		pinp->ctx_input.dwInCtx0 = htole32(mask);
-		pinp->ctx_input.dwInCtx1 = 0;
-	} else {
-		mask |= 1;
-		pinp->ctx_input.dwInCtx0 = 0;
-		pinp->ctx_input.dwInCtx1 = htole32(mask);
-	}
+	max_packet_count --;
 
 	temp = XHCI_EPCTX_0_EPSTATE_SET(0) |
 	    XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
@@ -1698,12 +1885,12 @@
 
 	switch (edesc->bmAttributes & UE_XFERTYPE) {
 	case UE_INTERRUPT:
-		k = xhci_log2(xfer->interval) + 3;
+		k = xhci_log2(interval) + 3;
 		temp |= XHCI_EPCTX_0_IVAL_SET(k);
 		break;
 	case UE_ISOCHRONOUS:
 		if (udev->speed == USB_SPEED_SUPER)
-			temp |= XHCI_EPCTX_0_MULT_SET(xfer->max_packet_count - 1);
+			temp |= XHCI_EPCTX_0_MULT_SET(max_packet_count);
 		break;
 	default:
 		break;
@@ -1713,8 +1900,8 @@
 
 	temp =
 	    XHCI_EPCTX_1_HID_SET(0) |
-	    XHCI_EPCTX_1_MAXB_SET(xfer->max_packet_count - 1) |
-	    XHCI_EPCTX_1_MAXP_SIZE_SET(xfer->max_packet_size);
+	    XHCI_EPCTX_1_MAXB_SET(max_packet_count) |
+	    XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size);
 
 	if ((udev->parent_hs_hub != NULL) || (udev->address != 0))
 		temp |= XHCI_EPCTX_1_CERR_SET(3);
@@ -1739,34 +1926,38 @@
 
 	pinp->ctx_ep[epno - 1].dwEpCtx1 = htole32(temp);
 
-	if (drop == 0) {
+	ring_addr |= XHCI_EPCTX_2_DCS_SET(1);
 
-		USB_BUS_LOCK(&sc->sc_bus);
+	pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(ring_addr);
 
-		pepext->trb_ccs = 1;
-		pepext->trb_index = 0;
+	temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(max_frame_size) |
+	    XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size);
 
-		for (k = 0; k != XHCI_MAX_TRANSFERS; k++)
-			pepext->trb[k].dwTrb3 = 0;
+	pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp);
 
-		usb_pc_cpu_flush(pepext->page_cache);
+#ifdef USB_DEBUG
+	xhci_dump_endpoint(&pinp->ctx_ep[epno - 1]);
+#endif
+	usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc);
 
-		USB_BUS_UNLOCK(&sc->sc_bus);
-	}
+	return (0);		/* success */
+}
 
-	addr = XHCI_EPCTX_2_DCS_SET(1) |
-	    (buf_ep.physaddr + (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0]);
+static usb_error_t
+xhci_configure_endpoint_by_xfer(struct usb_xfer *xfer)
+{
+	struct xhci_endpoint_ext *pepext;
 
-	pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(addr);
+	pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
+	    xfer->endpoint->edesc);
 
-	temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(xfer->max_frame_size) |
-	    XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(xfer->max_frame_size);
+	pepext->trb[0].dwTrb3 = 0;	/* halt any transfers */
+	usb_pc_cpu_flush(pepext->page_cache);
 
-	pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp);
-
-	usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc);
-
-	return (0);		/* success */
+	return (xhci_configure_endpoint(xfer->xroot->udev,
+	    xfer->endpoint->edesc, pepext->physaddr,
+	    xfer->interval, xfer->max_packet_count,
+	    xfer->max_packet_size, xfer->max_frame_size));
 }
 
 static usb_error_t
@@ -1778,39 +1969,57 @@
 	struct usb_page_cache *pcdev;
 	struct usb_page_cache *pcinp;
 	struct xhci_input_dev_ctx *pinp;
+	struct xhci_dev_ctx *pdev;
 	struct usb_device *hubdev;
 	uint32_t temp;
+	uint32_t route;
+	uint8_t is_hub;
 	uint8_t index;
 	uint8_t rh_port;
 
 	index = udev->controller_slot_id;
 
+	DPRINTF("index=%u\n", index);
+
 	pcdev = &sc->sc_hw.devs[index].device_pc;

>>> TRUNCATED FOR MAIL (1000 lines) <<<



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