diff options
author | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2007-03-18 06:08:25 +0000 |
---|---|---|
committer | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2007-03-18 06:08:25 +0000 |
commit | 112100be1d15b3241b1e8acf05932b12c18880e6 (patch) | |
tree | 4ed2b7de8afa2f4ef56b68241325f6763653e45a /sys | |
parent | a4aa20bbe39a4ed79d63cfde14fc8c13f34abe59 (diff) |
Perform legacy emulation handover for USB1 companion controllers immediately
but defer the remainder of their initialisation until after the other devices
on their PCI bus have attached. This ensures that any USB2 controller has also
completed its initialisation before we start to initialise the USB1 parts.
This minimises the chance that a nasty SMM implementation will trash the USB1
controller's config when it performs legacy emulation handover of the USB2 part.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/ohci_pci.c | 58 | ||||
-rw-r--r-- | sys/dev/pci/uhci_pci.c | 29 | ||||
-rw-r--r-- | sys/dev/usb/ohci.c | 28 |
3 files changed, 89 insertions, 26 deletions
diff --git a/sys/dev/pci/ohci_pci.c b/sys/dev/pci/ohci_pci.c index 67751c585c8..7c3f3507b23 100644 --- a/sys/dev/pci/ohci_pci.c +++ b/sys/dev/pci/ohci_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ohci_pci.c,v 1.29 2006/05/22 16:09:21 dlg Exp $ */ +/* $OpenBSD: ohci_pci.c,v 1.30 2007/03/18 06:08:24 pascoe Exp $ */ /* $NetBSD: ohci_pci.c,v 1.23 2002/10/02 16:51:47 thorpej Exp $ */ /* @@ -64,8 +64,17 @@ #include <dev/usb/ohcireg.h> #include <dev/usb/ohcivar.h> +#ifdef OHCI_DEBUG +#define DPRINTF(x) do { if (ohcidebug) logprintf x; } while (0) +extern int ohcidebug; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + int ohci_pci_match(struct device *, void *, void *); void ohci_pci_attach(struct device *, struct device *, void *); +void ohci_pci_attach_deferred(struct device *); int ohci_pci_detach(struct device *, int); struct ohci_pci_softc { @@ -100,10 +109,10 @@ ohci_pci_attach(struct device *parent, struct device *self, void *aux) pci_chipset_tag_t pc = pa->pa_pc; char const *intrstr; pci_intr_handle_t ih; - usbd_status r; - int s; + int s, i; const char *vendor; char *devname = sc->sc.sc_bus.bdev.dv_xname; + u_int32_t ctl, sts; /* Map I/O registers */ if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0, @@ -158,6 +167,49 @@ ohci_pci_attach(struct device *parent, struct device *self, void *aux) else snprintf(sc->sc.sc_vendor, sizeof (sc->sc.sc_vendor), "vendor 0x%04x", PCI_VENDOR(pa->pa_id)); + + /* Ignore interrupts for now */ + sc->sc.sc_dying = 1; + + /* Perform legacy handover if required. */ + ctl = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OHCI_CONTROL); + if (ctl & OHCI_IR) { + /* SMM active, request change */ + DPRINTF(("ohci_init: SMM active, request owner change\n")); + if ((sc->sc.sc_intre & (OHCI_OC | OHCI_MIE)) == + (OHCI_OC | OHCI_MIE)) + bus_space_write_4(sc->sc.iot, sc->sc.ioh, + OHCI_INTERRUPT_ENABLE, OHCI_MIE); + sts = bus_space_read_4(sc->sc.iot, sc->sc.ioh, + OHCI_COMMAND_STATUS); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_COMMAND_STATUS, + sts | OHCI_OCR); + for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { + usb_delay_ms(&sc->sc.sc_bus, 1); + ctl = bus_space_read_4(sc->sc.iot, sc->sc.ioh, + OHCI_CONTROL); + } + bus_space_write_4(sc->sc.iot, sc->sc.ioh, + OHCI_INTERRUPT_DISABLE, OHCI_MIE); + } + + config_defer(self, ohci_pci_attach_deferred); + + splx(s); + + return; +} + +void +ohci_pci_attach_deferred(struct device *self) +{ + struct ohci_pci_softc *sc = (struct ohci_pci_softc *)self; + usbd_status r; + int s; + + s = splusb(); + + sc->sc.sc_dying = 1; r = ohci_init(&sc->sc); if (r != USBD_NORMAL_COMPLETION) { diff --git a/sys/dev/pci/uhci_pci.c b/sys/dev/pci/uhci_pci.c index 2d03e1ab30a..f609b453af9 100644 --- a/sys/dev/pci/uhci_pci.c +++ b/sys/dev/pci/uhci_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uhci_pci.c,v 1.22 2006/08/25 04:17:00 pascoe Exp $ */ +/* $OpenBSD: uhci_pci.c,v 1.23 2007/03/18 06:08:24 pascoe Exp $ */ /* $NetBSD: uhci_pci.c,v 1.24 2002/10/02 16:51:58 thorpej Exp $ */ /* @@ -59,6 +59,7 @@ int uhci_pci_match(struct device *, void *, void *); void uhci_pci_attach(struct device *, struct device *, void *); +void uhci_pci_attach_deferred(struct device *); int uhci_pci_detach(struct device *, int); struct uhci_pci_softc { @@ -97,7 +98,6 @@ uhci_pci_attach(struct device *parent, struct device *self, void *aux) pci_intr_handle_t ih; const char *vendor; char *devname = sc->sc.sc_bus.bdev.dv_xname; - usbd_status r; int s; #if defined(__NetBSD__) @@ -172,7 +172,32 @@ uhci_pci_attach(struct device *parent, struct device *self, void *aux) else snprintf(sc->sc.sc_vendor, sizeof (sc->sc.sc_vendor), "vendor 0x%04x", PCI_VENDOR(pa->pa_id)); + + config_defer(self, uhci_pci_attach_deferred); + + /* Ignore interrupts for now */ + sc->sc.sc_dying = 1; + + splx(s); + + return; + +unmap_ret: + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + splx(s); +} + +void +uhci_pci_attach_deferred(struct device *self) +{ + struct uhci_pci_softc *sc = (struct uhci_pci_softc *)self; + char *devname = sc->sc.sc_bus.bdev.dv_xname; + usbd_status r; + int s; + + s = splhardusb(); + sc->sc.sc_dying = 0; r = uhci_init(&sc->sc); if (r != USBD_NORMAL_COMPLETION) { printf("%s: init failed, error=%d\n", devname, r); diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c index e5f1f55e477..4e3c6bc2a2f 100644 --- a/sys/dev/usb/ohci.c +++ b/sys/dev/usb/ohci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ohci.c,v 1.73 2006/06/23 06:27:11 miod Exp $ */ +/* $OpenBSD: ohci.c,v 1.74 2007/03/18 06:08:24 pascoe Exp $ */ /* $NetBSD: ohci.c,v 1.139 2003/02/22 05:24:16 tsutsui Exp $ */ /* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */ @@ -616,7 +616,7 @@ ohci_init(ohci_softc_t *sc) ohci_soft_ed_t *sed, *psed; usbd_status err; int i; - u_int32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca, descb; + u_int32_t ctl, rwc, ival, hcr, fm, per, rev, desca, descb; DPRINTF(("ohci_init: start\n")); printf(","); @@ -718,26 +718,12 @@ ohci_init(ohci_softc_t *sc) desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); - /* Determine in what context we are running. */ + /* SMM handover performed by the PCI code didn't work? */ if (ctl & OHCI_IR) { - /* SMM active, request change */ - DPRINTF(("ohci_init: SMM active, request owner change\n")); - if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == - (OHCI_OC | OHCI_MIE)) - OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); - s = OREAD4(sc, OHCI_COMMAND_STATUS); - OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); - for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { - usb_delay_ms(&sc->sc_bus, 1); - ctl = OREAD4(sc, OHCI_CONTROL); - } - OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); - if (ctl & OHCI_IR) { - printf("%s: SMM does not respond, resetting\n", - USBDEVNAME(sc->sc_bus.bdev)); - OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); - goto reset; - } + printf("%s: SMM does not respond, resetting\n", + USBDEVNAME(sc->sc_bus.bdev)); + OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); + goto reset; #if 0 /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { |