diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2014-04-04 20:00:13 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2014-04-04 20:00:13 +0000 |
commit | 53ed39fb312cb6d46963e96a5b96f381786312d9 (patch) | |
tree | 21f6ff3f4688950f7c92431289ab9f0c06dafc79 /sys/arch/alpha/pci | |
parent | fd6f626f2e0b7a02615bb66916d4da45e51ae673 (diff) |
It seems that, when the on-board USB controller is an ALI M5237 USB and its
interrupt is routed through the ISA PIC, the interrupt is edge-triggered
(despite PCI interrupts being level-triggered).
Attempt to recognize this and correctly setup the PIC ELCR register to `edge'.
This allows ES40 systems (and maybe others, but apparently all the other alpha
systems with on-board M5237 correctly route its interrupt as a PCI interrupt)
to reliably boot multiuser without suffering from USB interrupt storms (this is
especially noticeable when using glass console which, unlike serial console,
does not trigger other interrupts to give other devices a chance to run).
However, this is not enough yet to allow for proper USB device usage; your
mileage may vary.
Tested by bluhm@ and me. Putting it early in the release cycle so that
regressions on other systems, if any, can hopefully get noticed soon enough.
Diffstat (limited to 'sys/arch/alpha/pci')
-rw-r--r-- | sys/arch/alpha/pci/sio_pic.c | 82 |
1 files changed, 48 insertions, 34 deletions
diff --git a/sys/arch/alpha/pci/sio_pic.c b/sys/arch/alpha/pci/sio_pic.c index df15d8f7264..2634b3787d6 100644 --- a/sys/arch/alpha/pci/sio_pic.c +++ b/sys/arch/alpha/pci/sio_pic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sio_pic.c,v 1.36 2014/02/18 19:37:33 miod Exp $ */ +/* $OpenBSD: sio_pic.c,v 1.37 2014/04/04 20:00:12 miod Exp $ */ /* $NetBSD: sio_pic.c,v 1.28 2000/06/06 03:10:13 thorpej Exp $ */ /*- @@ -116,6 +116,15 @@ u_int8_t initial_ocw1[2]; u_int8_t initial_elcr[2]; #endif +/* + * Overrides for ELCR settings. + * These are used on ES40 and similar systems suffering from a PCI USB HCI + * interrupt being routed through the ISA logic with actual logic to + * make it behave an edge-triggered interrupt, although PCI interrupts are + * supposed to be level-triggered. + */ +u_int8_t elcr_override[2] = { 0x00, 0x00 }; + void sio_setirqstat(int, int, int); int sio_intr_alloc(void *, int, int, int *); int sio_intr_check(void *, int, int); @@ -135,6 +144,9 @@ bus_space_handle_t sio_ioh_elcr; int i82378_setup_elcr() { + int device, maxndevs; + pcitag_t tag; + pcireg_t id; int rv; /* @@ -145,12 +157,30 @@ i82378_setup_elcr() rv = bus_space_map(sio_iot, 0x4d0, 2, 0, &sio_ioh_elcr); - if (rv == 0) { - sio_read_elcr = i82378_read_elcr; - sio_write_elcr = i82378_write_elcr; + if (rv != 0) + return 0; + + sio_read_elcr = i82378_read_elcr; + sio_write_elcr = i82378_write_elcr; + + /* + * Search PCI configuration space for an ALI M5237 USB controller + * on the first bus. + */ + + maxndevs = pci_bus_maxdevs(sio_pc, 0); + + for (device = 0; device < maxndevs; device++) { + tag = pci_make_tag(sio_pc, 0, device, 0); + id = pci_conf_read(sio_pc, tag, PCI_ID_REG); + + if (id == PCI_ID_CODE(PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5237)) { + elcr_override[10 / 8] |= 1 << (10 % 8); + break; + } } - return (rv); + return (0); } u_int8_t @@ -203,31 +233,13 @@ cy82c693_setup_elcr() tag = pci_make_tag(sio_pc, 0, device, 0); id = pci_conf_read(sio_pc, tag, PCI_ID_REG); - /* Invalid vendor ID value? */ - if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) - continue; - /* XXX Not invalid, but we've done this ~forever. */ - if (PCI_VENDOR(id) == 0) - continue; - - if (PCI_VENDOR(id) != PCI_VENDOR_CONTAQ || - PCI_PRODUCT(id) != PCI_PRODUCT_CONTAQ_82C693) - continue; - - /* - * Found one! - */ - -#if 0 - printf("cy82c693_setup_elcr: found 82C693 at device %d\n", - device); -#endif - - sio_cy82c693_handle = cy82c693_init(sio_iot); - sio_read_elcr = cy82c693_read_elcr; - sio_write_elcr = cy82c693_write_elcr; - - return (0); + if (id == + PCI_ID_CODE(PCI_VENDOR_CONTAQ, PCI_PRODUCT_CONTAQ_82C693)) { + sio_cy82c693_handle = cy82c693_init(sio_iot); + sio_read_elcr = cy82c693_read_elcr; + sio_write_elcr = cy82c693_write_elcr; + return (0); + } } /* @@ -300,13 +312,18 @@ sio_setirqstat(irq, enabled, type) ocw1[icu] |= 1 << bit; /* - * interrupt type select: set bit to get level-triggered. + * interrupt type select: set bit to get level-triggered... */ if (type == IST_LEVEL) elcr[icu] |= 1 << bit; else elcr[icu] &= ~(1 << bit); + /* + * ...unless we pretend to know better. + */ + elcr[icu] &= ~elcr_override[icu]; + #ifdef not_here /* see the init function... */ ocw1[0] &= ~0x04; /* always enable IRQ2 on first PIC */ @@ -325,9 +342,6 @@ sio_intr_setup(pc, iot) pci_chipset_tag_t pc; bus_space_tag_t iot; { -#ifdef notyet - char *cp; -#endif int i; sio_iot = iot; |