summaryrefslogtreecommitdiff
path: root/sys/arch/macppc
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2008-09-18 03:56:26 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2008-09-18 03:56:26 +0000
commitac9178859bad2dfb8a089ace0ca2594821702c01 (patch)
tree992557fe2a1c5c09d102dd4bca38f8ecffb6c1d8 /sys/arch/macppc
parent856abc40f5e309364d84e9e75693686f63551c07 (diff)
Redesign of the powerpc interrupt architecture, use true levels intead of
blocking specific interrupts. Needs signficant testing to prove that one remaining elusive bug has been squashed.
Diffstat (limited to 'sys/arch/macppc')
-rw-r--r--sys/arch/macppc/dev/macintr.c550
-rw-r--r--sys/arch/macppc/dev/openpic.c715
-rw-r--r--sys/arch/macppc/include/intr.h4
-rw-r--r--sys/arch/macppc/macppc/clock.c4
-rw-r--r--sys/arch/macppc/macppc/cpu.c4
-rw-r--r--sys/arch/macppc/macppc/genassym.cf3
-rw-r--r--sys/arch/macppc/macppc/machdep.c4
7 files changed, 554 insertions, 730 deletions
diff --git a/sys/arch/macppc/dev/macintr.c b/sys/arch/macppc/dev/macintr.c
index c0ca3e684f4..e327b99c2c1 100644
--- a/sys/arch/macppc/dev/macintr.c
+++ b/sys/arch/macppc/dev/macintr.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: macintr.c,v 1.33 2007/05/29 18:10:42 miod Exp $ */
+/* $OpenBSD: macintr.c,v 1.34 2008/09/18 03:56:25 drahn Exp $ */
/*-
+ * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org>
* Copyright (c) 1995 Per Fogelstrom
* Copyright (c) 1993, 1994 Charles M. Hannum.
* Copyright (c) 1990 The Regents of the University of California.
@@ -58,25 +59,17 @@
#define ICU_LEN 64
#define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
-int m_intrtype[ICU_LEN], m_intrmask[ICU_LEN], m_intrlevel[ICU_LEN];
-struct intrhand *m_intrhand[ICU_LEN];
-int m_hwirq[ICU_LEN], m_virq[64];
-unsigned int imen_m = 0xffffffff;
-int m_virq_max = 0;
-
-static int fakeintr(void *);
-static char *intr_typename(int type);
-static void intr_calculatemasks(void);
-static void enable_irq(int x);
-static __inline int cntlzw(int x);
-static int mapirq(int irq);
-static int read_irq(void);
-static void mac_intr_do_pending_int(void);
+int macintr_ienable_l[IPL_NUM], macintr_ienable_h[IPL_NUM];
+int macintr_pri_share[IPL_NUM];
-extern u_int32_t *heathrow_FCR;
+struct intrq macintr_handler[ICU_LEN];
+
+void macintr_calc_mask(void);
+void macintr_eoi(int irq);
+int macintr_read_irq(void);
+static void macintr_do_pending_int(void);
-#define HWIRQ_MAX 27
-#define HWIRQ_MASK 0x0fffffff
+extern u_int32_t *heathrow_FCR;
#define INT_STATE_REG0 (interrupt_reg + 0x20)
#define INT_ENABLE_REG0 (interrupt_reg + 0x24)
@@ -95,6 +88,8 @@ int macintr_match(struct device *parent, void *cf, void *aux);
void macintr_attach(struct device *, struct device *, void *);
void mac_do_pending_int(void);
void mac_ext_intr(void);
+void macintr_collect_preconf_intr(void);
+void macintr_setipl(int ipl);
struct cfattach macintr_ca = {
sizeof(struct macintr_softc),
@@ -140,31 +135,84 @@ intr_establish_t macintr_establish;
intr_disestablish_t macintr_disestablish;
extern intr_establish_t *mac_intr_establish_func;
extern intr_disestablish_t *mac_intr_disestablish_func;
-void macintr_collect_preconf_intr(void);
+
+ppc_splraise_t macintr_splraise;
+ppc_spllower_t macintr_spllower;
+ppc_splx_t macintr_splx;
+
+
+int
+macintr_splraise(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ newcpl = macintr_pri_share[newcpl];
+ int ocpl = ci->ci_cpl;
+ if (ocpl > newcpl)
+ newcpl = ocpl;
+
+ macintr_setipl(newcpl);
+
+ return ocpl;
+}
+
+int
+macintr_spllower(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ macintr_splx(newcpl);
+
+ return ocpl;
+}
+
+void
+macintr_splx(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+
+ macintr_setipl(newcpl);
+ if (ci->ci_ipending & ppc_smask[newcpl])
+ macintr_do_pending_int();
+}
void
macintr_attach(struct device *parent, struct device *self, void *aux)
{
+ struct cpu_info *ci = curcpu();
struct confargs *ca = aux;
extern intr_establish_t *intr_establish_func;
extern intr_disestablish_t *intr_disestablish_func;
+ struct intrq *iq;
+ int i;
interrupt_reg = (void *)mapiodev(ca->ca_baseaddr,0x100); /* XXX */
+ for (i = 0; i < ICU_LEN; i++) {
+ iq = &macintr_handler[i];
+ TAILQ_INIT(&iq->iq_list);
+ }
+ ppc_smask_init();
+
install_extint(mac_ext_intr);
- pending_int_f = mac_intr_do_pending_int;
+ pending_int_f = macintr_do_pending_int;
intr_establish_func = macintr_establish;
intr_disestablish_func = macintr_disestablish;
mac_intr_establish_func = macintr_establish;
mac_intr_disestablish_func = macintr_disestablish;
+ ppc_intr_func.raise = macintr_splraise;
+ ppc_intr_func.lower = macintr_spllower;
+ ppc_intr_func.x = macintr_splx;
+
+ ci->ci_iactive = 0;
+
macintr_collect_preconf_intr();
mac_intr_establish(parent, 0x14, IST_LEVEL, IPL_HIGH,
macintr_prog_button, (void *)0x14, "progbutton");
ppc_intr_enable(1);
-
printf("\n");
}
@@ -209,11 +257,19 @@ macintr_prog_button (void *arg)
return 1;
}
-static int
-fakeintr(void *arg)
+void
+macintr_setipl(int ipl)
{
+ struct cpu_info *ci = curcpu();
+ int s;
+ s = ppc_intr_disable();
+ ci->ci_cpl = ipl;
+ if (heathrow_FCR)
+ out32rb(INT_ENABLE_REG1,
+ macintr_ienable_h[macintr_pri_share[ipl]]);
- return 0;
+ out32rb(INT_ENABLE_REG0, macintr_ienable_l[macintr_pri_share[ipl]]);
+ ppc_intr_enable(s);
}
/*
@@ -223,19 +279,13 @@ void *
macintr_establish(void * lcv, int irq, int type, int level,
int (*ih_fun)(void *), void *ih_arg, char *name)
{
- struct intrhand **p, *q, *ih;
- static struct intrhand fakehand;
-
- fakehand.ih_next = NULL;
- fakehand.ih_fun = fakeintr;
+ struct cpu_info *ci = curcpu();
+ struct intrq *iq;
+ struct intrhand *ih;
+ int s;
#if 0
-printf("macintr_establish, hI %d L %d ", irq, type);
-printf("addr reg0 %x\n", INT_STATE_REG0);
-#endif
- irq = mapirq(irq);
-#if 0
-printf("vI %d ", irq);
+printf("macintr_establish, hI %d L %d %s", irq, level, ppc_intr_typename(type));
#endif
/* no point in sleeping unless someone can free memory. */
@@ -246,51 +296,40 @@ printf("vI %d ", irq);
if (!LEGAL_IRQ(irq) || type == IST_NONE)
panic("intr_establish: bogus irq or type");
- switch (m_intrtype[irq]) {
+ iq = &macintr_handler[irq];
+ switch (iq->iq_ist) {
case IST_NONE:
- m_intrtype[irq] = type;
+ iq->iq_ist = type;
break;
case IST_EDGE:
case IST_LEVEL:
- if (type == m_intrtype[irq])
+ if (type == iq->iq_ist)
break;
case IST_PULSE:
if (type != IST_NONE)
panic("intr_establish: can't share %s with %s",
- intr_typename(m_intrtype[irq]),
- intr_typename(type));
+ ppc_intr_typename(iq->iq_ist),
+ ppc_intr_typename(type));
break;
}
- /*
- * Figure out where to put the handler.
- * This is O(N^2), but we want to preserve the order, and N is
- * generally small.
- */
- for (p = &m_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
- ;
-
- /*
- * Actually install a fake handler momentarily, since we might be doing
- * this with interrupts enabled and DON'T WANt the real routine called
- * until masking is set up.
- */
- fakehand.ih_level = level;
- *p = &fakehand;
-
- intr_calculatemasks();
-
- /*
- * Poke the real handler in now.
- */
ih->ih_fun = ih_fun;
ih->ih_arg = ih_arg;
- ih->ih_next = NULL;
ih->ih_level = level;
ih->ih_irq = irq;
- evcount_attach(&ih->ih_count, name, (void *)&m_hwirq[irq],
+ evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
&evcount_intr);
- *p = ih;
+
+ /*
+ * Append handler to end of list
+ */
+ s = ppc_intr_disable();
+
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
+ macintr_calc_mask();
+
+ macintr_setipl(ci->ci_cpl);
+ ppc_intr_enable(s);
return (ih);
}
@@ -301,195 +340,93 @@ printf("vI %d ", irq);
void
macintr_disestablish(void *lcp, void *arg)
{
+ struct cpu_info *ci = curcpu();
struct intrhand *ih = arg;
int irq = ih->ih_irq;
- struct intrhand **p, *q;
+ int s;
+ struct intrq *iq;
if (!LEGAL_IRQ(irq))
panic("intr_disestablish: bogus irq");
/*
* Remove the handler from the chain.
- * This is O(n^2), too.
*/
- for (p = &m_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
- ;
- if (q)
- *p = q->ih_next;
- else
- panic("intr_disestablish: handler not registered");
- evcount_detach(&ih->ih_count);
- free((void *)ih, M_DEVBUF);
+ iq = &macintr_handler[irq];
+ s = ppc_intr_disable();
- intr_calculatemasks();
+ TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
+ macintr_calc_mask();
- if (m_intrhand[irq] == NULL)
- m_intrtype[irq] = IST_NONE;
-}
+ macintr_setipl(ci->ci_cpl);
+ ppc_intr_enable(s);
+ evcount_detach(&ih->ih_count);
+ free((void *)ih, M_DEVBUF);
-static char *
-intr_typename(int type)
-{
- switch (type) {
- case IST_NONE :
- return ("none");
- case IST_PULSE:
- return ("pulsed");
- case IST_EDGE:
- return ("edge-triggered");
- case IST_LEVEL:
- return ("level-triggered");
- default:
- panic("intr_typename: invalid type %d", type);
-#if 1 /* XXX */
- return ("unknown");
-#endif
- }
+ if (TAILQ_EMPTY(&iq->iq_list))
+ iq->iq_ist = IST_NONE;
}
+
/*
* Recalculate the interrupt masks from scratch.
* We could code special registry and deregistry versions of this function that
* 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
+macintr_calc_mask()
{
- int irq, level;
- struct intrhand *q;
-
- /* First, figure out which levels each IRQ uses. */
- for (irq = 0; irq < ICU_LEN; irq++) {
- register int levels = 0;
- for (q = m_intrhand[irq]; q; q = q->ih_next)
- levels |= 1 << q->ih_level;
- m_intrlevel[irq] = levels;
- }
+ int irq;
+ struct intrhand *ih;
+ int i;
- /* 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 (m_intrlevel[irq] & (1 << level))
- irqs |= 1 << irq;
- imask[level] = irqs | SINT_MASK;
+ for (i = IPL_NONE; i < IPL_NUM; i++) {
+ macintr_pri_share[i] = i;
}
- /*
- * 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;
-
- /*
- * These are pseudo-levels.
- */
- imask[IPL_NONE] = 0x00000000;
- imask[IPL_HIGH] = 0xffffffff;
-
- /* And eventually calculate the complete masks. */
for (irq = 0; irq < ICU_LEN; irq++) {
- register int irqs = 1 << irq;
- for (q = m_intrhand[irq]; q; q = q->ih_next)
- irqs |= imask[q->ih_level];
- m_intrmask[irq] = irqs | SINT_MASK;
- }
-
- /* Lastly, determine which IRQs are actually in use. */
- {
- register int irqs = 0;
- for (irq = 0; irq < ICU_LEN; irq++) {
- if (m_intrhand[irq])
- irqs |= 1 << irq;
+ int maxipl = IPL_NONE;
+ int minipl = IPL_HIGH;
+ struct intrq *iq = &macintr_handler[irq];
+
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ if (ih->ih_level > maxipl)
+ maxipl = ih->ih_level;
+ if (ih->ih_level < minipl)
+ minipl = ih->ih_level;
}
- imen_m = ~irqs;
- enable_irq(~imen_m);
- }
-}
-static void
-enable_irq(int x)
-{
- int state0, state1, v;
- int irq;
-
- x &= HWIRQ_MASK; /* XXX Higher bits are software interrupts. */
-
- state0 = state1 = 0;
- while (x) {
- v = 31 - cntlzw(x);
- irq = m_hwirq[v];
- if (irq < 32)
- state0 |= 1 << irq;
- else
- state1 |= 1 << (irq - 32);
-
- x &= ~(1 << v);
- }
-
- if (heathrow_FCR)
- out32rb(INT_ENABLE_REG1, state1);
-
- out32rb(INT_ENABLE_REG0, state0);
-}
-int m_virq_inited = 0;
+ iq->iq_ipl = maxipl;
-/*
- * Map 64 irqs into 32 (bits).
- */
-static int
-mapirq(int irq)
-{
- int v;
- int i;
+ if (maxipl == IPL_NONE) {
+ minipl = IPL_NONE; /* Interrupt not enabled */
+ } else {
+ for (i = minipl; i <= maxipl; i++)
+ macintr_pri_share[i] = i;
+ }
- if (m_virq_inited == 0) {
- m_virq_max = 0;
- for (i = 0; i < ICU_LEN; i++) {
- m_virq[i] = 0;
+ /* Enable interrupts at lower levels */
+
+ if (irq < 32) {
+ for (i = IPL_NONE; i < minipl; i++)
+ macintr_ienable_l[i] |= (1 << irq);
+ for (; i <= IPL_HIGH; i++)
+ macintr_ienable_l[i] &= ~(1 << irq);
+ } else {
+ for (i = IPL_NONE; i < minipl; i++)
+ macintr_ienable_h[i] |= (1 << (irq-32));
+ for (; i <= IPL_HIGH; i++)
+ macintr_ienable_h[i] &= ~(1 << (irq-32));
}
- m_virq_inited = 1;
}
- /* irq in table already? */
- if (m_virq[irq] != 0)
- return m_virq[irq];
-
- if (irq < 0 || irq >= 64)
- panic("invalid irq %d", irq);
- m_virq_max++;
- v = m_virq_max;
- if (v > HWIRQ_MAX)
- panic("virq overflow");
-
- m_hwirq[v] = irq;
- m_virq[irq] = v;
#if 0
-printf("\nmapirq %x to %x\n", irq, v);
+ for (i = 0; i < IPL_NUM; i++)
+ printf("imask[%d] %x %x\n", i, macintr_ienable_l[i],
+ macintr_ienable_h[i]);
#endif
-
- return v;
-}
-
-/*
- * Count leading zeros.
- */
-static __inline int
-cntlzw(int x)
-{
- int a;
-
- __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
-
- return a;
}
/*
@@ -499,143 +436,136 @@ void
mac_ext_intr()
{
int irq = 0;
- int o_imen, r_imen;
int pcpl;
struct cpu_info *ci = curcpu();
+ struct intrq *iq;
struct intrhand *ih;
- volatile unsigned long int_state;
pcpl = ci->ci_cpl; /* Turn off all */
- int_state = read_irq();
- if (int_state == 0)
- goto out;
-
-start:
- irq = 31 - cntlzw(int_state);
-
- o_imen = imen_m;
- r_imen = 1 << irq;
+ irq = macintr_read_irq();
+ while (irq != 255) {
+ iq = &macintr_handler[irq];
+ macintr_setipl(iq->iq_ipl);
- if ((ci->ci_cpl & r_imen) != 0) {
- /* Masked! Mark this as pending. */
- ci->ci_ipending |= r_imen;
- imen_m |= r_imen;
- enable_irq(~imen_m);
- } else {
- splraise(m_intrmask[irq]);
-
- ih = m_intrhand[irq];
- while (ih) {
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ ppc_intr_enable(1);
if ((*ih->ih_fun)(ih->ih_arg))
ih->ih_count.ec_count++;
- ih = ih->ih_next;
+ (void)ppc_intr_disable();
}
+ macintr_eoi(irq);
+ macintr_setipl(pcpl);
uvmexp.intrs++;
+
+ irq = macintr_read_irq();
}
- int_state &= ~r_imen;
- if (int_state)
- goto start;
-out:
+ ppc_intr_enable(1);
splx(pcpl); /* Process pendings. */
}
void
-mac_intr_do_pending_int()
+macintr_do_pending_int()
{
struct cpu_info *ci = curcpu();
- struct intrhand *ih;
- int irq;
- int pcpl;
- int hwpend;
- int s;
-
- if (ci->ci_iactive)
- return;
-
- ci->ci_iactive = 1;
- pcpl = splhigh(); /* Turn off all */
+ int pcpl = ci->ci_cpl; /* XXX */
+ int s, s2;
s = ppc_intr_disable();
-
- hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */
- imen_m &= ~hwpend;
- enable_irq(~imen_m);
- hwpend &= HWIRQ_MASK;
- while (hwpend) {
- irq = 31 - cntlzw(hwpend);
- hwpend &= ~(1L << irq);
- ih = m_intrhand[irq];
- while(ih) {
- if ((*ih->ih_fun)(ih->ih_arg))
- ih->ih_count.ec_count++;
- ih = ih->ih_next;
- }
+ if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) {
+ ppc_intr_enable(s);
+ return;
}
-
- /*out32rb(INT_ENABLE_REG, ~imen_m);*/
+ atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
do {
- if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) {
- ci->ci_ipending &= ~SINT_CLOCK;
- softclock();
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && (pcpl < IPL_SOFTTTY)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
+ s2 = ci->ci_cpl;
+ ci->ci_cpl = IPL_SOFTTTY;
+ ppc_intr_enable(1);
+ KERNEL_LOCK();
+ softtty();
+ KERNEL_UNLOCK();
+ ppc_intr_disable();
+ ci->ci_cpl = pcpl;
+ continue;
}
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && (pcpl < IPL_SOFTNET)) {
extern int netisr;
int pisr;
- ci->ci_ipending &= ~SINT_NET;
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
while ((pisr = netisr) != 0) {
atomic_clearbits_int(&netisr, pisr);
+ ci->ci_cpl = IPL_SOFTNET;
+ ppc_intr_enable(1);
+ KERNEL_LOCK();
softnet(pisr);
+ KERNEL_UNLOCK();
+ ppc_intr_disable();
+ ci->ci_cpl = pcpl;
}
+ continue;
}
- if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
- ci->ci_ipending &= ~SINT_TTY;
- softtty();
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && (pcpl < IPL_SOFTCLOCK)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
+ ci->ci_cpl = IPL_SOFTCLOCK;
+ ppc_intr_enable(1);
+ KERNEL_LOCK();
+ softclock();
+ KERNEL_UNLOCK();
+ ppc_intr_disable();
+ ci->ci_cpl = pcpl;
+ continue;
}
- } while ((ci->ci_ipending & SINT_MASK) & ~pcpl);
- ci->ci_ipending &= pcpl;
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
- ppc_intr_enable(s);
- ci->ci_iactive = 0;
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
+ macintr_setipl(pcpl);
+ atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
}
-static int
-read_irq()
+void
+macintr_eoi(int irq)
{
- int rv = 0;
- int state0, state1, p;
- int state0save, state1save;
+ u_int32_t state0, state1;
- state0 = in32rb(INT_STATE_REG0);
- if (state0)
+ if (irq < 32) {
+ state0 = 1 << irq;
out32rb(INT_CLEAR_REG0, state0);
- state0save = state0;
- while (state0) {
- p = 31 - cntlzw(state0);
- rv |= 1 << m_virq[p];
- state0 &= ~(1 << p);
+ } else {
+ if (heathrow_FCR) { /* has heathrow? */
+ state1 = 1 << (irq - 32);
+ out32rb(INT_CLEAR_REG1, state1);
+ }
}
+}
+
+int
+macintr_read_irq()
+{
+ struct cpu_info *ci = curcpu();
+ u_int32_t state0, state1, irq_mask;
+ int ipl, irq;
+
+ state0 = in32rb(INT_STATE_REG0);
if (heathrow_FCR) /* has heathrow? */
state1 = in32rb(INT_STATE_REG1);
else
state1 = 0;
- if (state1)
- out32rb(INT_CLEAR_REG1, state1);
- state1save = state1;
- while (state1) {
- p = 31 - cntlzw(state1);
- rv |= 1 << m_virq[p + 32];
- state1 &= ~(1 << p);
+ for (ipl = IPL_HIGH; ipl >= ci->ci_cpl; ipl --) {
+ irq_mask = state0 & macintr_ienable_l[ipl];
+ if (irq_mask) {
+ irq = ffs(irq_mask) - 1;
+ return irq;
+ }
+ irq_mask = state1 & macintr_ienable_h[ipl];
+ if (irq_mask) {
+ irq = ffs(irq_mask) + 31;
+ return irq;
+ }
}
-#if 0
-printf("mac_intr int_stat 0:%x 1:%x\n", state0save, state1save);
-#endif
-
- /* 1 << 0 is invalid. */
- return rv & ~1;
+ return 255;
}
diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c
index a7038df1b34..63fd8e9e3b3 100644
--- a/sys/arch/macppc/dev/openpic.c
+++ b/sys/arch/macppc/dev/openpic.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: openpic.c,v 1.48 2008/09/16 04:20:42 drahn Exp $ */
+/* $OpenBSD: openpic.c,v 1.49 2008/09/18 03:56:25 drahn Exp $ */
/*-
+ * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org>
* Copyright (c) 1995 Per Fogelstrom
* Copyright (c) 1993, 1994 Charles M. Hannum.
* Copyright (c) 1990 The Regents of the University of California.
@@ -56,23 +57,19 @@
#include <dev/ofw/openfirm.h>
#define ICU_LEN 128
+int openpic_numirq = ICU_LEN;
#define LEGAL_IRQ(x) ((x >= 0) && (x < 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];
-int o_virq_max;
+int openpic_pri_share[IPL_NUM];
+
+struct intrq openpic_handler[ICU_LEN];
-static int fakeintr(void *);
-static char *intr_typename(int type);
void openpic_calc_mask(void);
-static __inline int cntlzw(int x);
-static int mapirq(int irq);
int openpic_prog_button(void *arg);
-void openpic_enable_irq_mask(int irq_mask);
-#define HWIRQ_MAX 27
-#define HWIRQ_MASK 0x0fffffff
+ppc_splraise_t openpic_splraise;
+ppc_spllower_t openpic_spllower;
+ppc_splx_t openpic_splx;
/* IRQ vector used for inter-processor interrupts. */
#define IPI_VECTOR_NOP 64
@@ -83,17 +80,30 @@ static struct evcount ipi_nop[PPC_MAXPROCS];
static int ipi_nopirq = IPI_VECTOR_NOP;
static int ipi_ddbirq = IPI_VECTOR_DDB;
#endif
+struct evcount openpic_spurious;
+int openpic_spurious_irq = 255;
-static __inline u_int openpic_read(int);
-static __inline void openpic_write(int, u_int);
-void openpic_set_enable_irq(int, int);
-void openpic_enable_irq(int);
-void openpic_disable_irq(int);
-void openpic_init(void);
-void openpic_set_priority(int, int);
+void openpic_enable_irq(int, int);
+void openpic_disable_irq(int);
+void openpic_init(void);
+void openpic_set_priority(int);
void openpic_ipi_ddb(void);
-static __inline int openpic_read_irq(int);
-static __inline void openpic_eoi(int);
+
+typedef void (void_f) (void);
+extern void_f *pending_int_f;
+
+vaddr_t openpic_base;
+void * openpic_intr_establish( void * lcv, int irq, int type, int level,
+ int (*ih_fun)(void *), void *ih_arg, char *name);
+void openpic_intr_disestablish( void *lcp, void *arg);
+void openpic_collect_preconf_intr(void);
+int openpic_big_endian;
+#ifdef MULTIPROCESSOR
+intr_send_ipi_t openpic_send_ipi;
+#endif
+
+u_int openpic_read(int reg);
+void openpic_write(int reg, u_int val);
struct openpic_softc {
struct device sc_dev;
@@ -101,9 +111,9 @@ struct openpic_softc {
int openpic_match(struct device *parent, void *cf, void *aux);
void openpic_attach(struct device *, struct device *, void *);
-void openpic_do_pending_int(void);
+void openpic_do_pending_int(int pcpl);
void openpic_collect_preconf_intr(void);
-void ext_intr_openpic(void);
+void openpic_ext_intr(void);
struct cfattach openpic_ca = {
sizeof(struct openpic_softc),
@@ -115,6 +125,42 @@ struct cfdriver openpic_cd = {
NULL, "openpic", DV_DULL
};
+u_int
+openpic_read(int reg)
+{
+ char *addr = (void *)(openpic_base + reg);
+
+ asm volatile("eieio");
+ if (openpic_big_endian)
+ return in32(addr);
+ else
+ return in32rb(addr);
+}
+
+void
+openpic_write(int reg, u_int val)
+{
+ char *addr = (void *)(openpic_base + reg);
+
+ if (openpic_big_endian)
+ out32(addr, val);
+ else
+ out32rb(addr, val);
+ asm volatile("eieio");
+}
+
+static inline int
+openpic_read_irq(int cpu)
+{
+ return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
+}
+
+static inline void
+openpic_eoi(int cpu)
+{
+ openpic_write(OPENPIC_EOI(cpu), 0);
+}
+
int
openpic_match(struct device *parent, void *cf, void *aux)
{
@@ -142,22 +188,10 @@ openpic_match(struct device *parent, void *cf, void *aux)
return 1;
}
-typedef void (void_f) (void);
-extern void_f *pending_int_f;
-
-vaddr_t openpic_base;
-void * openpic_intr_establish( void * lcv, int irq, int type, int level,
- int (*ih_fun)(void *), void *ih_arg, char *name);
-void openpic_intr_disestablish( void *lcp, void *arg);
-#ifdef MULTIPROCESSOR
-intr_send_ipi_t openpic_send_ipi;
-#endif
-void openpic_collect_preconf_intr(void);
-int openpic_big_endian;
-
void
openpic_attach(struct device *parent, struct device *self, void *aux)
{
+ struct cpu_info *ci = curcpu();
struct confargs *ca = aux;
u_int32_t reg;
@@ -168,12 +202,16 @@ openpic_attach(struct device *parent, struct device *self, void *aux)
openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr +
ca->ca_reg[0], 0x40000);
- printf(": version 0x%x %s endian", openpic_read(OPENPIC_VENDOR_ID),
- openpic_big_endian ? "big" : "little" );
+ /* openpic may support more than 128 interupts but driver doesn't */
+ openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1;
+
+ printf(": version 0x%x feature %x %s",
+ openpic_read(OPENPIC_VENDOR_ID),
+ openpic_read(OPENPIC_FEATURE),
+ openpic_big_endian ? "BE" : "LE" );
openpic_init();
- pending_int_f = openpic_do_pending_int;
intr_establish_func = openpic_intr_establish;
intr_disestablish_func = openpic_intr_disestablish;
mac_intr_establish_func = openpic_intr_establish;
@@ -181,22 +219,73 @@ openpic_attach(struct device *parent, struct device *self, void *aux)
#ifdef MULTIPROCESSOR
intr_send_ipi_func = openpic_send_ipi;
#endif
- install_extint(ext_intr_openpic);
-#if 1
+ ppc_smask_init();
+
openpic_collect_preconf_intr();
-#endif
+
+ evcount_attach(&openpic_spurious, "spurious",
+ (void *)&openpic_spurious_irq, &evcount_intr);
#if 1
mac_intr_establish(parent, 0x37, IST_LEVEL,
IPL_HIGH, openpic_prog_button, (void *)0x37, "progbutton");
#endif
+ ppc_intr_func.raise = openpic_splraise;
+ ppc_intr_func.lower = openpic_spllower;
+ ppc_intr_func.x = openpic_splx;
+
+ openpic_set_priority(ci->ci_cpl);
+
ppc_intr_enable(1);
printf("\n");
}
+static inline void
+openpic_setipl(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int s;
+ /* XXX - try do to this without the disable */
+ s = ppc_intr_disable();
+ ci->ci_cpl = newcpl;
+ openpic_set_priority(newcpl);
+ ppc_intr_enable(s);
+}
+
+int
+openpic_splraise(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ newcpl = openpic_pri_share[newcpl];
+ int ocpl = ci->ci_cpl;
+ if (ocpl > newcpl)
+ newcpl = ocpl;
+
+ openpic_setipl(newcpl);
+
+ return ocpl;
+}
+
+int
+openpic_spllower(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ openpic_splx(newcpl);
+
+ return ocpl;
+}
+
+void
+openpic_splx(int newcpl)
+{
+ openpic_do_pending_int(newcpl);
+}
+
void
openpic_collect_preconf_intr()
{
@@ -215,13 +304,6 @@ openpic_collect_preconf_intr()
}
}
-static int
-fakeintr(void *arg)
-{
-
- return 0;
-}
-
/*
* Register an interrupt handler.
*/
@@ -229,74 +311,52 @@ void *
openpic_intr_establish(void *lcv, int irq, int type, int level,
int (*ih_fun)(void *), void *ih_arg, char *name)
{
- struct intrhand **p, *q, *ih;
- static struct intrhand fakehand;
-
- fakehand.ih_next = NULL;
- fakehand.ih_fun = fakeintr;
-
-#if 0
-printf("mac_intr_establish, hI %d L %d ", irq, type);
-#endif
-
- irq = mapirq(irq);
-#if 0
-printf("vI %d ", irq);
-#endif
+ struct intrhand *ih;
+ struct intrq *iq;
+ int s;
/* no point in sleeping unless someone can free memory. */
ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
if (ih == NULL)
panic("intr_establish: can't malloc handler info");
+ iq = &openpic_handler[irq];
if (!LEGAL_IRQ(irq) || type == IST_NONE)
panic("intr_establish: bogus irq or type");
- switch (o_intrtype[irq]) {
+ switch (iq->iq_ist) {
case IST_NONE:
- o_intrtype[irq] = type;
+ iq->iq_ist = type;
break;
case IST_EDGE:
case IST_LEVEL:
- if (type == o_intrtype[irq])
+ if (type == iq->iq_ist)
break;
case IST_PULSE:
if (type != IST_NONE)
panic("intr_establish: can't share %s with %s",
- intr_typename(o_intrtype[irq]),
- intr_typename(type));
+ ppc_intr_typename(iq->iq_ist),
+ ppc_intr_typename(type));
break;
}
- /*
- * Figure out where to put the handler.
- * This is O(N^2), but we want to preserve the order, and N is
- * generally small.
- */
- for (p = &o_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
- ;
+ ih->ih_fun = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_level = level;
+ ih->ih_irq = irq;
+
+ evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
+ &evcount_intr);
/*
- * Actually install a fake handler momentarily, since we might be doing
- * this with interrupts enabled and DON'T WANt the real routine called
- * until masking is set up.
+ * Append handler to end of list
*/
- fakehand.ih_level = level;
- *p = &fakehand;
+ s = ppc_intr_disable();
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
openpic_calc_mask();
- /*
- * Poke the real handler in now.
- */
- ih->ih_fun = ih_fun;
- ih->ih_arg = ih_arg;
- ih->ih_next = NULL;
- ih->ih_level = level;
- ih->ih_irq = irq;
- evcount_attach(&ih->ih_count, name, (void *)&o_hwirq[irq],
- &evcount_intr);
- *p = ih;
+ ppc_intr_enable(s);
return (ih);
}
@@ -309,51 +369,27 @@ openpic_intr_disestablish(void *lcp, void *arg)
{
struct intrhand *ih = arg;
int irq = ih->ih_irq;
- struct intrhand **p, *q;
+ struct intrq *iq = &openpic_handler[irq];
+ int s;
if (!LEGAL_IRQ(irq))
panic("intr_disestablish: bogus irq");
/*
* Remove the handler from the chain.
- * This is O(n^2), too.
*/
- for (p = &o_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
- ;
- if (q)
- *p = q->ih_next;
- else
- panic("intr_disestablish: handler not registered");
-
- evcount_detach(&ih->ih_count);
- free((void *)ih, M_DEVBUF);
+ s = ppc_intr_disable();
+ TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
openpic_calc_mask();
- if (o_intrhand[irq] == NULL)
- o_intrtype[irq] = IST_NONE;
-}
-
+ ppc_intr_enable(s);
-static char *
-intr_typename(int type)
-{
+ evcount_detach(&ih->ih_count);
+ free((void *)ih, M_DEVBUF);
- switch (type) {
- case IST_NONE:
- return ("none");
- case IST_PULSE:
- return ("pulsed");
- case IST_EDGE:
- return ("edge-triggered");
- case IST_LEVEL:
- return ("level-triggered");
- default:
- panic("intr_typename: invalid type %d", type);
-#if 1 /* XXX */
- return ("unknown");
-#endif
- }
+ if (TAILQ_EMPTY(&iq->iq_list))
+ iq->iq_ist = IST_NONE;
}
/*
@@ -366,268 +402,129 @@ intr_typename(int type)
void
openpic_calc_mask()
{
+ struct cpu_info *ci = curcpu();
int irq;
struct intrhand *ih;
int i;
/* disable all openpic interrupts */
- openpic_set_priority(0, 15);
+ openpic_set_priority(15);
- for (irq = 0; irq < ICU_LEN; irq++) {
- int max = IPL_NONE;
- int min = IPL_HIGH;
- int reg;
- 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;
- }
- }
+ for (i = IPL_NONE; i < IPL_NUM; i++) {
+ openpic_pri_share[i] = i;
+ }
- o_intrmaxlvl[irq] = max;
+ for (irq = 0; irq < openpic_numirq; irq++) {
+ int maxipl = IPL_NONE;
+ int minipl = IPL_HIGH;
+ struct intrq *iq = &openpic_handler[irq];
- /* adjust priority if it changes */
- reg = openpic_read(OPENPIC_SRC_VECTOR(irq));
- if (max != ((reg >> OPENPIC_PRIORITY_SHIFT) & 0xf)) {
- openpic_write(OPENPIC_SRC_VECTOR(irq),
- (reg & ~(0xf << OPENPIC_PRIORITY_SHIFT)) |
- (max << OPENPIC_PRIORITY_SHIFT) );
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ if (ih->ih_level > maxipl)
+ maxipl = ih->ih_level;
+ if (ih->ih_level < minipl)
+ minipl = ih->ih_level;
}
- if (max == IPL_NONE)
- min = IPL_NONE; /* Interrupt not enabled */
+ if (maxipl == IPL_NONE) {
+ minipl = IPL_NONE; /* Interrupt not enabled */
- 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]);
+ openpic_disable_irq(irq);
+ } else {
+ for (i = minipl; i <= maxipl; i++) {
+ openpic_pri_share[i] = maxipl;
+ }
+ openpic_enable_irq(irq, maxipl);
}
- }
- /* restore interrupts */
- openpic_set_priority(0, 0);
-
- for (i = IPL_NONE; i <= IPL_HIGH; i++) {
- if (i > IPL_NONE)
- imask[i] |= SINT_MASK;
+ iq->iq_ipl = maxipl;
}
- imask[IPL_HIGH] = 0xffffffff;
-}
-
-/*
- * Map 64 irqs into 32 (bits).
- */
-static int
-mapirq(int irq)
-{
- int v;
-
- /* irq in table already? */
- if (o_virq[irq] != 0)
- return o_virq[irq];
-
- if (irq < 0 || irq >= ICU_LEN)
- panic("invalid irq %d", irq);
- o_virq_max++;
- v = o_virq_max;
- if (v > HWIRQ_MAX)
- panic("virq overflow");
-
- o_hwirq[v] = irq;
- o_virq[irq] = v;
-#if 0
-printf("\nmapirq %x to %x\n", irq, v);
-#endif
-
- return v;
-}
-
-/*
- * Count leading zeros.
- */
-static __inline int
-cntlzw(int x)
-{
- int a;
-
- __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
-
- return a;
+ /* restore interrupts */
+ openpic_set_priority(ci->ci_cpl);
}
-void openpic_do_pending_softint(int pcpl);
-
void
-openpic_do_pending_int()
+openpic_do_pending_int(int pcpl)
{
struct cpu_info *ci = curcpu();
- struct intrhand *ih;
- int irq;
- int pcpl;
- int hwpend;
- int pri, pripending;
int s;
+ int loopcount = 0;
- if (ci->ci_iactive & CI_IACTIVE_PROCESSING_HARD)
- return;
-
- atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_HARD);
s = ppc_intr_disable();
- pcpl = ci->ci_cpl;
-
- hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */
- hwpend &= HWIRQ_MASK;
- while (hwpend) {
- /* this still doesn't handle the interrupts in priority order */
- for (pri = IPL_HIGH; pri >= IPL_NONE; pri--) {
- pripending = hwpend & ~imask[pri];
- irq = 31 - cntlzw(pripending);
- ci->ci_ipending &= ~(1L << irq);
- ci->ci_cpl = imask[o_intrmaxlvl[o_hwirq[irq]]];
- openpic_enable_irq_mask(~ci->ci_cpl);
- ih = o_intrhand[irq];
- while(ih) {
- ppc_intr_enable(1);
-
- KERNEL_LOCK();
- if ((*ih->ih_fun)(ih->ih_arg))
- ih->ih_count.ec_count++;
- KERNEL_UNLOCK();
-
- (void)ppc_intr_disable();
-
- ih = ih->ih_next;
- }
- }
- hwpend = ci->ci_ipending & ~pcpl;/* Catch new pendings */
- hwpend &= HWIRQ_MASK;
- }
- ci->ci_cpl = pcpl | SINT_MASK;
- openpic_enable_irq_mask(~ci->ci_cpl);
- atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_HARD);
-
- openpic_do_pending_softint(pcpl);
-
- ppc_intr_enable(s);
-}
-
-void
-openpic_do_pending_softint(int pcpl)
-{
- struct cpu_info *ci = curcpu();
-
- if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT)
+ if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) {
+ ppc_intr_enable(s);
return;
+ }
atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
do {
- if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) {
- ci->ci_ipending &= ~SINT_CLOCK;
- ci->ci_cpl = SINT_CLOCK|SINT_NET|SINT_TTY;
- ppc_intr_enable(1);
+ loopcount ++;
+ if (loopcount > 5)
+ printf("do_pending looping %d pcpl %x %x\n", loopcount,
+ pcpl, ci->ci_cpl);
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
+ (pcpl < IPL_SOFTTTY)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
+
+ openpic_setipl(IPL_SOFTTTY);
+ ppc_intr_enable(s);
KERNEL_LOCK();
- softclock();
+ softtty();
KERNEL_UNLOCK();
ppc_intr_disable();
continue;
}
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
+ (pcpl < IPL_SOFTNET)) {
extern int netisr;
int pisr;
-
- ci->ci_ipending &= ~SINT_NET;
- ci->ci_cpl = SINT_NET|SINT_TTY;
+
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
+ openpic_setipl(IPL_SOFTNET);
+ ppc_intr_enable(s);
+ KERNEL_LOCK();
while ((pisr = netisr) != 0) {
atomic_clearbits_int(&netisr, pisr);
- ppc_intr_enable(1);
- KERNEL_LOCK();
softnet(pisr);
- KERNEL_UNLOCK();
- ppc_intr_disable();
}
+ KERNEL_UNLOCK();
+ ppc_intr_disable();
continue;
}
- if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
- ci->ci_ipending &= ~SINT_TTY;
- ci->ci_cpl = SINT_TTY;
- ppc_intr_enable(1);
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
+ (pcpl < IPL_SOFTCLOCK)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
+ openpic_setipl(IPL_SOFTCLOCK);
+ ppc_intr_enable(s);
KERNEL_LOCK();
- softtty();
+ softclock();
KERNEL_UNLOCK();
ppc_intr_disable();
continue;
}
- } while ((ci->ci_ipending & SINT_MASK) & ~pcpl);
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
+ break;
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
+ openpic_setipl(pcpl); /* Don't use splx... we are here already! */
atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
+ ppc_intr_enable(s);
}
-u_int
-openpic_read(int reg)
-{
- char *addr = (void *)(openpic_base + reg);
-
- if (openpic_big_endian)
- return in32(addr);
- else
- return in32rb(addr);
-}
-
-void
-openpic_write(int reg, u_int val)
-{
- char *addr = (void *)(openpic_base + reg);
-
- if (openpic_big_endian)
- out32(addr, val);
- else
- out32rb(addr, val);
-}
-
-void
-openpic_enable_irq_mask(int irq_mask)
-{
- int irq;
- for ( irq = 0; irq <= o_virq_max; irq++) {
- if (irq_mask & (1 << irq))
- openpic_enable_irq(o_hwirq[irq]);
- else
- openpic_disable_irq(o_hwirq[irq]);
- }
-}
-
-void
-openpic_set_enable_irq(int irq, int type)
-{
- u_int x;
-
- x = openpic_read(OPENPIC_SRC_VECTOR(irq));
- x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE);
- if (type == IST_LEVEL)
- x |= OPENPIC_SENSE_LEVEL;
- else
- x |= OPENPIC_SENSE_EDGE;
- openpic_write(OPENPIC_SRC_VECTOR(irq), x);
-}
void
-openpic_enable_irq(int irq)
+openpic_enable_irq(int irq, int pri)
{
u_int x;
+ struct intrq *iq = &openpic_handler[irq];
- x = openpic_read(OPENPIC_SRC_VECTOR(irq));
- x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE);
- if (o_intrtype[o_virq[irq]] == IST_LEVEL)
+ x = irq;
+ if (iq->iq_ist == IST_LEVEL)
x |= OPENPIC_SENSE_LEVEL;
else
x |= OPENPIC_SENSE_EDGE;
+ x |= OPENPIC_POLARITY_POSITIVE;
+ x |= pri << OPENPIC_PRIORITY_SHIFT;
openpic_write(OPENPIC_SRC_VECTOR(irq), x);
}
@@ -642,31 +539,13 @@ openpic_disable_irq(int irq)
}
void
-openpic_set_priority(int cpu, int pri)
-{
- u_int x;
-
- x = openpic_read(OPENPIC_CPU_PRIORITY(cpu));
- x &= ~OPENPIC_CPU_PRIORITY_MASK;
- x |= pri;
- openpic_write(OPENPIC_CPU_PRIORITY(cpu), x);
-}
-
-int
-openpic_read_irq(int cpu)
-{
- return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
-}
-
-void
-openpic_eoi(int cpu)
+openpic_set_priority(int pri)
{
- openpic_write(OPENPIC_EOI(cpu), 0);
- openpic_read(OPENPIC_EOI(cpu));
+ struct cpu_info *ci = curcpu();
+ openpic_write(OPENPIC_CPU_PRIORITY(ci->ci_cpuid), pri);
}
#ifdef MULTIPROCESSOR
-
void
openpic_send_ipi(struct cpu_info *ci, int id)
{
@@ -681,80 +560,80 @@ openpic_send_ipi(struct cpu_info *ci, int id)
panic("invalid ipi send to cpu %d %d\n", ci->ci_cpuid, id);
}
-
openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid);
}
#endif
void
-ext_intr_openpic()
+openpic_ext_intr()
{
struct cpu_info *ci = curcpu();
- int irq, realirq;
- int r_imen;
- int pcpl, ocpl;
+ int irq;
+ int pcpl;
struct intrhand *ih;
+ struct intrq *iq;
+ int irqloop = 0;
+ static int irqnest = 0;
+ int spurious;
pcpl = ci->ci_cpl;
- realirq = openpic_read_irq(ci->ci_cpuid);
+ irq = openpic_read_irq(ci->ci_cpuid);
+ irqnest++;
- while (realirq != 255) {
+ while (irq != 255) {
+ irqloop++;
+ if (irqloop > 20 || irqnest > 3) {
+ printf("irqloop %d irqnest %d\n", irqloop, irqnest);
+ }
#ifdef MULTIPROCESSOR
- if (realirq == IPI_VECTOR_NOP) {
+ if (irq == IPI_VECTOR_NOP) {
ipi_nop[ci->ci_cpuid].ec_count++;
openpic_eoi(ci->ci_cpuid);
- realirq = openpic_read_irq(ci->ci_cpuid);
+ irq = openpic_read_irq(ci->ci_cpuid);
continue;
}
- if (realirq == IPI_VECTOR_DDB) {
+ if (irq == IPI_VECTOR_DDB) {
ipi_ddb[ci->ci_cpuid].ec_count++;
openpic_eoi(ci->ci_cpuid);
openpic_ipi_ddb();
- realirq = openpic_read_irq(ci->ci_cpuid);
+ irq = openpic_read_irq(ci->ci_cpuid);
continue;
}
#endif
+ iq = &openpic_handler[irq];
- irq = o_virq[realirq];
+ if (iq->iq_ipl <= ci->ci_cpl)
+ printf("invalid interrupt %d lvl %d at %d hw %d\n",
+ irq, iq->iq_ipl, ci->ci_cpl,
+ openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid)));
+ splraise(iq->iq_ipl);
+ openpic_eoi(ci->ci_cpuid);
- /* XXX check range */
-
- r_imen = 1 << irq;
-
- if ((pcpl & r_imen) != 0) {
- /* Masked! Mark this as pending. */
- ci->ci_ipending |= r_imen;
- openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]);
- openpic_eoi(ci->ci_cpuid);
- } else {
- openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]);
- openpic_eoi(ci->ci_cpuid);
- ocpl = splraise(imask[o_intrmaxlvl[realirq]]);
-
- ih = o_intrhand[irq];
- while (ih) {
- ppc_intr_enable(1);
-
- KERNEL_LOCK();
- if ((*ih->ih_fun)(ih->ih_arg))
- ih->ih_count.ec_count++;
- KERNEL_UNLOCK();
-
- (void)ppc_intr_disable();
- ih = ih->ih_next;
- }
+ spurious = 1;
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ ppc_intr_enable(1);
+ KERNEL_LOCK();
+ if ((*ih->ih_fun)(ih->ih_arg)) {
+ ih->ih_count.ec_count++;
+ spurious = 0;
+ }
+ KERNEL_UNLOCK();
- uvmexp.intrs++;
- __asm__ volatile("":::"memory"); /* don't reorder.... */
- ci->ci_cpl = ocpl;
- __asm__ volatile("":::"memory"); /* don't reorder.... */
- openpic_enable_irq_mask(~pcpl);
+ (void)ppc_intr_disable();
+ }
+ if (spurious) {
+ openpic_spurious.ec_count++;
+ printf("spurious intr %d\n", irq);
}
- realirq = openpic_read_irq(ci->ci_cpuid);
+ uvmexp.intrs++;
+ openpic_setipl(pcpl);
+
+ irq = openpic_read_irq(ci->ci_cpuid);
}
+ irqnest--;
ppc_intr_enable(1);
splx(pcpl); /* Process pendings. */
@@ -763,22 +642,29 @@ ext_intr_openpic()
void
openpic_init()
{
+ struct cpu_info *ci = curcpu();
+ struct intrq *iq;
int irq;
u_int x;
+ int i;
+
+ openpic_set_priority(15);
/* disable all interrupts */
- for (irq = 0; irq < 255; irq++)
+ for (irq = 0; irq < openpic_numirq; irq++)
openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
- openpic_set_priority(0, 15);
+
+ for (i = 0; i < openpic_numirq; i++) {
+ iq = &openpic_handler[i];
+ TAILQ_INIT(&iq->iq_list);
+ }
/* we don't need 8259 pass through mode */
x = openpic_read(OPENPIC_CONFIG);
x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
openpic_write(OPENPIC_CONFIG, x);
- /* send all interrupts to cpu 0 */
- for (irq = 0; irq < ICU_LEN; irq++)
- openpic_write(OPENPIC_IDEST(irq), 1 << 0);
+ /* initialize all vectors to something sane */
for (irq = 0; irq < ICU_LEN; irq++) {
x = irq;
x |= OPENPIC_IMASK;
@@ -788,6 +674,17 @@ openpic_init()
openpic_write(OPENPIC_SRC_VECTOR(irq), x);
}
+ /* send all interrupts to cpu 0 */
+ for (irq = 0; irq < openpic_numirq; irq++)
+ openpic_write(OPENPIC_IDEST(irq), 1 << 0);
+
+ /* clear all pending interrunts */
+ for (irq = 0; irq < ICU_LEN; irq++) {
+ openpic_read_irq(ci->ci_cpuid);
+ openpic_eoi(ci->ci_cpuid);
+ }
+
+
#ifdef MULTIPROCESSOR
/* Set up inter-processor interrupts. */
/* IPI0 - NOP */
@@ -801,6 +698,7 @@ openpic_init()
x |= (15 << OPENPIC_PRIORITY_SHIFT) | IPI_VECTOR_DDB;
openpic_write(OPENPIC_IPI_VECTOR(1), x);
+ /* XXX - ncpus */
evcount_attach(&ipi_nop[0], "ipi_nop0", (void *)&ipi_nopirq,
&evcount_intr);
evcount_attach(&ipi_nop[1], "ipi_nop1", (void *)&ipi_nopirq,
@@ -811,21 +709,21 @@ openpic_init()
&evcount_intr);
#endif
- /* XXX set spurious intr vector */
-
- openpic_set_priority(0, 0);
-
/* clear all pending interrunts */
for (irq = 0; irq < ICU_LEN; irq++) {
openpic_read_irq(0);
openpic_eoi(0);
}
- for (irq = 0; irq < ICU_LEN; irq++)
- openpic_disable_irq(irq);
+#if 0
+ openpic_write(OPENPIC_SPURIOUS_VECTOR, 255);
+#endif
- install_extint(ext_intr_openpic);
+ install_extint(openpic_ext_intr);
+
+ openpic_set_priority(0);
}
+
/*
* programmer_button function to fix args to Debugger.
* deal with any enables/disables, if necessary.
@@ -842,10 +740,9 @@ openpic_prog_button (void *arg)
return 1;
}
-
void
-openpic_ipi_ddb(void)
+openpic_ipi_ddb()
{
+ printf("ipi_ddb() called\n");
Debugger();
}
-
diff --git a/sys/arch/macppc/include/intr.h b/sys/arch/macppc/include/intr.h
index 5278758ac65..ee424cb7224 100644
--- a/sys/arch/macppc/include/intr.h
+++ b/sys/arch/macppc/include/intr.h
@@ -1,9 +1,9 @@
-/* $OpenBSD: intr.h,v 1.4 2008/09/16 04:20:42 drahn Exp $ */
+/* $OpenBSD: intr.h,v 1.5 2008/09/18 03:56:25 drahn Exp $ */
#include <powerpc/intr.h>
#ifndef _LOCORE
void softtty(void);
-void openpic_set_priority(int, int);
+void openpic_set_priority(int);
#endif
diff --git a/sys/arch/macppc/macppc/clock.c b/sys/arch/macppc/macppc/clock.c
index 6c7f3f889ec..215e8c46b17 100644
--- a/sys/arch/macppc/macppc/clock.c
+++ b/sys/arch/macppc/macppc/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.22 2008/04/30 17:59:33 kettenis Exp $ */
+/* $OpenBSD: clock.c,v 1.23 2008/09/18 03:56:25 drahn Exp $ */
/* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */
/*
@@ -225,7 +225,7 @@ decr_intr(struct clockframe *frame)
*/
ppc_mtdec(nextevent - tb);
- if (curcpu()->ci_cpl & SPL_CLOCK) {
+ if (ci->ci_cpl >= IPL_CLOCK) {
ci->ci_statspending += nstats;
} else {
KERNEL_LOCK();
diff --git a/sys/arch/macppc/macppc/cpu.c b/sys/arch/macppc/macppc/cpu.c
index 5d0efe0079a..1c7e58ea528 100644
--- a/sys/arch/macppc/macppc/cpu.c
+++ b/sys/arch/macppc/macppc/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.57 2008/05/02 19:10:01 drahn Exp $ */
+/* $OpenBSD: cpu.c,v 1.58 2008/09/18 03:56:25 drahn Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom
@@ -788,7 +788,7 @@ cpu_hatch(void)
ppc_intr_enable(intrstate);
/* Enable inter-processor interrupts. */
- openpic_set_priority(curcpu()->ci_cpuid, 14);
+ openpic_set_priority(14);
SCHED_LOCK(s);
cpu_switchto(NULL, sched_chooseproc());
diff --git a/sys/arch/macppc/macppc/genassym.cf b/sys/arch/macppc/macppc/genassym.cf
index 78f4defa294..edd3bd8a851 100644
--- a/sys/arch/macppc/macppc/genassym.cf
+++ b/sys/arch/macppc/macppc/genassym.cf
@@ -1,4 +1,4 @@
-# $OpenBSD: genassym.cf,v 1.17 2008/04/27 15:59:49 drahn Exp $
+# $OpenBSD: genassym.cf,v 1.18 2008/09/18 03:56:25 drahn Exp $
#
# Copyright (c) 1982, 1990 The Regents of the University of California.
# All rights reserved.
@@ -86,7 +86,6 @@ member ci_curproc
member ci_curpcb
member ci_curpm
member ci_want_resched
-member ci_cpl
member ci_intrdepth
member ci_intstk
member ci_tempsave
diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c
index befb3f7bd19..d7a7dae07c6 100644
--- a/sys/arch/macppc/macppc/machdep.c
+++ b/sys/arch/macppc/macppc/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.100 2008/09/16 04:20:42 drahn Exp $ */
+/* $OpenBSD: machdep.c,v 1.101 2008/09/18 03:56:25 drahn Exp $ */
/* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */
/*
@@ -877,8 +877,6 @@ dumpsys()
}
-int imask[IPL_NUM];
-
/*
* this is a hack interface to allow zs to work better until
* a true soft interrupt mechanism is created.