summaryrefslogtreecommitdiff
path: root/sys/arch/macppc
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2008-05-03 22:44:57 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2008-05-03 22:44:57 +0000
commit36fc7f0644092574a9ce2540ddf97cbffd75da71 (patch)
treeb375c919df9860aef9c2da0a0de4b15b349f2f8d /sys/arch/macppc
parent77a35ce083d5e10ea7be58a1b2c4cae633079ba2 (diff)
Rework the interrupt calculation masks, a bit easier to follow (not so wrong).
Diffstat (limited to 'sys/arch/macppc')
-rw-r--r--sys/arch/macppc/dev/openpic.c100
1 files changed, 40 insertions, 60 deletions
diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c
index f20a62f0472..ca517a77718 100644
--- a/sys/arch/macppc/dev/openpic.c
+++ b/sys/arch/macppc/dev/openpic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: openpic.c,v 1.43 2008/05/01 08:25:32 kettenis Exp $ */
+/* $OpenBSD: openpic.c,v 1.44 2008/05/03 22:44:56 drahn Exp $ */
/*-
* Copyright (c) 1995 Per Fogelstrom
@@ -58,7 +58,7 @@
#define ICU_LEN 128
#define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
-int o_intrtype[ICU_LEN], o_intrmask[ICU_LEN], o_intrlevel[ICU_LEN];
+int o_intrtype[ICU_LEN], o_intrmaxlvl[ICU_LEN];
struct intrhand *o_intrhand[ICU_LEN] = { 0 };
int o_hwirq[ICU_LEN], o_virq[ICU_LEN];
unsigned int imen_o = 0xffffffff;
@@ -66,7 +66,7 @@ int o_virq_max;
static int fakeintr(void *);
static char *intr_typename(int type);
-static void intr_calculatemasks(void);
+void openpic_calc_mask(void);
static __inline int cntlzw(int x);
static int mapirq(int irq);
int openpic_prog_button(void *arg);
@@ -274,7 +274,7 @@ printf("vI %d ", irq);
fakehand.ih_level = level;
*p = &fakehand;
- intr_calculatemasks();
+ openpic_calc_mask();
/*
* Poke the real handler in now.
@@ -318,7 +318,7 @@ openpic_intr_disestablish(void *lcp, void *arg)
evcount_detach(&ih->ih_count);
free((void *)ih, M_DEVBUF);
- intr_calculatemasks();
+ openpic_calc_mask();
if (o_intrhand[irq] == NULL)
o_intrtype[irq] = IST_NONE;
@@ -352,68 +352,48 @@ intr_typename(int type)
* would be faster, but the code would be nastier, and we don't expect this to
* happen very much anyway.
*/
-static void
-intr_calculatemasks()
+
+void
+openpic_calc_mask()
{
- int irq, level;
- struct intrhand *q;
+ int irq;
+ struct intrhand *ih;
+ int i;
+ int imen_n = 0;
- /* First, figure out which levels each IRQ uses. */
for (irq = 0; irq < ICU_LEN; irq++) {
- register int levels = 0;
- for (q = o_intrhand[irq]; q; q = q->ih_next)
- levels |= 1 << q->ih_level;
- o_intrlevel[irq] = levels;
- }
-
- /* Then figure out which IRQs use each level. */
- for (level = IPL_NONE; level < IPL_NUM; level++) {
- register int irqs = 0;
- for (irq = 0; irq < ICU_LEN; irq++)
- if (o_intrlevel[irq] & (1 << level))
- irqs |= 1 << irq;
- imask[level] = irqs | SINT_MASK;
- }
-
- /*
- * There are tty, network and disk drivers that use free() at interrupt
- * time, so vm > (tty | net | bio).
- *
- * Enforce a hierarchy that gives slow devices a better chance at not
- * dropping data.
- */
- imask[IPL_NET] |= imask[IPL_BIO];
- imask[IPL_TTY] |= imask[IPL_NET];
- imask[IPL_VM] |= imask[IPL_TTY];
- imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK;
+ int max = IPL_NONE;
+ int min = IPL_HIGH;
+ if (o_virq[irq] != 0) {
+ for (ih = o_intrhand[o_virq[irq]]; ih;
+ ih = ih->ih_next) {
+ if (ih->ih_level > max)
+ max = ih->ih_level;
+ if (ih->ih_level < min)
+ min = ih->ih_level;
+ }
+ }
- /*
- * These are pseudo-levels.
- */
- imask[IPL_NONE] = 0x00000000;
- imask[IPL_HIGH] = 0xffffffff;
+ o_intrmaxlvl[irq] = max;
- /* And eventually calculate the complete masks. */
- for (irq = 0; irq < ICU_LEN; irq++) {
- register int irqs = 1 << irq;
- for (q = o_intrhand[irq]; q; q = q->ih_next)
- irqs |= imask[q->ih_level];
- o_intrmask[irq] = irqs | SINT_MASK;
- }
+ if (max == IPL_NONE)
+ min = IPL_NONE; /* Interrupt not enabled */
- /* Lastly, determine which IRQs are actually in use. */
- {
- register int irqs = 0;
- for (irq = 0; irq < ICU_LEN; irq++) {
- if (o_intrhand[irq]) {
- irqs |= 1 << irq;
- openpic_enable_irq(o_hwirq[irq]);
- } else {
- openpic_disable_irq(o_hwirq[irq]);
- }
+ if (o_virq[irq] != 0) {
+ /* Enable (dont mask) interrupts at lower levels */
+ for (i = IPL_NONE; i < min; i++)
+ imask[i] &= ~(1 << o_virq[irq]);
+ for (; i <= IPL_HIGH; i++)
+ imask[i] |= (1 << o_virq[irq]);
+ imen_n |= (1 << o_virq[irq]);
}
- imen_o = ~irqs;
}
+ for (i = IPL_NONE; i <= IPL_HIGH; i++) {
+ if (i > IPL_NONE)
+ imask[i] |= SINT_MASK;
+ }
+ imask[IPL_HIGH] = 0xffffffff;
+ imen_o = ~imen_n;
}
/*
@@ -673,7 +653,7 @@ ext_intr_openpic()
} else {
openpic_disable_irq(realirq);
openpic_eoi(ci->ci_cpuid);
- ocpl = splraise(o_intrmask[irq]);
+ ocpl = splraise(imask[o_intrmaxlvl[realirq]]);
ih = o_intrhand[irq];
while (ih) {