[Midnightbsd-cvs] src [6571] trunk/sys/dev/usb/controller: Disable XHCI port routing in case of several error conditions known to happen on intel Z87 chipsets.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Dec 29 12:50:49 EST 2013


Revision: 6571
          http://svnweb.midnightbsd.org/src/?rev=6571
Author:   laffer1
Date:     2013-12-29 12:50:49 -0500 (Sun, 29 Dec 2013)
Log Message:
-----------
Disable XHCI port routing in case of several error conditions known to happen on intel Z87 chipsets.  Obtained from: FreeBSD 9-stable (r255965)

Revision Links:
--------------
    http://svnweb.midnightbsd.org/src/?rev=255965

Modified Paths:
--------------
    trunk/sys/dev/usb/controller/xhci.c
    trunk/sys/dev/usb/controller/xhci.h
    trunk/sys/dev/usb/controller/xhci_pci.c

Modified: trunk/sys/dev/usb/controller/xhci.c
===================================================================
--- trunk/sys/dev/usb/controller/xhci.c	2013-12-28 15:32:07 UTC (rev 6570)
+++ trunk/sys/dev/usb/controller/xhci.c	2013-12-29 17:50:49 UTC (rev 6571)
@@ -94,6 +94,8 @@
 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);
+#else
+#define	xhciroute 0
 #endif
 
 #define	XHCI_INTR_ENDPT 1
@@ -179,16 +181,6 @@
 }
 #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)
 {
@@ -480,6 +472,11 @@
 	/* catch any lost interrupts */
 	xhci_do_poll(&sc->sc_bus);
 
+	if (sc->sc_port_route != NULL) {
+		/* Route all ports to the XHCI by default */
+		sc->sc_port_route(sc->sc_bus.parent,
+		    ~xhciroute, xhciroute);
+	}
 	return (0);
 }
 
@@ -917,7 +914,7 @@
 	}
 }
 
-static void
+static int
 xhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb)
 {
 	if (sc->sc_cmd_addr == trb->qwTrb0) {
@@ -925,10 +922,12 @@
 		sc->sc_cmd_result[0] = trb->dwTrb2;
 		sc->sc_cmd_result[1] = trb->dwTrb3;
 		cv_signal(&sc->sc_cmd_cv);
+		return (1);	/* command match */
 	}
+	return (0);
 }
 
-static void
+static int
 xhci_interrupt_poll(struct xhci_softc *sc)
 {
 	struct usb_page_search buf_res;
@@ -935,6 +934,7 @@
 	struct xhci_hw_root *phwr;
 	uint64_t addr;
 	uint32_t temp;
+	int retval = 0;
 	uint16_t i;
 	uint8_t event;
 	uint8_t j;
@@ -974,7 +974,7 @@
 			xhci_check_transfer(sc, &phwr->hwr_events[i]);
 			break;
 		case XHCI_TRB_EVENT_CMD_COMPLETE:
-			xhci_check_command(sc, &phwr->hwr_events[i]);
+			retval |= xhci_check_command(sc, &phwr->hwr_events[i]);
 			break;
 		default:
 			DPRINTF("Unhandled event = %u\n", event);
@@ -1011,6 +1011,8 @@
 
 	XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr);
 	XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32));
+
+	return (retval);
 }
 
 static usb_error_t
@@ -1098,7 +1100,15 @@
 	err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx,
 	    USB_MS_TO_TICKS(timeout_ms));
 
-	if (err) {
+	/*
+	 * In some error cases event interrupts are not generated.
+	 * Poll one time to see if the command has completed.
+	 */
+	if (err != 0 && xhci_interrupt_poll(sc) != 0) {
+		DPRINTF("Command was completed when polling\n");
+		err = 0;
+	}
+	if (err != 0) {
 		DPRINTFN(0, "Command timeout!\n");
 		err = USB_ERR_TIMEOUT;
 		trb->dwTrb2 = 0;
@@ -1277,6 +1287,14 @@
 		    (address == 0), index);
 
 		if (err != 0) {
+			temp = le32toh(sc->sc_cmd_result[0]);
+			if (address == 0 && sc->sc_port_route != NULL &&
+			    XHCI_TRB_2_ERROR_GET(temp) ==
+			    XHCI_TRB_ERROR_PARAMETER) {
+				/* LynxPoint XHCI - ports are not switchable */
+				/* Un-route all ports from the XHCI */
+				sc->sc_port_route(sc->sc_bus.parent, 0, ~0);
+			}
 			DPRINTF("Could not set address "
 			    "for slot %u.\n", index);
 			if (address != 0)

Modified: trunk/sys/dev/usb/controller/xhci.h
===================================================================
--- trunk/sys/dev/usb/controller/xhci.h	2013-12-28 15:32:07 UTC (rev 6570)
+++ trunk/sys/dev/usb/controller/xhci.h	2013-12-29 17:50:49 UTC (rev 6571)
@@ -421,6 +421,8 @@
 	uint8_t				temp[128];
 };
 
+typedef int (xhci_port_route_t)(device_t, uint32_t, uint32_t);
+
 struct xhci_softc {
 	struct xhci_hw_softc	sc_hw;
 	/* base device */
@@ -429,6 +431,8 @@
 	struct usb_process	sc_config_proc;
 	struct usb_bus_msg	sc_config_msg[2];
 
+	xhci_port_route_t	*sc_port_route;
+
 	union xhci_hub_desc	sc_hub_desc;
 
 	struct cv		sc_cmd_cv;
@@ -491,7 +495,6 @@
 
 /* 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:32:07 UTC (rev 6570)
+++ trunk/sys/dev/usb/controller/xhci_pci.c	2013-12-29 17:50:49 UTC (rev 6571)
@@ -136,6 +136,25 @@
 TUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi);
 
 static int
+xhci_pci_port_route(device_t self, uint32_t set, uint32_t clear)
+{
+	uint32_t temp;
+
+	temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) |
+	    pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4);
+
+	temp |= set;
+	temp &= ~clear;
+
+	pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp, 4);
+	pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp, 4);
+
+	device_printf(self, "Port routing mask set to 0x%08x\n", temp);
+
+	return (0);
+}
+
+static int
 xhci_pci_attach(device_t self)
 {
 	struct xhci_softc *sc = device_get_softc(self);
@@ -200,6 +219,16 @@
 		sc->sc_intr_hdl = NULL;
 		goto error;
 	}
+	/* On Intel chipsets reroute ports from EHCI to XHCI controller. */
+	switch (pci_get_devid(self)) {
+	case 0x1e318086:	/* Panther Point */
+	case 0x8c318086:	/* Lynx Point */
+		sc->sc_port_route = &xhci_pci_port_route;
+		break;
+	default:
+		break;
+	}
+
 	xhci_pci_take_controller(self);
 
 	err = xhci_halt_controller(sc);
@@ -266,7 +295,6 @@
 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;
@@ -307,13 +335,5 @@
 			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);
 }



More information about the Midnightbsd-cvs mailing list