Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Aug 2010 20:39:04 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 181803 for review
Message-ID:  <201008032039.o73Kd4l3045324@repoman.freebsd.org>

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

Change 181803 by hselasky@hselasky_laptop001 on 2010/08/03 20:38:47

	USB controller (XHCI):
		- first compiling version of complete XHCI driver.
		- added logic to reset endpoints after failed transfers.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#12 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#13 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#5 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#12 edit

Differences ...

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

@@ -114,6 +114,8 @@
 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 usb_proc_callback_t xhci_configure_msg;
+static usb_error_t xhci_configure_reset_endpoint(struct usb_xfer *xfer, uint8_t set_address);
 
 extern struct usb_bus_methods xhci_bus_methods;
 
@@ -363,12 +365,24 @@
 		return (ENOMEM);
 	}
 
+        sc->sc_config_msg[0].hdr.pm_callback = &xhci_configure_msg;
+        sc->sc_config_msg[0].bus = &sc->sc_bus;
+        sc->sc_config_msg[1].hdr.pm_callback = &xhci_configure_msg;
+        sc->sc_config_msg[1].bus = &sc->sc_bus;
+
+	if (usb_proc_create(&sc->sc_config_proc,
+	    &sc->sc_bus.bus_mtx, device_get_nameunit(self), USB_PRI_MED)) {
+                printf("WARNING: Creation of XHCI configure "
+                    "callback process failed.\n");
+        }
 	return (0);
 }
 
 void
 xhci_uninit(struct xhci_softc *sc)
 {
+	usb_proc_free(&sc->sc_config_proc);
+
 	usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc);
 
 	cv_destroy(&sc->sc_cmd_cv);
@@ -524,6 +538,7 @@
 {
 	struct usb_xfer *xfer;
 	struct xhci_td *td;
+	struct xhci_endpoint_ext *pepext;
 	uint64_t td_event;
 	uint32_t temp;
 	uint32_t actlen;
@@ -536,10 +551,24 @@
 	/* try to find the USB transfer that generated the event */
 	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
 
+		/* check if transfer is cancelling */
+		if (xfer->flags_int.did_dma_delay)
+			continue;
+
+		pepext = xhci_get_endpoint_ext(xfer);
+
+		/* check if endpoint is halted */
+		if (pepext->trb_halted != 0)
+			continue;
+
 		td = xfer->td_transfer_cache;
 
 		if (td_event == td->td_event) {
 
+			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);
 
@@ -852,6 +881,7 @@
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
 
+#if 0
 static usb_error_t
 xhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx,
     uint8_t slot_id)
@@ -867,6 +897,7 @@
 
 	return (xhci_do_command(sc, &trb, 50 /* ms */));
 }
+#endif
 
 static usb_error_t
 xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve,
@@ -889,6 +920,7 @@
 	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)
@@ -909,6 +941,7 @@
 
 	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)
@@ -975,11 +1008,18 @@
 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);
+
+	/* check if endpoint is halted */
+	if (pepext->trb_halted != 0)
+		return;
+
 	/* transfer is transferred */
 	xhci_device_done(xfer, USB_ERR_TIMEOUT);
 }
@@ -1431,7 +1471,7 @@
 	xfer->td_transfer_last = td;
 }
 
-static usb_error_t
+static void
 xhci_set_slot_pointers(struct xhci_softc *sc, uint8_t index,
     uint64_t dev_addr, uint64_t scratch_addr)
 {
@@ -1481,15 +1521,15 @@
 	uint8_t epno;
 	uint8_t k;
 
-	usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
-	usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc, 0, &buf_ep);
-
 	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);
+	usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc, 0, &buf_ep);
+
 	edesc = xfer->endpoint->edesc;
 
 	epno = edesc->bEndpointAddress;
@@ -1511,8 +1551,7 @@
 		pinp->ctx_input.dwInCtx0 = htole32(mask);
 		pinp->ctx_input.dwInCtx1 = 0;
 	} else {
-		if (mask & 2)
-			mask |= 1;
+		mask |= 1;
 		pinp->ctx_input.dwInCtx0 = 0;
 		pinp->ctx_input.dwInCtx1 = htole32(mask);
 	}
@@ -1566,14 +1605,17 @@
 
 	if (drop == 0) {
 
+		USB_BUS_LOCK(&sc->sc_bus);
+
 		pepext->trb_ccs = 1;
 		pepext->trb_index = 0;
-		pepext->trb_halted = 0;
 
 		for (k = 0; k != XHCI_MAX_TRANSFERS; k++)
 			pepext->trb[k].dwTrb3 = 0;
 
 		usb_pc_cpu_flush(pepext->page_cache);
+
+		USB_BUS_UNLOCK(&sc->sc_bus);
 	}
 
 	addr = XHCI_EPCTX_2_DCS_SET(1) |
@@ -1587,6 +1629,8 @@
 	pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp);
 
 	usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc);
+
+	return (0);		/* success */
 }
 
 static usb_error_t
@@ -1606,6 +1650,8 @@
 	uint8_t rh_port;
 	uint8_t i;
 
+	index = udev->controller_slot_id;
+
 	pcdev = &sc->sc_hw.devs[index].device_pc;
 	pcinp = &sc->sc_hw.devs[index].input_pc;
 
@@ -1693,6 +1739,8 @@
 
 	xhci_set_slot_pointers(sc, udev->controller_slot_id, buf_dev.physaddr,
 	    buf_inp.physaddr + (uintptr_t)&((struct xhci_input_dev_ctx *)0)->ctx_sp_buf_ptr[0]);
+
+	return (0);		/* success */
 }
 
 static usb_error_t
@@ -1842,7 +1890,7 @@
 		pepext->trb_used--;
 
 		if (error)
-			xhci_transfer_stop_endpoint(xfer);
+			pepext->trb_halted = 1;
 	}
 }
 
@@ -1863,6 +1911,10 @@
 
 	pepext = xhci_get_endpoint_ext(xfer);
 
+	/* 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;
@@ -2270,7 +2322,6 @@
 			err = USB_ERR_IOERROR;
 			goto done;
 		}
-		sc->sc_addr = value;
 		break;
 	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
 		if ((value != 0) && (value != 1)) {
@@ -2661,71 +2712,95 @@
 	}
 
 	if ((parm->buf != NULL) && (parm->err == 0)) {
-		struct usb_page_search buf_dev;
-		struct usb_page_search buf_inp;
-		struct usb_device *udev;
-		struct xhci_endpoint_ext *pepext;
-		struct xhci_dev_ctx *pdctx;
-		struct usb_page_cache *pcdev;
-		struct usb_page_cache *pcinp;
-		usb_error_t err;
-		uint32_t temp;
-		uint8_t index;
+		parm->err = xhci_configure_reset_endpoint(xfer, 1);
+	}
+}
+
+static usb_error_t
+xhci_configure_reset_endpoint(struct usb_xfer *xfer, uint8_t set_address)
+{
+	struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+	struct usb_page_search buf_dev;
+	struct usb_page_search buf_inp;
+	struct usb_device *udev;
+	struct xhci_endpoint_ext *pepext;
+	struct usb_endpoint_descriptor *edesc;
+	struct xhci_dev_ctx *pdctx;
+	struct usb_page_cache *pcdev;
+	struct usb_page_cache *pcinp;
+	usb_error_t err;
+	uint32_t temp;
+	uint8_t index;
+	uint8_t epno;
+
+	pepext = xhci_get_endpoint_ext(xfer);
+	udev = xfer->xroot->udev;
+	index = udev->controller_slot_id;
+
+	pcdev = &sc->sc_hw.devs[index].device_pc;
+	pcinp = &sc->sc_hw.devs[index].input_pc;
+
+	usbd_get_page(pcdev, 0, &buf_dev);
+	usbd_get_page(pcinp, 0, &buf_inp);
+
+	pdctx = buf_dev.buffer;
+
+	edesc = xfer->endpoint->edesc;
 
-		pepext = xhci_get_endpoint_ext(xfer);
-		udev = xfer->xroot->udev;
-		index = udev->controller_slot_id;
+	epno = edesc->bEndpointAddress;
 
-		pcdev = &sc->sc_hw.devs[index].device_pc;
-		pcinp = &sc->sc_hw.devs[index].input_pc;
+	if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL)
+		epno |= UE_DIR_IN;
 
-		usbd_get_page(pcdev, 0, &buf_dev);
-		usbd_get_page(pcinp, 0, &buf_inp);
+	epno = XHCI_EPNO2EPID(epno);
 
-		pdctx = buf_dev.buffer;
+ 	if (epno == 0)
+		return (USB_ERR_INVAL);		/* invalid */
 
-		XHCI_CMD_LOCK(sc);
+	XHCI_CMD_LOCK(sc);
 
+	err = xhci_configure_device(udev);
+	if (err == 0)
 		err = xhci_configure_endpoint(xfer, 1);
-		if (err == 0)
-			err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
-		if (err == 0)
-			err = xhci_configure_endpoint(xfer, 0);
-		if (err == 0)
-			err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
+	if (err == 0)
+		err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
+	if (err == 0)
+		err = xhci_configure_endpoint(xfer, 0);
+	if (err == 0)
+		err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
+	if (err == 0)
+		err = xhci_cmd_reset_ep(sc, 0, epno - 1, index);
+	if (err != 0)
+		DPRINTFN(0, "Could not configure/reset endpoint\n");
 
-		if (err != 0)
-			DPRINTFN(0, "Could not configure endpoint\n");
+	if (xfer->flags_int.control_xfr && set_address) {
 
-		if (xfer->flags_int.control_xfr) {
+		if (udev->address != 0) {
+			err = xhci_cmd_set_address(sc, buf_inp.physaddr, 0, index);
+			if (err == 0) {
+				usb_pc_cpu_invalidate(pcdev);
 
-			if (udev->address != 0) {
-				err = xhci_cmd_set_address(sc, buf_inp.physaddr, 0, index);
-				if (err == 0) {
-					usb_pc_cpu_invalidate(pcdev);
+				temp = le32toh(pdctx->ctx_slot.dwSctx3);
 
-					temp = le32toh(pdctx->ctx_slot.dwSctx3);
+				/* update address */
+				udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp);
 
-					/* update address */
-					udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp);
-
-					if (udev->address == 0)
-						DPRINTFN(0, "XHCI returned address zero!\n");
+				if (udev->address == 0)
+					DPRINTFN(0, "XHCI returned address zero!\n");
 				}
-			} else {
-				err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1, index);
-
-				if (err != 0)
-					err = xhci_cmd_reset_dev(sc, index);
-			}
+		} else {
+			err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1, index);
 
 			if (err != 0)
-				DPRINTFN(0, "Could not set address\n");
+				err = xhci_cmd_reset_dev(sc, index);
 		}
-		XHCI_CMD_UNLOCK(sc);
 
-		parm->err = err;
+		if (err != 0)
+			DPRINTFN(0, "Could not set address\n");
 	}
+	XHCI_CMD_UNLOCK(sc);
+
+	return (err);
 }
 
 static void
@@ -2735,20 +2810,98 @@
 }
 
 static void
+xhci_start_dma_delay(struct usb_xfer *xfer)
+{
+	struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+
+	/* put transfer on interrupt queue (again) */
+	usbd_transfer_enqueue(&sc->sc_bus.intr_q, xfer);
+
+	(void)usb_proc_msignal(&sc->sc_config_proc,
+	    &sc->sc_config_msg[0], &sc->sc_config_msg[1]);
+}
+
+static void
+xhci_configure_msg(struct usb_proc_msg *pm)
+{
+	struct xhci_softc *sc;
+	struct xhci_endpoint_ext *pepext;
+	struct usb_xfer *xfer;
+
+	sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus);
+
+	/* make sure everything that is halted is gone, else we can loop */
+
+restart0:
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+		pepext = xhci_get_endpoint_ext(xfer);
+
+		if ((pepext->trb_halted != 0) &&
+		    (xfer->flags_int.bandwidth_reclaimed != 0)) {
+			xhci_device_done(xfer, USB_ERR_IOERROR);
+			goto restart0;
+		}
+	}
+
+restart1:
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+		pepext = xhci_get_endpoint_ext(xfer);
+
+		if (xfer->flags_int.did_dma_delay) {
+
+			if (pepext->trb_halted != 0) {
+
+				/* NOTE: The USB transfer cannot vanish in this state! */
+
+				USB_BUS_UNLOCK(&sc->sc_bus);
+
+				xhci_configure_reset_endpoint(xfer, 0);
+
+				USB_BUS_LOCK(&sc->sc_bus);
+
+				pepext->trb_reset = 1;
+			}
+
+			/* remove transfer from interrupt queue (again) */
+			usbd_transfer_dequeue(xfer);
+
+			/* we are finally done */
+			usb_dma_delay_done_cb(xfer);
+
+			/* queue changed - restart */
+			goto restart1;
+		}
+	}
+
+	/* queue up leftover transfers, if any */
+
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+		pepext = xhci_get_endpoint_ext(xfer);
+
+		if ((pepext->trb_halted != 0) &&
+		    (pepext->trb_reset != 0)) {
+			pepext->trb_halted = 0;
+			pepext->trb_reset = 0;
+		}
+		xhci_transfer_insert(xfer);
+	}
+}
+
+static void
 xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
     struct usb_endpoint *ep)
 {
-	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
-
-	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
+	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n",
 	    ep, udev->address,
-	    edesc->bEndpointAddress, udev->flags.usb_mode,
-	    sc->sc_addr);
+	    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;
 }
@@ -2874,4 +3027,5 @@
 	.set_hw_power = xhci_set_hw_power,
 	.roothub_exec = xhci_roothub_exec,
 	.xfer_poll = xhci_do_poll,
+	.start_dma_delay = xhci_start_dma_delay,
 };

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

@@ -350,6 +350,7 @@
 	uint8_t trb_ccs;
 	uint8_t trb_index;
 	uint8_t trb_halted;
+	uint8_t trb_reset;
 };
 
 struct xhci_hw_dev {
@@ -400,6 +401,8 @@
 struct xhci_softc {
 	struct xhci_hw_softc sc_hw;
 	struct usb_bus sc_bus;		/* base device */
+	struct usb_process sc_config_proc;	/* configure process */
+	struct usb_bus_msg sc_config_msg[2];
 
 	union xhci_hub_desc sc_hub_desc;
 
@@ -436,7 +439,6 @@
 	uint8_t	sc_noslot;		/* number of XHCI device slots */
 	uint8_t	sc_noport;		/* number of ports on root HUB */
 	uint8_t sc_noscratch;		/* number of scratch pages */
-	uint8_t	sc_addr;		/* root HUB device address */
 	uint8_t	sc_conf;		/* root HUB device configuration */
 	uint8_t	sc_hub_idata[2];
 
@@ -444,9 +446,9 @@
 
 };
 
-#define	XHCI_CMD_LOCK(sc)	sx_xlock(&sc->sc_cmd_sx)
-#define	XHCI_CMD_UNLOCK(sc)	sx_xunlock(&sc->sc_cmd_sx)
-#define	XHCI_CMD_ASSERT_LOCKED(sc) sx_assert(&sc->sc_cmd_sx, SA_LOCKED)
+#define	XHCI_CMD_LOCK(sc)	sx_xlock(&(sc)->sc_cmd_sx)
+#define	XHCI_CMD_UNLOCK(sc)	sx_xunlock(&(sc)->sc_cmd_sx)
+#define	XHCI_CMD_ASSERT_LOCKED(sc) sx_assert(&(sc)->sc_cmd_sx, SA_LOCKED)
 
 /* prototypes */
 

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


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




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