PERFORCE change 181646 for review

Hans Petter Selasky hselasky at FreeBSD.org
Sat Jul 31 14:55:00 UTC 2010


http://p4web.freebsd.org/@@181646?ac=10

Change 181646 by hselasky at hselasky_laptop001 on 2010/07/31 14:53:59

	USB controller (XHCI):
		- add more initialisation logic and register definitions

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#3 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#5 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#6 edit

Differences ...

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

@@ -112,29 +112,187 @@
 void
 xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
 {
+        struct xhci_softc *sc = XHCI_BUS2SC(bus);
 
+        cb(bus, &sc->sc_hw.root_pc, &sc->sc_hw.root_pg,
+	   sizeof(struct xhci_hw_root), XHCI_PAGE_SIZE);
 
+        cb(bus, &sc->sc_ctx.root_pc, &sc->sc_ctx.root_pg,
+	   sizeof(struct xhci_ctx_root), XHCI_PAGE_SIZE);
 }
 
-usb_error_t
-xhci_reset(struct xhci_softc *sc)
+static usb_error_t
+xhci_start_controller(struct xhci_softc *sc)
 {
+	struct usb_page_search buf_res;
+	struct xhci_hw_root *phwr;
+	struct xhci_ctx_root *pctxr;
+	uint64_t addr;
+	uint32_t temp;
+	uint16_t i;
+
+	DPRINTF("\n");
+
+	sc->sc_capa_off = 0;
+	sc->sc_oper_off = XREAD4(sc, capa, XHCI_CAPLENGTH);
+	sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0xF;
+	sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3;
+
+	DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION));
+
+	/* Reset controller */
+	XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST);
+
+	for (i = 0; i != 100; i++) {
+		usb_pause_mtx(NULL, hz / 1000);
+		temp = XREAD4(sc, XHCI_USBCMD) & XHCI_CMD_HCRST;
+		if (!temp)
+			break;
+	}
+
+	if (temp) {
+		device_printf(sc->sc_bus.bdev, "Controller reset timeout.\n");
+		return (USB_ERR_IOERROR);
+	}
+
+	if (!(XREAD4(sc, oper, XHCI_PAGESIZE) & XHCI_PAGESIZE_4K)) {
+		device_printf(sc->sc_bus.bdev, "Controller does not support 4K page size.\n");
+		return (USB_ERR_IOERROR);
+	}
+
+	temp = XREAD4(sc, oper, XHCI_USBSTS);
+
+	/* clear interrupts */
+	XWRITE4(sc, oper, XHCI_USBSTS, status);
+
+	/* disable all device notifications */
+	XWRITE4(sc, oper, XHCI_DNCTRL, 0);
+
+	/* setup device context base address */
+
+	usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res);
+
+	addr = buf_res.physaddr;
+	pctxr = buf_res.ptr;
+
+	memset(pctxr, 0, sizeof(*pctxr));
+
+	XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr);
+	XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32));
+
+	/* setup number of device slots */
+
+	XWRITE4(sc, oper, XHCI_CONFIG, XHCI_MAX_DEVICES);
+
+	/* Setup interrupter registers */
+
+	temp = XREAD4(sc, runt, XHCI_IMAN(0));
+	temp |= XHCI_IMAN_IE_BIT | XHCI_IMAN_IP_BIT;
+	XWRITE4(sc, runt, XHCI_IMAN(0));
+
+	/* Setup interrupt rate */
+
+	XWRITE4(sc, runt, XHCI_IMOD, XHCI_IMOD_DEFAULT);
+
+	usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res);
+
+	phwr = buf_res.ptr;
+	addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0];
+
+	/* reset hardware root structure */
+
+	memset(phwr, 0, sizeof(*phwr));
+
+	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("hcsparams2=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), temp);
+
+	XWRITE4(sc, oper, XHCI_ERDP_LO(0), (uint32_t)addr);
+	XWRITE4(sc, oper, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32));
+
+	addr = (uint64_t)buf_res.physaddr;
+
+	XWRITE4(sc, oper, XHCI_ERSTBA_LO(0), (uint32_t)addr);
+	XWRITE4(sc, oper, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32));
+
+	/* setup command ring control base address */
+
+	addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0];
+
+	XWRITE4(sc, oper, XHCI_CRCR_LO, (uint32_t)addr);
+	XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32));
+
+	usb_bus_mem_flush_all(&sc->sc_bus, &ehci_iterate_hw_softc);
+
+	/* Go! */
+	XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_RS | XHCI_CMD_INTE | XHCI_CMD_HSEE);
+
+	for (i = 0; i != 100; i++) {
+		usb_pause_mtx(NULL, hz / 1000);
+		temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH;
+		if (!temp)
+			break;
+	}
+	if (temp) {
+		device_printf(sc->sc_bus.bdev, "Run timeout.\n");
+		return (USB_ERR_IOERROR);
+	}
 
+	/* catch any lost interrupts */
+	xhci_do_poll(&sc->sc_bus);
 
+	return (0);
 }
 
 static usb_error_t
-xhci_hcreset(struct xhci_softc *sc)
+xhci_halt_controller(struct xhci_softc *sc)
 {
+	uint32_t temp;
+	uint16_t i;
+
+	DPRINTF("\n");
 
+	/* Halt controller */
+	XWRITE4(sc, oper, XHCI_USBCMD, 0);
+
+	for (i = 0; i != 100; i++) {
+		usb_pause_mtx(NULL, hz / 1000);
+		temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH;
+		if (temp)
+			break;
+	}
 
+	if (!temp) {
+		device_printf(sc->sc_bus.bdev, "Controller halt timeout.\n");
+		return (USB_ERR_IOERROR);
+	}
+	return (0);
 }
 
 usb_error_t
 xhci_init(struct xhci_softc *sc)
 {
+	/* set the bus revision */
+	sc->sc_bus.usbrev = USB_REV_3_0;
 
+        /* set up the bus struct */
+        sc->sc_bus.methods = &ehci_bus_methods;
 
+	return (0);
 }
 
 void
@@ -165,17 +323,6 @@
 
 }
 
-static void
-xhci_transfer_intr_enqueue(struct usb_xfer *xfer)
-{
-	/* check for early completion */
-	if (xhci_check_transfer(xfer))
-		return;
-
-	/* put transfer on interrupt queue */
-	usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
-}
-
 static usb_error_t
 xhci_generic_done_sub(struct usb_xfer *xfer)
 {
@@ -377,12 +524,6 @@
 }
 
 static void
-xhci_pcd_enable(struct xhci_softc *sc)
-{
-
-}
-
-static void
 xhci_interrupt_poll(struct xhci_softc *sc)
 {
 	struct usb_xfer *xfer;
@@ -405,8 +546,40 @@
 void
 xhci_interrupt(struct xhci_softc *sc)
 {
+	uint32_t status;
+
+	USB_BUS_LOCK(&sc->sc_bus);
+
+	DPRINTFN(16, "real interrupt\n");
+
+	status = XREAD4(sc, oper, XHCI_USBSTS);
+
+	if (status & XHCI_STS_PCD) {
+		xhci_root_intr(sc);
+	}
+
+	if (status & XHCI_STS_HCH) {
+		printf("%s: host controller halted\n",
+		    __FUNCTION__);
+	}
 
+	if (status & XHCI_STS_HSE) {
+		printf("%s: host system error\n",
+		    __FUNCTION__);
+	}
 
+	if (status & XHCI_STS_HCE) {
+		printf("%s: host controller error\n",
+		    __FUNCTION__);
+	}
+
+	/* acknowledge interrupts */
+
+	XWRITE4(sc, oper, XHCI_USBSTS, status);
+
+	xhci_interrupt_poll(sc);
+
+	USB_BUS_UNLOCK(&sc->sc_bus);
 }
 
 /*------------------------------------------------------------------------*
@@ -873,7 +1046,26 @@
 static void
 xhci_root_intr(struct xhci_softc *sc)
 {
+	uint16_t i;
+
+	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
 
+	/* clear any old interrupt data */
+	memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata));
+
+	for (i = 1; i <= sc->sc_noport; i++) {
+		/* pick out CHANGE bits from the status register */
+		if (XREAD4(sc, oper, XHCI_PORTSC(i)) & (
+		    XHCI_PS_CSC | XHCI_PS_PEC |
+		    XHCI_PS_OCC | XHCI_PS_WRC |
+		    XHCI_PS_PRC | XHCI_PS_PLC |
+		    XHCI_PS_CEC)) {
+			sc->sc_hub_idata[i / 8] |= 1 << (i % 8);
+			DPRINTF("port %d changed\n", i);
+		}
+	}
+	uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
+	    sizeof(sc->sc_hub_idata));
 }
 
 /*------------------------------------------------------------------------*
@@ -918,7 +1110,7 @@
 	xhci_setup_generic_chain(xfer);
 
 	/* put transfer on interrupt queue */
-	xhci_transfer_intr_enqueue(xfer);
+	usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
 }
 
 static void
@@ -986,8 +1178,8 @@
 		.bmAttributes = XXX,
 		HSETW(.wSpeedsSupported, 0x000C),
 		.bFunctionalitySupport = 8,
-		.bU1DevExitLat = 128,	/* dummy - not used */
-		.bU2DevExitLat = 128,	/* dummy - not used */
+		.bU1DevExitLat = 255,	/* dummy - not used */
+		.bU2DevExitLat = 255,	/* dummy - not used */
 	},
 	.cidd = {
 		.bLength = sizeof(xhci_bosd.cidd),

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

@@ -31,6 +31,7 @@
 #define	XHCI_MAX_SCRATCHPADS	32
 #define	XHCI_MAX_EVENTS		(16 * 7)
 #define	XHCI_MAX_COMMANDS	(16 * 7)
+#define	XHCI_MAX_RSEG		1
 
 #define	XHCI_DEV_CTX_ADDR_ALIGN		64	/* bytes */
 #define	XHCI_DEV_CTX_ALIGN		64	/* bytes */
@@ -46,6 +47,7 @@
 #define	XHCI_TRB_ALIGN			16	/* bytes */
 #define	XHCI_QH_ALIGN			16	/* bytes */
 #define	XHCI_TD_ALIGN			16	/* bytes */
+#define	XHCI_PAGE_SIZE			4096	/* bytes */
 
 struct xhci_dev_ctx_addr {
 	volatile uint64_t	qwBaaDevCtxAddr;
@@ -318,11 +320,16 @@
 };
 
 struct xhci_hw_root {
-	struct xhci_event_ring_seg	hwr_ring_seg[4];
+	struct xhci_event_ring_seg	hwr_ring_seg[XHCI_MAX_RSEG];
+	volatile uint64_t		hwr_padding[2];
 	struct xhci_trb			hwr_events[XHCI_MAX_EVENTS];
 	struct xhci_trb			hwr_commands[XHCI_MAX_COMMANDS];
 };
 
+struct xhci_ctx_root {
+	volatile uint64_t		ctxr_ptr[XHCI_MAX_DEVICES];
+};
+
 struct xhci_endpoint_ext {
 	TAILQ_HEAD(, xhci_qh) head;
 
@@ -335,16 +342,24 @@
 	uint8_t pstreams;
 };
 
+struct xhci_hw_dev {
+	struct usb_page_cache device_pc;
+	struct usb_page_cache input_pc;
+	struct usb_page_cache scratch_pc[XHCI_MAX_SCRATCHPADS];
+
+	struct usb_page device_pg;
+	struct usb_page input_pg;
+	struct usb_page scratch_pg[XHCI_MAX_SCRATCHPADS];
+};
+
 struct xhci_hw_softc {
 	struct usb_page_cache root_pc;
-	struct usb_page_cache device_pc[XHCI_MAX_DEVICES];
-	struct usb_page_cache device_input_pc[XHCI_MAX_DEVICES];
-	struct usb_page_cache device_sp_pc[XHCI_MAX_DEVICES][XHCI_MAX_SCRATCHPADS];
+	struct usb_page_cache ctx_pc;
 
 	struct usb_page root_pg;
-	struct usb_page device_pg[XHCI_MAX_DEVICES];
-	struct usb_page device_input_pg[XHCI_MAX_DEVICES];
-	struct usb_page device_sp_pg[XHCI_MAX_DEVICES][XHCI_MAX_SCRATCHPADS];
+	sturct usb_page ctx_pg;
+
+	struct xhci_hw_dev devs[XHCI_MAX_DEVICES];
 };
 
 struct xhci_config_desc {
@@ -383,17 +398,15 @@
 	bus_space_tag_t sc_io_tag;
 	bus_space_handle_t sc_io_hdl;
 
-	uint32_t sc_eintrs;
-	uint32_t sc_cmd;		/* shadow of cmd register during
-					 * suspend */
+	uint32_t sc_cmd;		/* copy of cmd register */
+
+	uint32_t sc_oper_off;		/* offset to operational registers */
+	uint32_t sc_capa_off;		/* offset to capability registers */
+	uint32_t sc_runt_off;		/* offset to runtime registers */
+	uint32_t sc_door_off;		/* offset to doorbell registers */
 
 	uint16_t sc_flags;		/* chip specific flags */
-
-	uint16_t sc_pcib_off;		/* offset to PCI registers */
-	uint16_t sc_oper_off;		/* offset to operational registers */
-	uint16_t sc_capa_off;		/* offset to capability registers */
-	uint16_t sc_runt_off;		/* offset to runtime registers */
-	uint16_t sc_door_off;		/* offset to doorbell registers */
+	uint16_t sc_erst_max;
 
 	uint8_t	sc_noport;		/* number of ports on root HUB */
 	uint8_t	sc_addr;		/* root HUB device address */

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

@@ -64,9 +64,7 @@
 #define	XHCI_HCS0_PSA_SZ_MAX(x)	(((x) >> 12) & 0xF)	/* max pri. stream array size */
 #define	XHCI_HCS0_XECP(x)	(((x) >> 16) & 0xFFFF)	/* extended capabilities pointer */
 #define	XHCI_DBOFF		0x14	/* RO doorbell offset */
-#define	XHCI_DBOFF_GET(x)	(((x) >> 2) & 0x3FFFFFFF)
 #define	XHCI_RTSOFF		0x18	/* RO runtime register space offset */
-#define	XHCI_RTSOFF_GET(x)	(((x) >> 5) & 0x7FFFFFF)
 
 /* XHCI operational registers.  Offset given by XHCI_CAPLENGTH register */
 #define	XHCI_USBCMD		0x00	/* XHCI command */


More information about the p4-projects mailing list