[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