summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/usb/controller/xhci.c14
-rw-r--r--sys/dev/usb/controller/xhci.h3
-rw-r--r--sys/dev/usb/controller/xhci_pci.c47
3 files changed, 49 insertions, 15 deletions
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index fd0e254..18ebaa5 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -90,6 +90,7 @@
#ifdef USB_DEBUG
static int xhcidebug;
static int xhciroute;
+static int xhcipolling;
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,
@@ -98,6 +99,9 @@ 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);
+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);
#endif
#define XHCI_INTR_ENDPT 1
@@ -194,6 +198,16 @@ xhci_get_port_route(void)
#endif
}
+uint8_t
+xhci_use_polling(void)
+{
+#ifdef USB_DEBUG
+ return (xhcipolling != 0);
+#else
+ return (0);
+#endif
+}
+
static void
xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
{
diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h
index d02c26f..0872f40 100644
--- a/sys/dev/usb/controller/xhci.h
+++ b/sys/dev/usb/controller/xhci.h
@@ -438,6 +438,8 @@ struct xhci_softc {
/* configure message */
struct usb_bus_msg sc_config_msg[2];
+ struct usb_callout sc_callout;
+
union xhci_hub_desc sc_hub_desc;
struct cv sc_cmd_cv;
@@ -500,6 +502,7 @@ 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);
usb_error_t xhci_start_controller(struct xhci_softc *);
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index d2c9035..8695dac 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -132,6 +132,16 @@ xhci_pci_probe(device_t self)
}
}
+static void
+xhci_interrupt_poll(void *_sc)
+{
+ struct xhci_softc *sc = _sc;
+ USB_BUS_UNLOCK(&sc->sc_bus);
+ xhci_interrupt(sc);
+ USB_BUS_LOCK(&sc->sc_bus);
+ usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc);
+}
+
static int
xhci_pci_attach(device_t self)
{
@@ -159,12 +169,13 @@ xhci_pci_attach(device_t self)
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
sc->sc_io_size = rman_get_size(sc->sc_io_res);
+ usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0);
+
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
device_printf(self, "Could not allocate IRQ\n");
- goto error;
}
sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
if (sc->sc_bus.bdev == NULL) {
@@ -175,18 +186,22 @@ xhci_pci_attach(device_t self)
sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self));
-#if (__FreeBSD_version >= 700031)
- err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
- NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl);
-#else
- err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
- (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl);
-#endif
- if (err) {
- device_printf(self, "Could not setup IRQ, err=%d\n", err);
- sc->sc_intr_hdl = NULL;
- goto error;
+ if (sc->sc_irq_res != NULL) {
+ err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+ NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl);
+ if (err != 0) {
+ device_printf(self, "Could not setup IRQ, err=%d\n", err);
+ sc->sc_intr_hdl = NULL;
+ }
}
+ if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL ||
+ xhci_use_polling() != 0) {
+ device_printf(self, "Interrupt polling at %dHz\n", hz);
+ USB_BUS_LOCK(&sc->sc_bus);
+ xhci_interrupt_poll(sc);
+ USB_BUS_UNLOCK(&sc->sc_bus);
+ }
+
xhci_pci_take_controller(self);
err = xhci_halt_controller(sc);
@@ -222,12 +237,14 @@ xhci_pci_detach(device_t self)
/* during module unload there are lots of children leftover */
device_delete_children(self);
+ if (sc->sc_io_res) {
+ usb_callout_drain(&sc->sc_callout);
+ xhci_halt_controller(sc);
+ }
+
pci_disable_busmaster(self);
if (sc->sc_irq_res && sc->sc_intr_hdl) {
-
- xhci_halt_controller(sc);
-
bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
sc->sc_intr_hdl = NULL;
}
OpenPOWER on IntegriCloud