summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2009-10-26 21:47:16 +0000
committerthompsa <thompsa@FreeBSD.org>2009-10-26 21:47:16 +0000
commite7629ee2bb8183368e57023949d649f501ab1e3a (patch)
tree26d1a93a0f4d08ef8f9a568d58099f7c70932e45
parent8f17b6fdd9def8c843751b1b5f7eb581d17a8a56 (diff)
downloadFreeBSD-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
-rw-r--r--sys/dev/usb/controller/ehci_pci.c49
-rw-r--r--sys/dev/usb/controller/ohci.c24
-rw-r--r--sys/dev/usb/controller/uhci_pci.c15
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) {
OpenPOWER on IntegriCloud