diff options
-rw-r--r-- | sys/dev/usb/controller/xhci.c | 46 | ||||
-rw-r--r-- | sys/dev/usb/controller/xhci.h | 5 | ||||
-rw-r--r-- | sys/dev/usb/controller/xhci_pci.c | 40 |
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); } |