summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2004-12-29 01:52:28 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2004-12-29 01:52:28 +0000
commite21f5a39ae887f8942ef4219e31f1ae7e5ade40c (patch)
tree0d92495fbe02d52ddc8ffd61fbb4247e4b95c341
parent72f515ed522e03c0608093ba6f814fbeebd7d9fc (diff)
from freebsd: ehci.c 1.13, ehci_pci.c 1.13, ehcireg.h 1.5, ehcivar.h 1.3
log message: Attempt to follow the correct procedure for synchronising with the system BIOS to disable legacy device emulation as per the "EHCI Extended Capability: Pre-OS to OS Handoff Synchronisation" section of the EHCI spec. BIOSes that implement legacy emulation using SMIs are supposed to disable the emulation when this procedure is performed. tested on various archs by jsg@ and me ok pascoe@, looks sane jsg@
-rw-r--r--sys/dev/cardbus/ehci_cardbus.c4
-rw-r--r--sys/dev/pci/ehci_pci.c76
-rw-r--r--sys/dev/usb/ehci.c4
-rw-r--r--sys/dev/usb/ehcireg.h15
-rw-r--r--sys/dev/usb/ehcivar.h3
5 files changed, 88 insertions, 14 deletions
diff --git a/sys/dev/cardbus/ehci_cardbus.c b/sys/dev/cardbus/ehci_cardbus.c
index 648d04b53fa..402028d0848 100644
--- a/sys/dev/cardbus/ehci_cardbus.c
+++ b/sys/dev/cardbus/ehci_cardbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci_cardbus.c,v 1.1 2004/12/07 05:42:41 dlg Exp $ */
+/* $OpenBSD: ehci_cardbus.c,v 1.2 2004/12/29 01:52:26 dlg Exp $ */
/* $NetBSD: ehci_cardbus.c,v 1.6.6.3 2004/09/21 13:27:25 skrll Exp $ */
/*
@@ -228,6 +228,8 @@ XXX (ct->ct_cf->cardbus_mem_open)(cc, 0, iob, iob + 0x40);
return;
}
+ sc->sc.sc_shutdownhook = shutdownhook_establish(ehci_shutdown, &sc->sc);
+
/* Attach usb device. */
sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
usbctlprint);
diff --git a/sys/dev/pci/ehci_pci.c b/sys/dev/pci/ehci_pci.c
index 82b1d85af24..398f6f0b27d 100644
--- a/sys/dev/pci/ehci_pci.c
+++ b/sys/dev/pci/ehci_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci_pci.c,v 1.3 2004/05/30 01:25:17 tedu Exp $ */
+/* $OpenBSD: ehci_pci.c,v 1.4 2004/12/29 01:52:27 dlg Exp $ */
/* $NetBSD: ehci_pci.c,v 1.15 2004/04/23 21:13:06 itojun Exp $ */
/*
@@ -69,10 +69,6 @@ extern int ehcidebug;
#define DPRINTF(x)
#endif
-int ehci_pci_match(struct device *, void *, void *);
-void ehci_pci_attach(struct device *, struct device *, void *);
-int ehci_pci_detach(device_ptr_t, int);
-
struct ehci_pci_softc {
ehci_softc_t sc;
pci_chipset_tag_t sc_pc;
@@ -80,6 +76,13 @@ struct ehci_pci_softc {
void *sc_ih; /* interrupt vectoring */
};
+int ehci_pci_match(struct device *, void *, void *);
+void ehci_pci_attach(struct device *, struct device *, void *);
+int ehci_pci_detach(device_ptr_t, int);
+void ehci_pci_givecontroller(struct ehci_pci_softc *);
+void ehci_pci_takecontroller(struct ehci_pci_softc *);
+void ehci_pci_shutdown(void *);
+
struct cfattach ehci_pci_ca = {
sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach,
ehci_pci_detach, ehci_activate
@@ -203,6 +206,7 @@ ehci_pci_attach(struct device *parent, struct device *self, void *aux)
}
sc->sc.sc_ncomp = ncomp;
+ ehci_pci_takecontroller(sc);
r = ehci_init(&sc->sc);
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: init failed, error=%d\n", devname, r);
@@ -210,6 +214,8 @@ ehci_pci_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ sc->sc.sc_shutdownhook = shutdownhook_establish(ehci_pci_shutdown, sc);
+
/* Attach usb device. */
sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
usbctlprint);
@@ -234,3 +240,63 @@ ehci_pci_detach(device_ptr_t self, int flags)
}
return (0);
}
+
+void
+ehci_pci_givecontroller(struct ehci_pci_softc *sc)
+{
+ u_int32_t cparams, eec, legsup;
+ int eecp;
+
+ cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
+ for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
+ eecp = EHCI_EECP_NEXT(eec)) {
+ eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
+ if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
+ continue;
+ legsup = eec;
+ pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
+ legsup & ~EHCI_LEGSUP_OSOWNED);
+ }
+}
+
+void
+ehci_pci_takecontroller(struct ehci_pci_softc *sc)
+{
+ u_int32_t cparams, eec, legsup;
+ int eecp, i;
+
+ cparams = EREAD4(&sc->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_conf_read(sc->sc_pc, sc->sc_tag, eecp);
+ if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
+ continue;
+ legsup = eec;
+ pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
+ legsup | EHCI_LEGSUP_OSOWNED);
+ if (legsup & EHCI_LEGSUP_BIOSOWNED) {
+ DPRINTF(("%s: waiting for BIOS to give up control\n",
+ USBDEVNAME(sc->sc.sc_bus.bdev)));
+ for (i = 0; i < 5000; i++) {
+ legsup = pci_conf_read(sc->sc_pc, sc->sc_tag,
+ eecp);
+ if ((legsup & EHCI_LEGSUP_BIOSOWNED) == 0)
+ break;
+ DELAY(1000);
+ }
+ if (legsup & EHCI_LEGSUP_BIOSOWNED)
+ printf("%s: timed out waiting for BIOS\n",
+ USBDEVNAME(sc->sc.sc_bus.bdev));
+ }
+ }
+}
+
+void
+ehci_pci_shutdown(void *v)
+{
+ struct ehci_pci_softc *sc = (struct ehci_pci_softc *)v;
+
+ ehci_shutdown(&sc->sc);
+ ehci_pci_givecontroller(sc);
+}
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index 4279581c0cd..363a084f0f3 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci.c,v 1.32 2004/10/31 10:29:45 dlg Exp $ */
+/* $OpenBSD: ehci.c,v 1.33 2004/12/29 01:52:27 dlg Exp $ */
/* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
/*
@@ -144,7 +144,6 @@ struct ehci_pipe {
} u;
};
-Static void ehci_shutdown(void *);
Static void ehci_power(int, void *);
Static usbd_status ehci_open(usbd_pipe_handle);
@@ -416,7 +415,6 @@ ehci_init(ehci_softc_t *sc)
sc->sc_bus.pipe_size = sizeof(struct ehci_pipe);
sc->sc_powerhook = powerhook_establish(ehci_power, sc);
- sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc);
sc->sc_eintrs = EHCI_NORMAL_INTRS;
diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h
index 3be89651e7b..76c4baffb40 100644
--- a/sys/dev/usb/ehcireg.h
+++ b/sys/dev/usb/ehcireg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehcireg.h,v 1.11 2004/10/25 22:30:04 dlg Exp $ */
+/* $OpenBSD: ehcireg.h,v 1.12 2004/12/29 01:52:27 dlg Exp $ */
/* $NetBSD: ehcireg.h,v 1.17 2004/06/23 06:45:56 mycroft Exp $ */
/*
@@ -64,9 +64,16 @@
#define PCI_EHCI_PORTWAKECAP 0x62 /* RW Port wake caps (opt) */
-/* Regs ar EECP + offset */
-#define PCI_EHCI_USBLEGSUP 0x00
-#define PCI_EHCI_USBLEGCTLSTS 0x04
+/* EHCI Extended Capabilities */
+#define EHCI_EC_LEGSUP 0x01
+
+#define EHCI_EECP_NEXT(x) (((x) >> 8) & 0xff)
+#define EHCI_EECP_ID(x) ((x) & 0xff)
+
+#define EHCI_LEGSUP_LEGSUP 0x01
+#define EHCI_LEGSUP_OSOWNED 0x01000000 /* OS owned semaphore */
+#define EHCI_LEGSUP_BIOSOWNED 0x00010000 /* BIOS owned semaphore */
+#define PCI_LEGSUP_USBLEGCTLSTS 0x04
/*** EHCI capability registers ***/
diff --git a/sys/dev/usb/ehcivar.h b/sys/dev/usb/ehcivar.h
index cc4d3fc1c93..bdfde1445b0 100644
--- a/sys/dev/usb/ehcivar.h
+++ b/sys/dev/usb/ehcivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehcivar.h,v 1.6 2004/10/20 12:45:31 dlg Exp $ */
+/* $OpenBSD: ehcivar.h,v 1.7 2004/12/29 01:52:27 dlg Exp $ */
/* $NetBSD: ehcivar.h,v 1.12 2001/12/31 12:16:57 augustss Exp $ */
/*
@@ -154,3 +154,4 @@ usbd_status ehci_init(ehci_softc_t *);
int ehci_intr(void *);
int ehci_detach(ehci_softc_t *, int);
int ehci_activate(device_ptr_t, enum devact);
+void ehci_shutdown(void *);