DF-5509 / fix.diff
--- a/sys/bus/u4b/controller/ehci_pci.c +++ b/sys/bus/u4b/controller/ehci_pci.c @@ -277,6 +277,7 @@ ehci_softc_t *sc = device_get_softc(self); int err; int rid; + uint8_t caplen; /* initialise some bus fields */ sc->sc_bus.parent = self; @@ -323,6 +324,25 @@ sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); + /* + * Quiesce any interrupt state left behind by the BIOS or a + * previous owner BEFORE bus_setup_intr() arms ehci_interrupt() + * below. Until ehci_init() latches sc_offs and sc_eintrs, the + * interrupt handler reads USBSTS from the wrong absolute offset + * (MMIO + 0 + 0x04 == HCSPARAMS) and unconditionally exits via + * "goto done" WITHOUT acknowledging, so a level-triggered + * pending interrupt in the window between bus_setup_intr() and + * ehci_init()'s ehci_hcreset() re-fires forever - including the + * up-to-5-second BIOS handoff wait in ehci_pci_take_controller(). + * CAPLENGTH (low byte of capability register 0) is an absolute + * offset and is therefore valid before sc_offs is initialized. + */ + caplen = bus_space_read_1(sc->sc_io_tag, sc->sc_io_hdl, 0); + bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, + caplen + EHCI_USBINTR, 0); + bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, + caplen + EHCI_USBSTS, 0xFFFFFFFF); + rid = 0; sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); |