summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/usb/controller/xhci.c46
-rw-r--r--sys/dev/usb/controller/xhci.h5
-rw-r--r--sys/dev/usb/controller/xhci_pci.c40
3 files changed, 66 insertions, 25 deletions
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index ec8b75a..0f8470e 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -108,6 +108,8 @@ TUNABLE_INT("hw.usb.xhci.xhci_port_route", &xhciroute);
SYSCTL_INT(_hw_usb_xhci, OID_AUTO, use_polling, CTLFLAG_RW | CTLFLAG_TUN,
&xhcipolling, 0, "Set to enable software interrupt polling for XHCI controller");
TUNABLE_INT("hw.usb.xhci.use_polling", &xhcipolling);
+#else
+#define xhciroute 0
#endif
#define XHCI_INTR_ENDPT 1
@@ -194,16 +196,6 @@ xhci_dump_device(struct xhci_softc *sc, struct xhci_slot_ctx *psl)
}
#endif
-uint32_t
-xhci_get_port_route(void)
-{
-#ifdef USB_DEBUG
- return (0xFFFFFFFFU ^ ((uint32_t)xhciroute));
-#else
- return (0xFFFFFFFFU);
-#endif
-}
-
uint8_t
xhci_use_polling(void)
{
@@ -505,6 +497,11 @@ xhci_start_controller(struct xhci_softc *sc)
/* 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);
}
@@ -951,7 +948,7 @@ xhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb)
}
}
-static void
+static int
xhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb)
{
if (sc->sc_cmd_addr == trb->qwTrb0) {
@@ -959,16 +956,19 @@ xhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb)
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;
struct xhci_hw_root *phwr;
uint64_t addr;
uint32_t temp;
+ int retval = 0;
uint16_t i;
uint8_t event;
uint8_t j;
@@ -1008,7 +1008,7 @@ xhci_interrupt_poll(struct xhci_softc *sc)
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);
@@ -1045,6 +1045,8 @@ xhci_interrupt_poll(struct xhci_softc *sc)
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
@@ -1132,7 +1134,15 @@ xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb,
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;
@@ -1311,6 +1321,14 @@ xhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address)
(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)
diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h
index 3d436fd..10045a7 100644
--- a/sys/dev/usb/controller/xhci.h
+++ b/sys/dev/usb/controller/xhci.h
@@ -431,6 +431,8 @@ union xhci_hub_desc {
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 */
@@ -440,6 +442,8 @@ struct xhci_softc {
struct usb_callout sc_callout;
+ xhci_port_route_t *sc_port_route;
+
union xhci_hub_desc sc_hub_desc;
struct cv sc_cmd_cv;
@@ -502,7 +506,6 @@ struct xhci_softc {
/* prototypes */
-uint32_t xhci_get_port_route(void);
uint8_t xhci_use_polling(void);
usb_error_t xhci_halt_controller(struct xhci_softc *);
usb_error_t xhci_init(struct xhci_softc *, device_t);
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index da16f51..2548fbb 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -146,6 +146,25 @@ xhci_interrupt_poll(void *_sc)
}
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);
@@ -189,7 +208,7 @@ xhci_pci_attach(device_t self)
&sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
device_printf(self, "Could not allocate IRQ\n");
- goto error;
+ /* goto error; FALLTHROUGH - use polling */
}
sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
if (sc->sc_bus.bdev == NULL) {
@@ -216,6 +235,16 @@ xhci_pci_attach(device_t self)
USB_BUS_UNLOCK(&sc->sc_bus);
}
+ /* 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);
@@ -284,7 +313,6 @@ static int
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;
@@ -325,13 +353,5 @@ xhci_pci_take_controller(device_t self)
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);
}
OpenPOWER on IntegriCloud