[Midnightbsd-cvs] src [6567] trunk/sys/dev/usb/controller: Update USB stack

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Dec 28 10:28:26 EST 2013


Revision: 6567
          http://svnweb.midnightbsd.org/src/?rev=6567
Author:   laffer1
Date:     2013-12-28 10:28:26 -0500 (Sat, 28 Dec 2013)
Log Message:
-----------
Update USB stack

Obtained from:	FreeBSD 9.2

Modified Paths:
--------------
    trunk/sys/dev/usb/controller/at91dci.c
    trunk/sys/dev/usb/controller/atmegadci.c
    trunk/sys/dev/usb/controller/avr32dci.c
    trunk/sys/dev/usb/controller/ehci.c
    trunk/sys/dev/usb/controller/ehci.h
    trunk/sys/dev/usb/controller/musb_otg.c
    trunk/sys/dev/usb/controller/ohci.c
    trunk/sys/dev/usb/controller/ohci_pci.c
    trunk/sys/dev/usb/controller/uhci.c
    trunk/sys/dev/usb/controller/usb_controller.c
    trunk/sys/dev/usb/controller/uss820dci.c
    trunk/sys/dev/usb/controller/xhci.c
    trunk/sys/dev/usb/controller/xhci.h
    trunk/sys/dev/usb/controller/xhci_pci.c
    trunk/sys/dev/usb/controller/xhcireg.h

Modified: trunk/sys/dev/usb/controller/at91dci.c
===================================================================
--- trunk/sys/dev/usb/controller/at91dci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/at91dci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -91,7 +91,7 @@
 #ifdef USB_DEBUG
 static int at91dcidebug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci");
 SYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RW,
     &at91dcidebug, 0, "at91dci debug level");
 #endif

Modified: trunk/sys/dev/usb/controller/atmegadci.c
===================================================================
--- trunk/sys/dev/usb/controller/atmegadci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/atmegadci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -83,7 +83,8 @@
 #ifdef USB_DEBUG
 static int atmegadci_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, atmegadci, CTLFLAG_RW, 0, "USB ATMEGA DCI");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, atmegadci, CTLFLAG_RW, 0,
+    "USB ATMEGA DCI");
 SYSCTL_INT(_hw_usb_atmegadci, OID_AUTO, debug, CTLFLAG_RW,
     &atmegadci_debug, 0, "ATMEGA DCI debug level");
 #endif

Modified: trunk/sys/dev/usb/controller/avr32dci.c
===================================================================
--- trunk/sys/dev/usb/controller/avr32dci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/avr32dci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -83,7 +83,7 @@
 #ifdef USB_DEBUG
 static int avr32dci_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, avr32dci, CTLFLAG_RW, 0, "USB AVR32 DCI");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, avr32dci, CTLFLAG_RW, 0, "USB AVR32 DCI");
 SYSCTL_INT(_hw_usb_avr32dci, OID_AUTO, debug, CTLFLAG_RW,
     &avr32dci_debug, 0, "AVR32 DCI debug level");
 #endif

Modified: trunk/sys/dev/usb/controller/ehci.c
===================================================================
--- trunk/sys/dev/usb/controller/ehci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/ehci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -94,21 +94,21 @@
 static int ehciiaadbug = 0;
 static int ehcilostintrbug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci");
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &ehcidebug, 0, "Debug level");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, no_hs, CTLFLAG_RW,
+TUNABLE_INT("hw.usb.ehci.debug", &ehcidebug);
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, no_hs, CTLFLAG_RW | CTLFLAG_TUN,
     &ehcinohighspeed, 0, "Disable High Speed USB");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, iaadbug, CTLFLAG_RW,
+TUNABLE_INT("hw.usb.ehci.no_hs", &ehcinohighspeed);
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, iaadbug, CTLFLAG_RW | CTLFLAG_TUN,
     &ehciiaadbug, 0, "Enable doorbell bug workaround");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, lostintrbug, CTLFLAG_RW,
+TUNABLE_INT("hw.usb.ehci.iaadbug", &ehciiaadbug);
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, lostintrbug, CTLFLAG_RW | CTLFLAG_TUN,
     &ehcilostintrbug, 0, "Enable lost interrupt bug workaround");
-
-TUNABLE_INT("hw.usb.ehci.debug", &ehcidebug);
-TUNABLE_INT("hw.usb.ehci.no_hs", &ehcinohighspeed);
-TUNABLE_INT("hw.usb.ehci.iaadbug", &ehciiaadbug);
 TUNABLE_INT("hw.usb.ehci.lostintrbug", &ehcilostintrbug);
 
+
 static void ehci_dump_regs(ehci_softc_t *sc);
 static void ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *sqh);
 
@@ -332,14 +332,18 @@
 	sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
 	sc->sc_bus.usbrev = USB_REV_2_0;
 
-	/* Reset the controller */
-	DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev));
+	if (!(sc->sc_flags & EHCI_SCFLG_DONTRESET)) {
+		/* Reset the controller */
+		DPRINTF("%s: resetting\n",
+		    device_get_nameunit(sc->sc_bus.bdev));
 
-	err = ehci_hcreset(sc);
-	if (err) {
-		device_printf(sc->sc_bus.bdev, "reset timeout\n");
-		return (err);
+		err = ehci_hcreset(sc);
+		if (err) {
+			device_printf(sc->sc_bus.bdev, "reset timeout\n");
+			return (err);
+		}
 	}
+
 	/*
 	 * use current frame-list-size selection 0: 1024*4 bytes 1:  512*4
 	 * bytes 2:  256*4 bytes 3:      unknown
@@ -3369,7 +3373,7 @@
 
 			/* Wait for reset to complete. */
 			usb_pause_mtx(&sc->sc_bus.bus_mtx,
-			    USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY));
+			    USB_MS_TO_TICKS(usb_port_root_reset_delay));
 
 			/* Terminate reset sequence. */
 			if (!(sc->sc_flags & EHCI_SCFLG_NORESTERM))

Modified: trunk/sys/dev/usb/controller/ehci.h
===================================================================
--- trunk/sys/dev/usb/controller/ehci.h	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/ehci.h	2013-12-28 15:28:26 UTC (rev 6567)
@@ -345,6 +345,8 @@
 #define	EHCI_SCFLG_TT		0x0020	/* transaction translator present */
 #define	EHCI_SCFLG_LOSTINTRBUG	0x0040	/* workaround for VIA / ATI chipsets */
 #define	EHCI_SCFLG_IAADBUG	0x0080	/* workaround for nVidia chipsets */
+#define	EHCI_SCFLG_DONTRESET	0x0100	/* don't reset ctrl. in ehci_init() */
+#define	EHCI_SCFLG_DONEINIT	0x1000	/* ehci_init() has been called. */
 
 	uint8_t	sc_offs;		/* offset to operational registers */
 	uint8_t	sc_doorbell_disable;	/* set on doorbell failure */

Modified: trunk/sys/dev/usb/controller/musb_otg.c
===================================================================
--- trunk/sys/dev/usb/controller/musb_otg.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/musb_otg.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -85,7 +85,7 @@
 #ifdef USB_DEBUG
 static int musbotgdebug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg");
 SYSCTL_INT(_hw_usb_musbotg, OID_AUTO, debug, CTLFLAG_RW,
     &musbotgdebug, 0, "Debug level");
 #endif

Modified: trunk/sys/dev/usb/controller/ohci.c
===================================================================
--- trunk/sys/dev/usb/controller/ohci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/ohci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -80,10 +80,9 @@
 #ifdef USB_DEBUG
 static int ohcidebug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci");
-SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci");
+SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &ohcidebug, 0, "ohci debug level");
-
 TUNABLE_INT("hw.usb.ohci.debug", &ohcidebug);
 
 static void ohci_dumpregs(ohci_softc_t *);
@@ -2344,7 +2343,7 @@
 			for (v = 0;; v++) {
 				if (v < 12) {
 					usb_pause_mtx(&sc->sc_bus.bus_mtx,
-					    USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY));
+					    USB_MS_TO_TICKS(usb_port_root_reset_delay));
 
 					if ((OREAD4(sc, port) & UPS_RESET) == 0) {
 						break;

Modified: trunk/sys/dev/usb/controller/ohci_pci.c
===================================================================
--- trunk/sys/dev/usb/controller/ohci_pci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/ohci_pci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -134,6 +134,8 @@
 		return "ATI SB400 USB Controller";
 	case 0x43971002:
 		return ("AMD SB7x0/SB8x0/SB9x0 USB controller");
+	case 0x43981002:
+		return ("AMD SB7x0/SB8x0/SB9x0 USB controller");
 	case 0x43991002:
 		return ("AMD SB7x0/SB8x0/SB9x0 USB controller");
 

Modified: trunk/sys/dev/usb/controller/uhci.c
===================================================================
--- trunk/sys/dev/usb/controller/uhci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/uhci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -85,13 +85,12 @@
 static int uhcidebug = 0;
 static int uhcinoloop = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci");
-SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci");
+SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &uhcidebug, 0, "uhci debug level");
-SYSCTL_INT(_hw_usb_uhci, OID_AUTO, loop, CTLFLAG_RW,
+TUNABLE_INT("hw.usb.uhci.debug", &uhcidebug);
+SYSCTL_INT(_hw_usb_uhci, OID_AUTO, loop, CTLFLAG_RW | CTLFLAG_TUN,
     &uhcinoloop, 0, "uhci noloop");
-
-TUNABLE_INT("hw.usb.uhci.debug", &uhcidebug);
 TUNABLE_INT("hw.usb.uhci.loop", &uhcinoloop);
 
 static void uhci_dumpregs(uhci_softc_t *sc);
@@ -2393,7 +2392,7 @@
 	UWRITE2(sc, port, x | UHCI_PORTSC_PR);
 
 	usb_pause_mtx(&sc->sc_bus.bus_mtx,
-	    USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY));
+	    USB_MS_TO_TICKS(usb_port_root_reset_delay));
 
 	DPRINTFN(4, "uhci port %d reset, status0 = 0x%04x\n",
 	    index, UREAD2(sc, port));
@@ -2421,7 +2420,7 @@
 	for (lim = 0; lim < 12; lim++) {
 
 		usb_pause_mtx(&sc->sc_bus.bus_mtx,
-		    USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
+		    USB_MS_TO_TICKS(usb_port_reset_delay));
 
 		x = UREAD2(sc, port);
 

Modified: trunk/sys/dev/usb/controller/usb_controller.c
===================================================================
--- trunk/sys/dev/usb/controller/usb_controller.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/usb_controller.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -79,7 +79,7 @@
 #ifdef USB_DEBUG
 static int usb_ctrl_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller");
 SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb_ctrl_debug, 0,
     "Debug level");
 #endif
@@ -86,7 +86,7 @@
 
 static int usb_no_boot_wait = 0;
 TUNABLE_INT("hw.usb.no_boot_wait", &usb_no_boot_wait);
-SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RDTUN, &usb_no_boot_wait, 0,
+SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RD|CTLFLAG_TUN, &usb_no_boot_wait, 0,
     "No USB device enumerate waiting at boot.");
 
 static int usb_no_suspend_wait = 0;
@@ -407,6 +407,7 @@
 	struct usb_bus *bus;
 	struct usb_device *udev;
 	usb_error_t err;
+	uint8_t do_unlock;
 
 	bus = ((struct usb_bus_msg *)pm)->bus;
 	udev = bus->devices[USB_ROOT_HUB_ADDR];
@@ -427,7 +428,7 @@
 
 	bus_generic_shutdown(bus->bdev);
 
-	usbd_enum_lock(udev);
+	do_unlock = usbd_enum_lock(udev);
 
 	err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
 	if (err)
@@ -444,7 +445,8 @@
 	if (bus->methods->set_hw_power_sleep != NULL)
 		(bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND);
 
-	usbd_enum_unlock(udev);
+	if (do_unlock)
+		usbd_enum_unlock(udev);
 
 	USB_BUS_LOCK(bus);
 }
@@ -460,6 +462,7 @@
 	struct usb_bus *bus;
 	struct usb_device *udev;
 	usb_error_t err;
+	uint8_t do_unlock;
 
 	bus = ((struct usb_bus_msg *)pm)->bus;
 	udev = bus->devices[USB_ROOT_HUB_ADDR];
@@ -469,7 +472,7 @@
 
 	USB_BUS_UNLOCK(bus);
 
-	usbd_enum_lock(udev);
+	do_unlock = usbd_enum_lock(udev);
 #if 0
 	DEVMETHOD(usb_take_controller, NULL);	/* dummy */
 #endif
@@ -503,7 +506,8 @@
 		    "attach root HUB\n");
 	}
 
-	usbd_enum_unlock(udev);
+	if (do_unlock)
+		usbd_enum_unlock(udev);
 
 	USB_BUS_LOCK(bus);
 }
@@ -519,6 +523,7 @@
 	struct usb_bus *bus;
 	struct usb_device *udev;
 	usb_error_t err;
+	uint8_t do_unlock;
 
 	bus = ((struct usb_bus_msg *)pm)->bus;
 	udev = bus->devices[USB_ROOT_HUB_ADDR];
@@ -530,7 +535,7 @@
 
 	bus_generic_shutdown(bus->bdev);
 
-	usbd_enum_lock(udev);
+	do_unlock = usbd_enum_lock(udev);
 
 	err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
 	if (err)
@@ -547,7 +552,8 @@
 	if (bus->methods->set_hw_power_sleep != NULL)
 		(bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN);
 
-	usbd_enum_unlock(udev);
+	if (do_unlock)
+		usbd_enum_unlock(udev);
 
 	USB_BUS_LOCK(bus);
 }
@@ -871,3 +877,28 @@
 
 	mtx_destroy(&bus->bus_mtx);
 }
+
+/* convenience wrappers */
+void
+usb_proc_explore_mwait(struct usb_device *udev, void *pm1, void *pm2)
+{
+	usb_proc_mwait(&udev->bus->explore_proc, pm1, pm2);
+}
+
+void	*
+usb_proc_explore_msignal(struct usb_device *udev, void *pm1, void *pm2)
+{
+	return (usb_proc_msignal(&udev->bus->explore_proc, pm1, pm2));
+}
+
+void
+usb_proc_explore_lock(struct usb_device *udev)
+{
+	USB_BUS_LOCK(udev->bus);
+}
+
+void
+usb_proc_explore_unlock(struct usb_device *udev)
+{
+	USB_BUS_UNLOCK(udev->bus);
+}

Modified: trunk/sys/dev/usb/controller/uss820dci.c
===================================================================
--- trunk/sys/dev/usb/controller/uss820dci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/uss820dci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -79,7 +79,8 @@
 #ifdef USB_DEBUG
 static int uss820dcidebug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uss820dci, CTLFLAG_RW, 0, "USB uss820dci");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uss820dci, CTLFLAG_RW, 0,
+    "USB uss820dci");
 SYSCTL_INT(_hw_usb_uss820dci, OID_AUTO, debug, CTLFLAG_RW,
     &uss820dcidebug, 0, "uss820dci debug level");
 #endif

Modified: trunk/sys/dev/usb/controller/xhci.c
===================================================================
--- trunk/sys/dev/usb/controller/xhci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/xhci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -84,14 +84,16 @@
     ((uint8_t *)&(((struct xhci_softc *)0)->sc_bus))))
 
 #ifdef USB_DEBUG
-static int xhcidebug = 0;
+static int xhcidebug;
+static int xhciroute;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI");
-SYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI");
+SYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &xhcidebug, 0, "Debug level");
-
 TUNABLE_INT("hw.usb.xhci.debug", &xhcidebug);
-
+SYSCTL_INT(_hw_usb_xhci, OID_AUTO, xhci_port_route, CTLFLAG_RW | CTLFLAG_TUN,
+    &xhciroute, 0, "Routing bitmap for switching EHCI ports to XHCI controller");
+TUNABLE_INT("hw.usb.xhci.xhci_port_route", &xhciroute);
 #endif
 
 #define	XHCI_INTR_ENDPT 1
@@ -177,6 +179,16 @@
 }
 #endif
 
+uint32_t
+xhci_get_port_route(void)
+{
+#ifdef USB_DEBUG
+	return (0xFFFFFFFFU ^ ((uint32_t)xhciroute));
+#else
+	return (0xFFFFFFFFU);
+#endif
+}
+
 static void
 xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
 {
@@ -874,6 +886,12 @@
 			 * a short packet also makes the transfer done
 			 */
 			if (td->remainder > 0) {
+				if (td->alt_next == NULL) {
+					DPRINTF(
+					    "short TD has no alternate next\n");
+					xhci_generic_done(xfer);
+					break;
+				}
 				DPRINTF("TD has short pkt\n");
 				if (xfer->flags_int.short_frames_ok ||
 				    xfer->flags_int.isochronous_xfr ||
@@ -1428,26 +1446,37 @@
 xhci_interrupt(struct xhci_softc *sc)
 {
 	uint32_t status;
-	uint32_t temp;
+	uint32_t iman;
 
 	USB_BUS_LOCK(&sc->sc_bus);
 
 	status = XREAD4(sc, oper, XHCI_USBSTS);
+	if (status == 0)
+		goto done;
 
 	/* acknowledge interrupts */
 
 	XWRITE4(sc, oper, XHCI_USBSTS, status);
 
-	temp = XREAD4(sc, runt, XHCI_IMAN(0));
+	DPRINTFN(16, "real interrupt (status=0x%08x)\n", status);
+ 
+	if (status & XHCI_STS_EINT) {
 
-	/* acknowledge pending event */
+		/* acknowledge pending event */
+		iman = XREAD4(sc, runt, XHCI_IMAN(0));
 
-	XWRITE4(sc, runt, XHCI_IMAN(0), temp);
+		/* reset interrupt */
+		XWRITE4(sc, runt, XHCI_IMAN(0), iman);
+ 
+		DPRINTFN(16, "real interrupt (iman=0x%08x)\n", iman);
+ 
+		/* check for event(s) */
+		xhci_interrupt_poll(sc);
+	}
 
-	DPRINTFN(16, "real interrupt (sts=0x%08x, "
-	    "iman=0x%08x)\n", status, temp);
+	if (status & (XHCI_STS_PCD | XHCI_STS_HCH |
+	    XHCI_STS_HSE | XHCI_STS_HCE)) {
 
-	if (status != 0) {
 		if (status & XHCI_STS_PCD) {
 			xhci_root_intr(sc);
 		}
@@ -1467,9 +1496,7 @@
 			   __FUNCTION__);
 		}
 	}
-
-	xhci_interrupt_poll(sc);
-
+done:
 	USB_BUS_UNLOCK(&sc->sc_bus);
 }
 
@@ -1506,9 +1533,11 @@
 	struct xhci_td *td;
 	struct xhci_td *td_next;
 	struct xhci_td *td_alt_next;
+	struct xhci_td *td_first;
 	uint32_t buf_offset;
 	uint32_t average;
 	uint32_t len_old;
+	uint32_t npkt_off;
 	uint32_t dword;
 	uint8_t shortpkt_old;
 	uint8_t precompute;
@@ -1518,12 +1547,13 @@
 	buf_offset = 0;
 	shortpkt_old = temp->shortpkt;
 	len_old = temp->len;
+	npkt_off = 0;
 	precompute = 1;
 
 restart:
 
 	td = temp->td;
-	td_next = temp->td_next;
+	td_next = td_first = temp->td_next;
 
 	while (1) {
 
@@ -1624,7 +1654,6 @@
 			/* fill out buffer pointers */
 
 			if (average == 0) {
-				npkt = 1;
 				memset(&buf_res, 0, sizeof(buf_res));
 			} else {
 				usbd_get_page(temp->pc, temp->offset +
@@ -1638,14 +1667,18 @@
 				if (buf_res.length > XHCI_TD_PAGE_SIZE)
 					buf_res.length = XHCI_TD_PAGE_SIZE;
 
-				/* setup npkt */
-				npkt = (average + temp->max_packet_size - 1) /
-				    temp->max_packet_size;
-
-				if (npkt > 31)
-					npkt = 31;
+				npkt_off += buf_res.length;
 			}
 
+			/* setup npkt */
+			npkt = (len_old - npkt_off + temp->max_packet_size - 1) /
+			    temp->max_packet_size;
+
+			if (npkt == 0)
+				npkt = 1;
+			else if (npkt > 31)
+				npkt = 31;
+
 			/* fill out TRB's */
 			td->td_trb[x].qwTrb0 =
 			    htole64((uint64_t)buf_res.physaddr);
@@ -1657,32 +1690,51 @@
 
 			td->td_trb[x].dwTrb2 = htole32(dword);
 
-			dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
-			  XHCI_TRB_3_TYPE_SET(temp->trb_type) |
-			  (temp->do_isoc_sync ?
-			   XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8) :
-			   XHCI_TRB_3_ISO_SIA_BIT) |
-			  XHCI_TRB_3_TBC_SET(temp->tbc) |
-			  XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
-
-			temp->do_isoc_sync = 0;
-
-			if (temp->direction == UE_DIR_IN) {
-				dword |= XHCI_TRB_3_DIR_IN;
-
-				/*
-				 * NOTE: Only the SETUP stage should
-				 * use the IDT bit. Else transactions
-				 * can be sent using the wrong data
-				 * toggle value.
-				 */
-				if (temp->trb_type !=
-				    XHCI_TRB_TYPE_SETUP_STAGE &&
-				    temp->trb_type !=
-				    XHCI_TRB_TYPE_STATUS_STAGE)
-					dword |= XHCI_TRB_3_ISP_BIT;
+			switch (temp->trb_type) {
+			case XHCI_TRB_TYPE_ISOCH:
+				dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+				    XHCI_TRB_3_TBC_SET(temp->tbc) |
+				    XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+				if (td != td_first) {
+					dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL);
+				} else if (temp->do_isoc_sync != 0) {
+					temp->do_isoc_sync = 0;
+					/* wait until "isoc_frame" */
+					dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) |
+					    XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8);
+				} else {
+					/* start data transfer at next interval */
+					dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) |
+					    XHCI_TRB_3_ISO_SIA_BIT;
+				}
+				if (temp->direction == UE_DIR_IN)
+					dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+				break;
+			case XHCI_TRB_TYPE_DATA_STAGE:
+				dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+				    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE) |
+				    XHCI_TRB_3_TBC_SET(temp->tbc) |
+				    XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+				if (temp->direction == UE_DIR_IN)
+					dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+				break;
+			case XHCI_TRB_TYPE_STATUS_STAGE:
+				dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+				    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE) |
+				    XHCI_TRB_3_TBC_SET(temp->tbc) |
+				    XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+				if (temp->direction == UE_DIR_IN)
+					dword |= XHCI_TRB_3_DIR_IN;
+				break;
+			default:	/* XHCI_TRB_TYPE_NORMAL */
+				dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+				    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) |
+				    XHCI_TRB_3_TBC_SET(temp->tbc) |
+				    XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+				if (temp->direction == UE_DIR_IN)
+					dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+				break;
 			}
-
 			td->td_trb[x].dwTrb3 = htole32(dword);
 
 			average -= buf_res.length;
@@ -1746,10 +1798,16 @@
 		goto restart;
 	}
 
-	/* remove cycle bit from first if we are stepping the TRBs */
-	if (temp->step_td)
-		td->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+	/*
+	 * Remove cycle bit from the first TRB if we are
+	 * stepping them:
+	 */
+	if (temp->step_td != 0) {
+		td_first->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+		usb_pc_cpu_flush(td_first->page_cache);
+	}
 
+	/* clear TD SIZE to zero, hence this is the last TRB */
 	/* remove chain bit because this is the last TRB in the chain */
 	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);
@@ -2032,7 +2090,9 @@
 	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
 	struct usb_page_search buf_inp;
 	struct xhci_input_dev_ctx *pinp;
+	uint32_t temp;
 	uint8_t index;
+	uint8_t x;
 
 	index = udev->controller_slot_id;
 
@@ -2047,6 +2107,24 @@
 	} else {
 		xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx0, 0);
 		xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx1, mask);
+
+		/* find most significant set bit */
+		for (x = 31; x != 1; x--) {
+			if (mask & (1 << x))
+				break;
+		}
+
+		/* adjust */
+		x--;
+
+		/* figure out maximum */
+		if (x > sc->sc_hw.devs[index].context_num) {
+			sc->sc_hw.devs[index].context_num = x;
+			temp = xhci_ctx_get_le32(sc, &pinp->ctx_slot.dwSctx0);
+			temp &= ~XHCI_SCTX_0_CTX_NUM_SET(31);
+			temp |= XHCI_SCTX_0_CTX_NUM_SET(x + 1);
+			xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp);
+		}
 	}
 	return (0);
 }
@@ -2268,17 +2346,10 @@
 
 	DPRINTF("Route=0x%08x\n", route);
 
-	temp = XHCI_SCTX_0_ROUTE_SET(route);
+	temp = XHCI_SCTX_0_ROUTE_SET(route) |
+	    XHCI_SCTX_0_CTX_NUM_SET(
+	    sc->sc_hw.devs[index].context_num + 1);
 
-	switch (sc->sc_hw.devs[index].state) {
-	case XHCI_ST_CONFIGURED:
-		temp |= XHCI_SCTX_0_CTX_NUM_SET(XHCI_MAX_ENDPOINTS - 1);
-		break;
-	default:
-		temp |= XHCI_SCTX_0_CTX_NUM_SET(1);
-		break;
-	}
-
 	switch (udev->speed) {
 	case USB_SPEED_LOW:
 		temp |= XHCI_SCTX_0_SPEED_SET(2);
@@ -2421,8 +2492,9 @@
 
 	if (usb_pc_alloc_mem(pc, pg, sc->sc_ctx_is_64_byte ?
 	    (2 * sizeof(struct xhci_input_dev_ctx)) :
-	     sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE))
+	    sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE)) {
 		goto error;
+	}
 
 	pc = &sc->sc_hw.devs[index].endpoint_pc;
 	pg = &sc->sc_hw.devs[index].endpoint_pg;
@@ -2430,8 +2502,10 @@
 	/* need to initialize the page cache */
 	pc->tag_parent = sc->sc_bus.dma_parent_tag;
 
-	if (usb_pc_alloc_mem(pc, pg, sizeof(struct xhci_dev_endpoint_trbs), XHCI_PAGE_SIZE))
+	if (usb_pc_alloc_mem(pc, pg,
+	    sizeof(struct xhci_dev_endpoint_trbs), XHCI_PAGE_SIZE)) {
 		goto error;
+	}
 
 	/* initialise all endpoint LINK TRBs */
 
@@ -2438,7 +2512,8 @@
 	for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) {
 
 		/* lookup endpoint TRB ring */
-		usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[i][0], &buf_ep);
+		usbd_get_page(pc, (uintptr_t)&
+		    ((struct xhci_dev_endpoint_trbs *)0)->trb[i][0], &buf_ep);
 
 		/* get TRB pointer */
 		trb = buf_ep.buffer;
@@ -2524,8 +2599,10 @@
 	epno = XHCI_EPNO2EPID(epno);
 	index = xfer->xroot->udev->controller_slot_id;
 
-	if (xfer->xroot->udev->flags.self_suspended == 0)
-		XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0));
+	if (xfer->xroot->udev->flags.self_suspended == 0) {
+		XWRITE4(sc, door, XHCI_DOORBELL(index),
+		    epno | XHCI_DB_SID_SET(/*xfer->stream_id*/ 0));
+	}
 }
 
 static void
@@ -2555,6 +2632,7 @@
 {
 	struct xhci_td *td_first;
 	struct xhci_td *td_last;
+	struct xhci_trb *trb_link;
 	struct xhci_endpoint_ext *pepext;
 	uint64_t addr;
 	uint8_t i;
@@ -2620,11 +2698,15 @@
 	/* compute terminating return address */
 	addr += inext * sizeof(struct xhci_trb);
 
+	/* compute link TRB pointer */
+	trb_link = td_last->td_trb + td_last->ntrb;
+
 	/* update next pointer of last link TRB */
-	td_last->td_trb[td_last->ntrb].qwTrb0 = htole64(addr);
-	td_last->td_trb[td_last->ntrb].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0));
-	td_last->td_trb[td_last->ntrb].dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT |
-	    XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
+	trb_link->qwTrb0 = htole64(addr);
+	trb_link->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0));
+	trb_link->dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT |
+	    XHCI_TRB_3_CYCLE_BIT |
+	    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
 
 #ifdef USB_DEBUG
 	xhci_dump_trb(&td_last->td_trb[td_last->ntrb]);
@@ -3527,7 +3609,7 @@
 	 * endpoint context state diagram in the XHCI specification:
 	 */
 
-	xhci_configure_mask(udev, 1U << epno, 0);
+	xhci_configure_mask(udev, (1U << epno) | 1U, 0);
 
 	err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index);
 
@@ -3803,6 +3885,7 @@
 	struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
 	uint8_t index;
 	uint8_t n;
+	uint8_t p;
 
 	DPRINTF("\n");
 
@@ -3818,8 +3901,12 @@
 
 	USB_BUS_LOCK(udev->bus);
 
-	for (n = 1; n != XHCI_MAX_ENDPOINTS; n++)
-		XWRITE4(sc, door, XHCI_DOORBELL(index), n | XHCI_DB_SID_SET(0));
+	for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) {
+		for (p = 0; p != 1 /*XHCI_MAX_STREAMS*/; p++) {
+			XWRITE4(sc, door, XHCI_DOORBELL(index),
+			    n | XHCI_DB_SID_SET(p));
+		}
+	}
 
 	USB_BUS_UNLOCK(udev->bus);
 
@@ -3893,8 +3980,12 @@
 		if (sc->sc_hw.devs[index].state == XHCI_ST_DEFAULT)
 			break;
 
+		/* set default state */
 		sc->sc_hw.devs[index].state = XHCI_ST_DEFAULT;
 
+		/* reset number of contexts */
+		sc->sc_hw.devs[index].context_num = 0;
+
 		err = xhci_cmd_reset_dev(sc, index);
 
 		if (err != 0) {
@@ -3921,11 +4012,15 @@
 		if (sc->sc_hw.devs[index].state == XHCI_ST_CONFIGURED)
 			break;
 
+		/* set configured state */
 		sc->sc_hw.devs[index].state = XHCI_ST_CONFIGURED;
 
+		/* reset number of contexts */
+		sc->sc_hw.devs[index].context_num = 0;
+
 		usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
 
-		xhci_configure_mask(udev, 1, 0);
+		xhci_configure_mask(udev, 3, 0);
 
 		err = xhci_configure_device(udev);
 		if (err != 0) {

Modified: trunk/sys/dev/usb/controller/xhci.h
===================================================================
--- trunk/sys/dev/usb/controller/xhci.h	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/xhci.h	2013-12-28 15:28:26 UTC (rev 6567)
@@ -385,7 +385,7 @@
 	uint8_t			state;
 	uint8_t			nports;
 	uint8_t			tt;
-	uint8_t			reserved;
+	uint8_t			context_num;
 };
 
 struct xhci_hw_softc {
@@ -436,6 +436,7 @@
 
 	struct usb_device	*sc_devices[XHCI_MAX_DEVICES];
 	struct resource		*sc_io_res;
+	int			sc_irq_rid;
 	struct resource		*sc_irq_res;
 
 	void			*sc_intr_hdl;
@@ -490,6 +491,7 @@
 
 /* prototypes */
 
+uint32_t	xhci_get_port_route(void);
 usb_error_t xhci_halt_controller(struct xhci_softc *);
 usb_error_t xhci_init(struct xhci_softc *, device_t);
 usb_error_t xhci_start_controller(struct xhci_softc *);

Modified: trunk/sys/dev/usb/controller/xhci_pci.c
===================================================================
--- trunk/sys/dev/usb/controller/xhci_pci.c	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/xhci_pci.c	2013-12-28 15:28:26 UTC (rev 6567)
@@ -99,8 +99,13 @@
 	case 0x01941033:
 		return ("NEC uPD720200 USB 3.0 controller");
 
+	case 0x10421b21:
+		return ("ASMedia ASM1042 USB 3.0 controller");
+
 	case 0x1e318086:
 		return ("Intel Panther Point USB 3.0 controller");
+	case 0x8c318086:
+		return ("Intel Lynx Point USB 3.0 controller");
 
 	default:
 		break;
@@ -127,12 +132,14 @@
 	}
 }
 
+static int xhci_use_msi = 1;
+TUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi);
+
 static int
 xhci_pci_attach(device_t self)
 {
 	struct xhci_softc *sc = device_get_softc(self);
-	int err;
-	int rid;
+	int count, err, rid;
 
 	/* XXX check for 64-bit capability */
 
@@ -154,9 +161,20 @@
 	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
 	sc->sc_io_size = rman_get_size(sc->sc_io_res);
 
-	rid = 0;
-	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
-	    RF_SHAREABLE | RF_ACTIVE);
+	sc->sc_irq_rid = 0;
+	if (xhci_use_msi) {
+		count = pci_msi_count(self);
+		if (count >= 1) {
+			count = 1;
+			if (pci_alloc_msi(self, &count) == 0) {
+				if (bootverbose)
+					device_printf(self, "MSI enabled\n");
+				sc->sc_irq_rid = 1;
+			}
+		}
+	}
+	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ,
+	    &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE);
 	if (sc->sc_irq_res == NULL) {
 		device_printf(self, "Could not allocate IRQ\n");
 		goto error;
@@ -227,7 +245,10 @@
 		sc->sc_intr_hdl = NULL;
 	}
 	if (sc->sc_irq_res) {
-		bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
+		if (sc->sc_irq_rid == 1)
+			pci_release_msi(self);
+		bus_release_resource(self, SYS_RES_IRQ, sc->sc_irq_rid,
+		    sc->sc_irq_res);
 		sc->sc_irq_res = NULL;
 	}
 	if (sc->sc_io_res) {
@@ -245,6 +266,7 @@
 xhci_pci_take_controller(device_t self)
 {
 	struct xhci_softc *sc = device_get_softc(self);
+	uint32_t device_id = pci_get_devid(self);
 	uint32_t cparams;
 	uint32_t eecp;
 	uint32_t eec;
@@ -285,5 +307,13 @@
 			usb_pause_mtx(NULL, hz / 100);	/* wait 10ms */
 		}
 	}
+
+	/* On Intel chipsets reroute ports from EHCI to XHCI controller. */
+	if (device_id == 0x1e318086 /* Panther Point */ ||
+	    device_id == 0x8c318086 /* Lynx Point */) {
+		uint32_t temp = xhci_get_port_route();
+		pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp, 4);
+		pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp, 4);
+	}
 	return (0);
 }

Modified: trunk/sys/dev/usb/controller/xhcireg.h
===================================================================
--- trunk/sys/dev/usb/controller/xhcireg.h	2013-12-28 15:27:54 UTC (rev 6566)
+++ trunk/sys/dev/usb/controller/xhcireg.h	2013-12-28 15:28:26 UTC (rev 6567)
@@ -34,6 +34,9 @@
 #define	PCI_USB_REV_3_0		0x30	/* USB 3.0 */
 #define	PCI_XHCI_FLADJ		0x61	/* RW frame length adjust */
 
+#define	PCI_XHCI_INTEL_XUSB2PR	0xD0	/* Intel USB2 Port Routing */
+#define	PCI_XHCI_INTEL_USB3_PSSEN 0xD8	/* Intel USB3 Port SuperSpeed Enable */
+
 /* XHCI capability registers */
 #define	XHCI_CAPLENGTH		0x00	/* RO capability */
 #define	XHCI_RESERVED		0x01	/* Reserved */
@@ -163,7 +166,7 @@
 #define	XHCI_IMOD_IVAL_SET(x)	(((x) & 0xFFFF) << 0)	/* 250ns unit */
 #define	XHCI_IMOD_ICNT_GET(x)	(((x) >> 16) & 0xFFFF)	/* 250ns unit */
 #define	XHCI_IMOD_ICNT_SET(x)	(((x) & 0xFFFF) << 16)	/* 250ns unit */
-#define	XHCI_IMOD_DEFAULT	0x000001F4U	/* 8000 IRQ/second */
+#define	XHCI_IMOD_DEFAULT	0x000003E8U	/* 8000 IRQ/second */
 #define	XHCI_ERSTSZ(n)		(0x0028 + (0x20 * (n)))	/* XHCI event ring segment table size */
 #define	XHCI_ERSTS_GET(x)	((x) & 0xFFFF)
 #define	XHCI_ERSTS_SET(x)	((x) & 0xFFFF)



More information about the Midnightbsd-cvs mailing list