diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2015-08-15 20:06:22 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2015-08-15 20:06:22 +0000 |
commit | 1ab8cc9463b40d26eb4ef3290d06a53e5a8f944a (patch) | |
tree | 170f0714b70c8c13a8c21712a97416c079a4f30b | |
parent | d95f32241d81b910948257cadf9f2f9a3f40a4b0 (diff) |
If the SRM has explicitely set up some ISA interrupts level-triggered,
honour this setting and consider them level-triggered instead of `polarity
decided by the first driver to use it'.
Add explicit code to turn registration of edge-triggered interrupts 3 and 4
into level-triggered, if they were set up a level-triggered by the SRM.
Based upon a NetBSD diff which eventually got reverted in NetBSD. However,
it turns out this is necessary for the kernel to correctly run with serial
console on my Multia.
-rw-r--r-- | sys/arch/alpha/pci/sio_pic.c | 44 |
1 files changed, 34 insertions, 10 deletions
diff --git a/sys/arch/alpha/pci/sio_pic.c b/sys/arch/alpha/pci/sio_pic.c index 2634b3787d6..da79b09b04a 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.37 2014/04/04 20:00:12 miod Exp $ */ +/* $OpenBSD: sio_pic.c,v 1.38 2015/08/15 20:06:21 miod Exp $ */ /* $NetBSD: sio_pic.c,v 1.28 2000/06/06 03:10:13 thorpej Exp $ */ /*- @@ -107,14 +107,15 @@ static struct alpha_shared_intr *sio_intr; #define STRAY_MAX 5 #endif -#ifdef BROKEN_PROM_CONSOLE /* * If prom console is broken, must remember the initial interrupt * settings and enforce them. WHEE! */ u_int8_t initial_ocw1[2]; u_int8_t initial_elcr[2]; -#endif + +#define INITIALLY_LEVEL_TRIGGERED(irq) \ + ((initial_elcr[(irq) / 8] & (1 << ((irq) % 8))) != 0) /* * Overrides for ELCR settings. @@ -357,7 +358,6 @@ sio_intr_setup(pc, iot) if (sio_elcr_setup_funcs[i] == NULL) panic("sio_intr_setup: can't map ELCR"); -#ifdef BROKEN_PROM_CONSOLE /* * Remember the initial values, so we can restore them later. */ @@ -365,7 +365,6 @@ sio_intr_setup(pc, iot) initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1); initial_elcr[0] = (*sio_read_elcr)(0); /* XXX */ initial_elcr[1] = (*sio_read_elcr)(1); /* XXX */ -#endif sio_intr = alpha_shared_intr_alloc(ICU_LEN); @@ -384,6 +383,11 @@ sio_intr_setup(pc, iot) * IRQs 0, 1, 8, and 13 must always be * edge-triggered. */ +#ifdef DIAGNOSTIC + if (INITIALLY_LEVEL_TRIGGERED(i)) + printf("WARNING: PROM set irq %d" + " level-triggered\n", i); +#endif sio_setirqstat(i, 0, IST_EDGE); alpha_shared_intr_set_dfltsharetype(sio_intr, i, IST_EDGE); @@ -403,11 +407,14 @@ sio_intr_setup(pc, iot) default: /* * Otherwise, disable the IRQ and set its - * type to (effectively) "unknown." + * type to (effectively) "unknown", or "level" + * if it was set so by the PROM. */ - sio_setirqstat(i, 0, IST_NONE); + sio_setirqstat(i, 0, INITIALLY_LEVEL_TRIGGERED(i) ? + IST_LEVEL : IST_NONE); alpha_shared_intr_set_dfltsharetype(sio_intr, i, - IST_NONE); + INITIALLY_LEVEL_TRIGGERED(i) ? + IST_LEVEL : IST_NONE); specific_eoi(i); break; } @@ -436,7 +443,7 @@ sio_intr_string(v, irq) void *v; int irq; { - static char irqstr[12]; /* 8 + 2 + NULL + sanity */ + static char irqstr[12]; /* 8 + 2 + NUL + sanity */ if (irq == 0 || irq >= ICU_LEN || irq == 2) panic("sio_intr_string: bogus isa irq 0x%x", irq); @@ -467,6 +474,14 @@ sio_intr_establish(v, irq, type, level, fn, arg, name) if (irq >= ICU_LEN || type == IST_NONE) panic("sio_intr_establish: bogus irq or type"); + /* + * XXX This is a workaround to let com(4) attach on Multia + * XXX where its interrupts are actually level triggered. + */ + if (type == IST_EDGE && INITIALLY_LEVEL_TRIGGERED(irq) && + (irq == 3 || irq == 4)) + type = IST_LEVEL; + cookie = alpha_shared_intr_establish(sio_intr, irq, type, level, fn, arg, name); @@ -518,7 +533,8 @@ sio_intr_disestablish(v, cookie) break; default: - ist = IST_NONE; + ist = INITIALLY_LEVEL_TRIGGERED(irq) ? + IST_LEVEL : IST_NONE; break; } sio_setirqstat(irq, 0, ist); @@ -649,6 +665,14 @@ sio_intr_check(void *v, int irq, int type) if (type == IST_NONE) return (0); + /* + * XXX This is a workaround to let com(4) attach on Multia + * XXX where its interrupts are actually level triggered. + */ + if (type == IST_EDGE && INITIALLY_LEVEL_TRIGGERED(irq) && + (irq == 3 || irq == 4)) + type = IST_LEVEL; + switch (sio_intr[irq].intr_sharetype) { case IST_NONE: return (2); |