diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-10-26 21:47:16 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-10-26 21:47:16 +0000 |
commit | e7629ee2bb8183368e57023949d649f501ab1e3a (patch) | |
tree | 26d1a93a0f4d08ef8f9a568d58099f7c70932e45 /sys/dev/usb/controller | |
parent | 8f17b6fdd9def8c843751b1b5f7eb581d17a8a56 (diff) | |
download | FreeBSD-src-e7629ee2bb8183368e57023949d649f501ab1e3a.zip FreeBSD-src-e7629ee2bb8183368e57023949d649f501ab1e3a.tar.gz |
Revert r198500 for now, this will break situations when
hw.pci.usb_early_takeover is set to zero and the SMM release
is never done.
Pointed out by: marcel
Diffstat (limited to 'sys/dev/usb/controller')
-rw-r--r-- | sys/dev/usb/controller/ehci_pci.c | 49 | ||||
-rw-r--r-- | sys/dev/usb/controller/ohci.c | 24 | ||||
-rw-r--r-- | sys/dev/usb/controller/uhci_pci.c | 15 |
3 files changed, 88 insertions, 0 deletions
diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c index 5931c51..fc2035b 100644 --- a/sys/dev/usb/controller/ehci_pci.c +++ b/sys/dev/usb/controller/ehci_pci.c @@ -102,6 +102,8 @@ __FBSDID("$FreeBSD$"); #define PCI_EHCI_BASE_REG 0x10 +static void ehci_pci_takecontroller(device_t self); + static device_probe_t ehci_pci_probe; static device_attach_t ehci_pci_attach; static device_detach_t ehci_pci_detach; @@ -127,6 +129,7 @@ ehci_pci_resume(device_t self) { ehci_softc_t *sc = device_get_softc(self); + ehci_pci_takecontroller(self); ehci_resume(sc); bus_generic_resume(self); @@ -411,6 +414,7 @@ ehci_pci_attach(device_t self) sc->sc_intr_hdl = NULL; goto error; } + ehci_pci_takecontroller(self); /* Undocumented quirks taken from Linux */ @@ -502,6 +506,51 @@ ehci_pci_detach(device_t self) return (0); } +static void +ehci_pci_takecontroller(device_t self) +{ + ehci_softc_t *sc = device_get_softc(self); + uint32_t cparams; + uint32_t eec; + uint16_t to; + uint8_t eecp; + uint8_t bios_sem; + + cparams = EREAD4(sc, EHCI_HCCPARAMS); + + /* Synchronise with the BIOS if it owns the controller. */ + for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; + eecp = EHCI_EECP_NEXT(eec)) { + eec = pci_read_config(self, eecp, 4); + if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) { + continue; + } + bios_sem = pci_read_config(self, eecp + + EHCI_LEGSUP_BIOS_SEM, 1); + if (bios_sem == 0) { + continue; + } + device_printf(sc->sc_bus.bdev, "waiting for BIOS " + "to give up control\n"); + pci_write_config(self, eecp + + EHCI_LEGSUP_OS_SEM, 1, 1); + to = 500; + while (1) { + bios_sem = pci_read_config(self, eecp + + EHCI_LEGSUP_BIOS_SEM, 1); + if (bios_sem == 0) + break; + + if (--to == 0) { + device_printf(sc->sc_bus.bdev, + "timed out waiting for BIOS\n"); + break; + } + usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ + } + } +} + static driver_t ehci_driver = { .name = "ehci", diff --git a/sys/dev/usb/controller/ohci.c b/sys/dev/usb/controller/ohci.c index 2ced676..637b639 100644 --- a/sys/dev/usb/controller/ohci.c +++ b/sys/dev/usb/controller/ohci.c @@ -175,6 +175,30 @@ ohci_controller_init(ohci_softc_t *sc) uint32_t per; uint32_t desca; + /* Determine in what context we are running. */ + ctl = OREAD4(sc, OHCI_CONTROL); + if (ctl & OHCI_IR) { + /* SMM active, request change */ + DPRINTF("SMM active, request owner change\n"); + OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_OCR); + for (i = 0; (i < 100) && (ctl & OHCI_IR); i++) { + usb_pause_mtx(NULL, hz / 1000); + ctl = OREAD4(sc, OHCI_CONTROL); + } + if (ctl & OHCI_IR) { + device_printf(sc->sc_bus.bdev, + "SMM does not respond, resetting\n"); + OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); + goto reset; + } + } else { + DPRINTF("cold started\n"); +reset: + /* controller was cold started */ + usb_pause_mtx(NULL, + USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); + } + /* * This reset should not be necessary according to the OHCI spec, but * without it some controllers do not start. diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c index e367b23..3956ead 100644 --- a/sys/dev/usb/controller/uhci_pci.c +++ b/sys/dev/usb/controller/uhci_pci.c @@ -115,6 +115,8 @@ uhci_pci_resume(device_t self) { uhci_softc_t *sc = device_get_softc(self); + pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2); + uhci_resume(sc); bus_generic_resume(self); @@ -361,6 +363,19 @@ uhci_pci_attach(device_t self) sc->sc_intr_hdl = NULL; goto error; } + /* + * Set the PIRQD enable bit and switch off all the others. We don't + * want legacy support to interfere with us XXX Does this also mean + * that the BIOS won't touch the keyboard anymore if it is connected + * to the ports of the root hub? + */ +#ifdef USB_DEBUG + if (pci_read_config(self, PCI_LEGSUP, 2) != PCI_LEGSUP_USBPIRQDEN) { + device_printf(self, "LegSup = 0x%04x\n", + pci_read_config(self, PCI_LEGSUP, 2)); + } +#endif + pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2); err = uhci_init(sc); if (!err) { |