summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2009-06-02 21:38:11 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2009-06-02 21:38:11 +0000
commitf70288906283f2a7276a9ce61eff992b7cb8b159 (patch)
treed2d247a2dfdaa434991b7979c084feeb181ce8ff /sys
parent09f980458916221509f840029a090c38d3b759ac (diff)
Reintroduce the macppc interrupt subsystem rewrite. Several bugs have
been found and corrected.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/macppc/dev/macintr.c547
-rw-r--r--sys/arch/macppc/dev/openpic.c766
-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
-rw-r--r--sys/arch/powerpc/include/intr.h117
-rw-r--r--sys/arch/powerpc/powerpc/intr.c104
-rw-r--r--sys/arch/powerpc/powerpc/mutex.S44
-rw-r--r--sys/arch/socppc/dev/ipic.c209
-rw-r--r--sys/arch/socppc/socppc/machdep.c60
12 files changed, 931 insertions, 935 deletions
diff --git a/sys/arch/macppc/dev/macintr.c b/sys/arch/macppc/dev/macintr.c
index 73235f28e77..baf88edcb88 100644
--- a/sys/arch/macppc/dev/macintr.c
+++ b/sys/arch/macppc/dev/macintr.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: macintr.c,v 1.35 2008/11/21 17:35:52 deraadt Exp $ */
+/* $OpenBSD: macintr.c,v 1.36 2009/06/02 21:38:09 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);
+ iq->iq_ipl = maxipl;
- out32rb(INT_ENABLE_REG0, state0);
-}
-
-int m_virq_inited = 0;
-
-/*
- * 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,135 @@ 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);
+ irq = macintr_read_irq();
+ while (irq != 255) {
+ iq = &macintr_handler[irq];
+ macintr_setipl(iq->iq_ipl);
- o_imen = imen_m;
- r_imen = 1 << irq;
-
- 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 pcpl = ci->ci_cpl; /* XXX */
int s;
-
- if (ci->ci_iactive)
- return;
-
- ci->ci_iactive = 1;
- pcpl = splhigh(); /* Turn off all */
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);
+ 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 bedd55017fd..d68949d13f2 100644
--- a/sys/arch/macppc/dev/openpic.c
+++ b/sys/arch/macppc/dev/openpic.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: openpic.c,v 1.52 2008/11/21 17:35:52 deraadt Exp $ */
+/* $OpenBSD: openpic.c,v 1.53 2009/06/02 21:38:09 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,10 @@ 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_do_pending_int_dis(int pcpl, int s);
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 +126,42 @@ struct cfdriver openpic_cd = {
NULL, "openpic", DV_DULL
};
+u_int
+openpic_read(int reg)
+{
+ char *addr = (void *)(openpic_base + reg);
+
+ asm volatile("eieio"::: "memory");
+ 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"::: "memory");
+}
+
+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 +189,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 +203,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 +220,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 +305,6 @@ openpic_collect_preconf_intr()
}
}
-static int
-fakeintr(void *arg)
-{
-
- return 0;
-}
-
/*
* Register an interrupt handler.
*/
@@ -229,74 +312,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 +370,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 +403,142 @@ 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;
-
- 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);
-
+ openpic_do_pending_int_dis(pcpl, s);
ppc_intr_enable(s);
+
}
+/*
+ * This function expect interrupts disabled on entry and exit,
+ * the s argument indicates if interrupts may be enabled during
+ * the processing of off level interrupts, s 'should' always be 1.
+ */
void
-openpic_do_pending_softint(int pcpl)
+openpic_do_pending_int_dis(int pcpl, int s)
{
struct cpu_info *ci = curcpu();
+ int loopcount = 0;
- if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT)
+ if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) {
+ /* soft interrupts are being processed, just set ipl/return */
+ openpic_setipl(pcpl);
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 > 50)
+ 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);
}
-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)
+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 (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)
-{
- u_int x;
-
- 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 +553,13 @@ openpic_disable_irq(int irq)
}
void
-openpic_set_priority(int cpu, int pri)
+openpic_set_priority(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_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,104 +574,148 @@ 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
+int openpic_irqnest[PPC_MAXPROCS];
+int openpic_irqloop[PPC_MAXPROCS];
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;
+ int maxipl = IPL_NONE;
struct intrhand *ih;
+ struct intrq *iq;
+ int spurious;
pcpl = ci->ci_cpl;
- realirq = openpic_read_irq(ci->ci_cpuid);
-
- while (realirq != 255) {
+ openpic_irqloop[ci->ci_cpuid] = 0;
+ irq = openpic_read_irq(ci->ci_cpuid);
+ openpic_irqnest[ci->ci_cpuid]++;
+
+ while (irq != 255) {
+ openpic_irqloop[ci->ci_cpuid]++;
+ if (openpic_irqloop[ci->ci_cpuid] > 20 ||
+ openpic_irqnest[ci->ci_cpuid] > 3) {
+ printf("irqloop %d irqnest %d\n",
+ openpic_irqloop[ci->ci_cpuid],
+ openpic_irqnest[ci->ci_cpuid]);
+ }
#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];
+
+ 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)));
+ if (iq->iq_ipl > maxipl)
+ maxipl = iq->iq_ipl;
+ splraise(iq->iq_ipl);
+ openpic_eoi(ci->ci_cpuid);
+
+ 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();
- irq = o_virq[realirq];
-
- /* 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]]);
+ (void)ppc_intr_disable();
+ }
+ if (spurious) {
+ openpic_spurious.ec_count++;
+#ifdef OPENPIC_NOISY
+ printf("spurious intr %d\n", irq);
+#endif
+ }
- ih = o_intrhand[irq];
- while (ih) {
- ppc_intr_enable(1);
+ uvmexp.intrs++;
+ openpic_setipl(pcpl);
- KERNEL_LOCK();
- if ((*ih->ih_fun)(ih->ih_arg))
- ih->ih_count.ec_count++;
- KERNEL_UNLOCK();
+ irq = openpic_read_irq(ci->ci_cpuid);
+ }
- (void)ppc_intr_disable();
- ih = ih->ih_next;
+ if (openpic_irqnest[ci->ci_cpuid] == 1) {
+ openpic_irqloop[ci->ci_cpuid] = 0;
+ /* raise IPL back to max until do_pending will lower it back */
+ openpic_setipl(maxipl);
+ /*
+ * we must not process pending soft interrupts when nested, can
+ * cause excessive recursion.
+ *
+ * The loop here is because an interrupt could case a pending
+ * soft interrupt between the finishing of the
+ * openpic_do_pending_int, but before ppc_intr_disable
+ */
+ do {
+ openpic_irqloop[ci->ci_cpuid]++;
+ if (openpic_irqloop[ci->ci_cpuid] > 5) {
+ printf("ext_intr: do_pending loop %d\n",
+ openpic_irqloop[ci->ci_cpuid]);
}
-
- uvmexp.intrs++;
- __asm__ volatile("":::"memory"); /* don't reorder.... */
- ci->ci_cpl = ocpl;
- __asm__ volatile("":::"memory"); /* don't reorder.... */
- openpic_enable_irq_mask(~pcpl);
- }
-
- realirq = openpic_read_irq(ci->ci_cpuid);
+ if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) {
+ openpic_setipl(pcpl);
+ /*
+ * some may be pending but someone else is
+ * processing them
+ */
+ break;
+ } else {
+ openpic_do_pending_int_dis(pcpl, 1);
+ }
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
}
- ppc_intr_enable(1);
-
- splx(pcpl); /* Process pendings. */
+ openpic_irqnest[ci->ci_cpuid]--;
}
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 +725,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 +749,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 +760,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(openpic_ext_intr);
- install_extint(ext_intr_openpic);
+ openpic_set_priority(0);
}
+
/*
* programmer_button function to fix args to Debugger.
* deal with any enables/disables, if necessary.
@@ -842,10 +791,11 @@ openpic_prog_button (void *arg)
return 1;
}
-
void
-openpic_ipi_ddb(void)
+openpic_ipi_ddb()
{
+#ifdef OPENPIC_NOISY
+ printf("ipi_ddb() called\n");
+#endif
Debugger();
}
-
diff --git a/sys/arch/macppc/include/intr.h b/sys/arch/macppc/include/intr.h
index c881dc54add..92ef9bfec34 100644
--- a/sys/arch/macppc/include/intr.h
+++ b/sys/arch/macppc/include/intr.h
@@ -1,9 +1,9 @@
-/* $OpenBSD: intr.h,v 1.6 2008/11/21 17:35:52 deraadt Exp $ */
+/* $OpenBSD: intr.h,v 1.7 2009/06/02 21:38:09 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 3ff3e9243cf..f74bcdfa750 100644
--- a/sys/arch/macppc/macppc/clock.c
+++ b/sys/arch/macppc/macppc/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.27 2009/06/02 21:23:55 drahn Exp $ */
+/* $OpenBSD: clock.c,v 1.28 2009/06/02 21:38:09 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 (ci->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 e76832070d2..87b31161710 100644
--- a/sys/arch/macppc/macppc/cpu.c
+++ b/sys/arch/macppc/macppc/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.61 2009/04/14 16:01:04 oga Exp $ */
+/* $OpenBSD: cpu.c,v 1.62 2009/06/02 21:38:09 drahn Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom
@@ -790,7 +790,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 50438c0f76e..a8c1410305b 100644
--- a/sys/arch/macppc/macppc/genassym.cf
+++ b/sys/arch/macppc/macppc/genassym.cf
@@ -1,4 +1,4 @@
-# $OpenBSD: genassym.cf,v 1.19 2008/11/21 17:35:52 deraadt Exp $
+# $OpenBSD: genassym.cf,v 1.20 2009/06/02 21:38:09 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 67005512a79..bf30d430a40 100644
--- a/sys/arch/macppc/macppc/machdep.c
+++ b/sys/arch/macppc/macppc/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.104 2009/01/22 22:41:42 kettenis Exp $ */
+/* $OpenBSD: machdep.c,v 1.105 2009/06/02 21:38:09 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.
diff --git a/sys/arch/powerpc/include/intr.h b/sys/arch/powerpc/include/intr.h
index d2f85d51aaf..fd930ce08e9 100644
--- a/sys/arch/powerpc/include/intr.h
+++ b/sys/arch/powerpc/include/intr.h
@@ -1,8 +1,8 @@
-/* $OpenBSD: intr.h,v 1.39 2009/03/15 19:40:40 miod Exp $ */
+/* $OpenBSD: intr.h,v 1.40 2009/06/02 21:38:10 drahn Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,14 +36,18 @@
#define _POWERPC_INTR_H_
#define IPL_NONE 0
-#define IPL_BIO 1
+#define IPL_SOFT 1
+#define IPL_SOFTCLOCK 2
+#define IPL_SOFTNET 3
+#define IPL_SOFTTTY 4
+#define IPL_BIO 5
#define IPL_AUDIO IPL_BIO /* XXX - was defined this val in audio_if.h */
-#define IPL_NET 2
-#define IPL_TTY 3
-#define IPL_VM 4
-#define IPL_CLOCK 5
-#define IPL_HIGH 6
-#define IPL_NUM 7
+#define IPL_NET 6
+#define IPL_TTY 7
+#define IPL_VM 8
+#define IPL_CLOCK 9
+#define IPL_HIGH 10
+#define IPL_NUM 11
#define IST_NONE 0
#define IST_PULSE 1
@@ -55,9 +59,9 @@
#include <sys/evcount.h>
#include <machine/atomic.h>
-#define PPC_NIRQ 66
-#define PPC_CLK_IRQ 64
-#define PPC_STAT_IRQ 65
+#define PPC_NIRQ 66
+#define PPC_CLK_IRQ 64
+#define PPC_STAT_IRQ 65
void setsoftclock(void);
void clearsoftclock(void);
@@ -70,10 +74,22 @@ int splraise(int);
int spllower(int);
void splx(int);
+typedef int (ppc_splraise_t) (int);
+typedef int (ppc_spllower_t) (int);
+typedef void (ppc_splx_t) (int);
-void do_pending_int(void);
+extern struct ppc_intr_func {
+ ppc_splraise_t *raise;
+ ppc_spllower_t *lower;
+ ppc_splx_t *x;
+}ppc_intr_func;
+
+extern int ppc_smask[IPL_NUM];
-extern int imask[IPL_NUM];
+void ppc_smask_init(void);
+char *ppc_intr_typename(int type);
+
+void do_pending_int(void);
/* SPL asserts */
#define splassert(wantipl) /* nothing */
@@ -81,38 +97,32 @@ extern int imask[IPL_NUM];
#define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p)
-#define SINT_CLOCK 0x10000000
-#define SINT_NET 0x20000000
-#define SINT_TTY 0x40000000
-#define SPL_CLOCK 0x80000000
-#define SINT_MASK (SINT_CLOCK|SINT_NET|SINT_TTY)
-
-#define splbio() splraise(imask[IPL_BIO])
-#define splnet() splraise(imask[IPL_NET])
-#define spltty() splraise(imask[IPL_TTY])
-#define splaudio() splraise(imask[IPL_AUDIO])
-#define splclock() splraise(imask[IPL_CLOCK])
-#define splvm() splraise(imask[IPL_VM])
-#define splsched() splhigh()
-#define spllock() splhigh()
-#define splstatclock() splhigh()
-#define splsoftclock() splraise(SINT_CLOCK)
-#define splsoftnet() splraise(SINT_NET|SINT_CLOCK)
-#define splsofttty() splraise(SINT_TTY|SINT_NET|SINT_CLOCK)
-
-#define setsoftclock() set_sint(SINT_CLOCK);
-#define setsoftnet() set_sint(SINT_NET);
-#define setsofttty() set_sint(SINT_TTY);
-
-#define splhigh() splraise(0xffffffff)
-#define spl0() spllower(0)
+#define splbio() splraise(IPL_BIO)
+#define splnet() splraise(IPL_NET)
+#define spltty() splraise(IPL_TTY)
+#define splaudio() splraise(IPL_AUDIO)
+#define splclock() splraise(IPL_CLOCK)
+#define splvm() splraise(IPL_VM)
+#define splsched() splhigh()
+#define spllock() splhigh()
+#define splstatclock() splhigh()
+#define splsoftclock() splraise(IPL_SOFTCLOCK)
+#define splsoftnet() splraise(IPL_SOFTNET)
+#define splsofttty() splraise(IPL_SOFTTTY)
+
+#define setsoftclock() set_sint(SI_TO_IRQBIT(SI_SOFTCLOCK))
+#define setsoftnet() set_sint(SI_TO_IRQBIT(SI_SOFTNET))
+#define setsofttty() set_sint(SI_TO_IRQBIT(SI_SOFTTTY))
+
+#define splhigh() splraise(IPL_HIGH)
+#define spl0() spllower(IPL_NONE)
/*
* Interrupt control struct used to control the ICU setup.
*/
struct intrhand {
- struct intrhand *ih_next;
+ TAILQ_ENTRY(intrhand) ih_list;
int (*ih_fun)(void *);
void *ih_arg;
struct evcount ih_count;
@@ -120,11 +130,36 @@ struct intrhand {
int ih_irq;
char *ih_what;
};
+
+struct intrq {
+ TAILQ_HEAD(, intrhand) iq_list; /* handler list */
+ int iq_ipl; /* IPL_ to mask while handling */
+ int iq_ist; /* share type */
+};
+
extern int ppc_configed_intr_cnt;
-#define MAX_PRECONF_INTR 16
+#define MAX_PRECONF_INTR 16
extern struct intrhand ppc_configed_intr[MAX_PRECONF_INTR];
void softnet(int isr);
+#define SI_TO_IRQBIT(x) (1 << (x))
+
+#define SI_SOFT 0 /* for IPL_SOFT */
+#define SI_SOFTCLOCK 1 /* for IPL_SOFTCLOCK */
+#define SI_SOFTNET 2 /* for IPL_SOFTNET */
+#define SI_SOFTTTY 3 /* for IPL_SOFTSERIAL */
+
+#if 0
+#define SI_NQUEUES 4
+
+#define SI_QUEUENAMES { \
+ "generic", \
+ "clock", \
+ "net", \
+ "serial", \
+}
+#endif
+
#define PPC_IPI_NOP 0
#define PPC_IPI_DDB 1
diff --git a/sys/arch/powerpc/powerpc/intr.c b/sys/arch/powerpc/powerpc/intr.c
index 722477c74cd..56e919dbe58 100644
--- a/sys/arch/powerpc/powerpc/intr.c
+++ b/sys/arch/powerpc/powerpc/intr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.c,v 1.4 2008/11/21 17:35:52 deraadt Exp $ */
+/* $OpenBSD: intr.c,v 1.5 2009/06/02 21:38:10 drahn Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA.
@@ -35,45 +35,121 @@
#include <machine/cpu.h>
#include <machine/intr.h>
+#include <machine/lock.h>
+
+int ppc_dflt_splraise(int);
+int ppc_dflt_spllower(int);
+void ppc_dflt_splx(int);
+
+/* provide a function for asm code to call */
+#undef splraise
+#undef spllower
+#undef splx
+
+int ppc_smask[IPL_NUM];
+
+void
+ppc_smask_init()
+{
+ int i;
+
+ for (i = IPL_NONE; i <= IPL_HIGH; i++) {
+ ppc_smask[i] = 0;
+#if 0
+ /* NOT YET */
+ if (i < IPL_SOFT)
+ ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
+#endif
+ if (i < IPL_SOFTCLOCK)
+ ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
+ if (i < IPL_SOFTNET)
+ ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
+ if (i < IPL_SOFTTTY)
+ ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFTTTY);
+ }
+}
+
int
splraise(int newcpl)
{
+ return ppc_intr_func.raise(newcpl);
+}
+
+int
+spllower(int newcpl)
+{
+ return ppc_intr_func.lower(newcpl);
+}
+
+void
+splx(int newcpl)
+{
+ ppc_intr_func.x(newcpl);
+}
+
+/*
+ * functions with 'default' behavior to use before the real
+ * interrupt controller attaches
+ */
+int
+ppc_dflt_splraise(int newcpl)
+{
struct cpu_info *ci = curcpu();
int oldcpl;
- __asm__ volatile("":::"memory"); /* reorder protect */
oldcpl = ci->ci_cpl;
- ci->ci_cpl = oldcpl | newcpl;
- __asm__ volatile("":::"memory");
+ if (newcpl < oldcpl)
+ newcpl = oldcpl;
+ ci->ci_cpl = newcpl;
return (oldcpl);
}
int
-spllower(int newcpl)
+ppc_dflt_spllower(int newcpl)
{
struct cpu_info *ci = curcpu();
int oldcpl;
- __asm__ volatile("":::"memory"); /* reorder protect */
oldcpl = ci->ci_cpl;
- ci->ci_cpl = newcpl;
- if (ci->ci_ipending & ~newcpl)
- do_pending_int();
- __asm__ volatile("":::"memory");
+
+ splx(newcpl);
return (oldcpl);
}
void
-splx(int newcpl)
+ppc_dflt_splx(int newcpl)
{
struct cpu_info *ci = curcpu();
- __asm__ volatile("":::"memory"); /* reorder protect */
ci->ci_cpl = newcpl;
- if (ci->ci_ipending & ~newcpl)
+
+ if (ci->ci_ipending & ppc_smask[newcpl])
do_pending_int();
- __asm__ volatile("":::"memory");
+}
+
+struct ppc_intr_func ppc_intr_func =
+{
+ ppc_dflt_splraise,
+ ppc_dflt_spllower,
+ ppc_dflt_splx
+};
+
+char *
+ppc_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:
+ return ("unknown");
+ }
}
diff --git a/sys/arch/powerpc/powerpc/mutex.S b/sys/arch/powerpc/powerpc/mutex.S
index 5f45f1f7673..6511203f606 100644
--- a/sys/arch/powerpc/powerpc/mutex.S
+++ b/sys/arch/powerpc/powerpc/mutex.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: mutex.S,v 1.7 2009/04/27 21:48:56 kettenis Exp $ */
+/* $OpenBSD: mutex.S,v 1.8 2009/06/02 21:38:10 drahn Exp $ */
/*
* Copyright (c) 2007 Dale Rahn
@@ -22,7 +22,11 @@
#include <machine/asm.h>
/* XXX */
+#ifdef USERLAND
+#define GET_CPUINFO(r) mr r, %r4
+#else
#define GET_CPUINFO(r) mfsprg r,0
+#endif
ENTRY(mtx_init)
li %r5,0
@@ -32,44 +36,44 @@ ENTRY(mtx_init)
blr
+/*
+ * mtx_enter(struct mutex *mtx[%r3])
+ */
ENTRY(mtx_enter)
- stwu %r1,-32(%r1) # reserve stack
+ stwu %r1,-16(%r1) # reserve stack
mflr %r0
- stw %r0,36(%r1) # save return address
+ stw %r0,20(%r1) # save return address
.L_retry:
+ stw %r3, 12(%r1)
+ lwz %r3,MTX_WANTIPL(%r3) # load new ipl
+ bl _C_LABEL(splraise)
+ mr %r7, %r3
GET_CPUINFO(%r4)
- lwz %r5,MTX_WANTIPL(%r3) # load new ipl
- lis %r6,_C_LABEL(imask)@ha # convert into cpl
- slwi %r5,%r5,2
- addi %r5,%r5,_C_LABEL(imask)@l
- lwzx %r5,%r5,%r6
- lwz %r7,CI_CPL(%r4) # load current cpl
- or %r6,%r5,%r7 # raise cpl
- stw %r6,CI_CPL(%r4) # store new cpl
+ lwz %r3,12(%r1)
li %r5,MTX_OWNER # load offset constant
lwarx %r6,%r5,%r3 # load reserve owner
cmpwi 0,%r6,0 # test owner == 0
beq+ 0,.L_mutex_free # if owner == 0 branch free
-.L_mutex_locked:
#ifdef DIAGNOSTIC
cmpl 0,%r4,%r6
beq- .L_mutex_selflocked
#endif
- stw %r3,28(%r1) # save mtx during lcsplx
- la %r4,28(%r1)
+.L_mutex_busy:
+ stw %r3,12(%r1) # save mtx during lcsplx
+ la %r4,12(%r1)
stwcx. %r3,0,%r4 # unreserve owner
mr %r3,%r7 # move old cpl to arg0
bl _C_LABEL(lcsplx) # call splx on old cpl
- lwz %r3,28(%r1)
+ lwz %r3,12(%r1)
b .L_retry
.L_mutex_free:
stwcx. %r4,%r5,%r3 # old owner was 0 cond store
- bne- .L_mutex_locked # branch if reserve cancelled
+ bne- .L_mutex_busy # branch if reserve cancelled
stw %r7,MTX_OLDCPL(%r3) # save old ipl
- lwz %r0,36(%r1) # load return address
+ lwz %r0,20(%r1) # load return address
mtlr %r0
- addi %r1,%r1,32 # restore stack
+ addi %r1,%r1,16 # restore stack
blr
#ifdef DIAGNOSTIC
@@ -94,11 +98,7 @@ ENTRY(mtx_leave)
lwz %r5,MTX_OLDCPL(%r3)
stw %r4,MTX_OLDCPL(%r3)
stw %r4,MTX_OWNER(%r3)
- GET_CPUINFO(%r4)
mr %r3,%r5
- lwz %r5,CI_CPL(%r4)
- cmpl 0,%r3,%r5
- beq 1f
b _C_LABEL(lcsplx)
1:
blr
diff --git a/sys/arch/socppc/dev/ipic.c b/sys/arch/socppc/dev/ipic.c
index f48770b9efb..364a0e401b3 100644
--- a/sys/arch/socppc/dev/ipic.c
+++ b/sys/arch/socppc/dev/ipic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipic.c,v 1.6 2008/12/04 16:02:20 maja Exp $ */
+/* $OpenBSD: ipic.c,v 1.7 2009/06/02 21:38:10 drahn Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
@@ -63,7 +63,7 @@ struct ipic_softc {
};
uint32_t ipic_imask;
-struct intrhand *ipic_intrhand[IPIC_NVEC];
+struct intrq ipic_handler[IPIC_NVEC];
struct ipic_softc *ipic_sc;
int ipic_match(struct device *, void *, void *);
@@ -82,9 +82,17 @@ void ipic_write(struct ipic_softc *, bus_addr_t, uint32_t);
uint32_t ipic_simsr_h(int);
uint32_t ipic_simsr_l(int);
uint32_t ipic_semsr(int);
+void ipic_calc_masks(void);
void ext_intr(void);
-void ipic_do_pending_int(void);
+
+ppc_splraise_t ipic_splraise;
+ppc_spllower_t ipic_spllower;
+ppc_splx_t ipic_splx;
+
+void ipic_setipl(int);
+void ipic_do_pending(int);
+
int
ipic_match(struct device *parent, void *cfdata, void *aux)
@@ -97,6 +105,8 @@ ipic_attach(struct device *parent, struct device *self, void *aux)
{
struct ipic_softc *sc = (void *)self;
struct obio_attach_args *oa = aux;
+ struct intrq *iq;
+ int i;
sc->sc_iot = oa->oa_iot;
if (bus_space_map(sc->sc_iot, oa->oa_offset, 128, 0, &sc->sc_ioh)) {
@@ -105,6 +115,17 @@ ipic_attach(struct device *parent, struct device *self, void *aux)
}
ipic_sc = sc;
+
+ for (i = 0; i < IPIC_NVEC; i++) {
+ iq = &ipic_handler[i];
+ TAILQ_INIT(&iq->iq_list);
+ }
+
+ ppc_smask_init();
+ ppc_intr_func.raise = ipic_splraise;
+ ppc_intr_func.lower = ipic_spllower;
+ ppc_intr_func.x = ipic_splx;
+
printf("\n");
}
@@ -176,32 +197,10 @@ ipic_semsr(int ivec)
return 0;
}
-static void
-intr_calculatemasks(void)
+void
+ipic_calc_masks(void)
{
struct ipic_softc *sc = ipic_sc;
- int level;
-
- for (level = IPL_NONE; level < IPL_NUM; level++)
- imask[level] = SINT_MASK | (1 << level);
-
- /*
- * 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;
sc->sc_simsr_h[IPL_NET] |= sc->sc_simsr_h[IPL_BIO];
sc->sc_simsr_h[IPL_TTY] |= sc->sc_simsr_h[IPL_NET];
@@ -227,31 +226,40 @@ intr_establish(int ivec, int type, int level,
int (*ih_fun)(void *), void *ih_arg, const char *name)
{
struct ipic_softc *sc = ipic_sc;
- struct intrhand **p, *q, *ih;
+ struct intrhand *ih;
+ struct intrq *iq;
uint32_t mask;
+ int s;
ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
if (ih == NULL)
panic("%s: malloc failed", __func__);
+ iq = &ipic_handler[ivec];
if (ivec < 0 || ivec >= IPIC_NVEC)
panic("%s: invalid vector %d", __func__, ivec);
- for (p = &ipic_intrhand[ivec]; (q = *p) != NULL; p = &q->ih_next)
- ;
-
sc->sc_simsr_h[level] |= ipic_simsr_h(ivec);
sc->sc_simsr_l[level] |= ipic_simsr_l(ivec);
sc->sc_semsr[level] |= ipic_semsr(ivec);
- intr_calculatemasks();
ih->ih_fun = ih_fun;
ih->ih_arg = ih_arg;
- ih->ih_next = NULL;
ih->ih_level = level;
ih->ih_irq = ivec;
- evcount_attach(&ih->ih_count, name, NULL, &evcount_intr);
- *p = ih;
+
+ evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
+ &evcount_intr);
+
+ /*
+ * Append handler to end of list
+ */
+ s = ppc_intr_disable();
+
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
+ ipic_calc_masks();
+
+ ppc_intr_enable(s);
/* Unmask the interrupt. */
mask = ipic_read(sc, IPIC_SIMSR_H);
@@ -273,31 +281,19 @@ ext_intr(void)
struct cpu_info *ci = curcpu();
struct ipic_softc *sc = ipic_sc;
struct intrhand *ih;
- uint32_t simsr_h, simsr_l, semsr;
- int pcpl, ocpl;
+ struct intrq *iq;
+ int pcpl;
int ivec;
pcpl = ci->ci_cpl;
ivec = ipic_read(sc, IPIC_SIVCR) & 0x7f;
- simsr_h = ipic_read(sc, IPIC_SIMSR_H);
- simsr_l = ipic_read(sc, IPIC_SIMSR_L);
- semsr = ipic_read(sc, IPIC_SEMSR);
- ipic_write(sc, IPIC_SIMSR_H, simsr_h & ~ipic_simsr_h(ivec));
- ipic_write(sc, IPIC_SIMSR_L, simsr_l & ~ipic_simsr_l(ivec));
- ipic_write(sc, IPIC_SEMSR, semsr & ~ipic_semsr(ivec));
-
- ih = ipic_intrhand[ivec];
- while (ih) {
- if (ci->ci_cpl & (1 << ih->ih_level)) {
- ci->ci_ipending |= (1 << ih->ih_level);
- return;
- }
+ iq = &ipic_handler[ivec];
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ if (ih->ih_level < pcpl)
+ continue;
- ipic_write(sc, IPIC_SIMSR_H, sc->sc_simsr_h[ih->ih_level]);
- ipic_write(sc, IPIC_SIMSR_L, sc->sc_simsr_l[ih->ih_level]);
- ipic_write(sc, IPIC_SEMSR, sc->sc_semsr[ih->ih_level]);
- ocpl = splraise(imask[ih->ih_level]);
+ ipic_splraise(ih->ih_level);
ppc_intr_enable(1);
KERNEL_LOCK();
@@ -306,40 +302,111 @@ ext_intr(void)
KERNEL_UNLOCK();
ppc_intr_disable();
- ci->ci_cpl = ocpl;
- ih = ih->ih_next;
}
- ipic_write(sc, IPIC_SIMSR_H, simsr_h);
- ipic_write(sc, IPIC_SIMSR_L, simsr_l);
- ipic_write(sc, IPIC_SEMSR, semsr);
splx(pcpl);
}
-static __inline int
-cntlzw(int x)
+int
+ipic_splraise(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ if (ocpl > newcpl)
+ newcpl = ocpl;
+
+ ipic_setipl(newcpl);
+
+ return (ocpl);
+}
+
+int
+ipic_spllower(int newcpl)
{
- int a;
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ ipic_splx(newcpl);
+
+ return (ocpl);
+}
- __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x));
+void
+ipic_splx(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
- return a;
+ ipic_setipl(newcpl);
+ if (ci->ci_ipending & ppc_smask[newcpl])
+ ipic_do_pending(newcpl);
}
void
-ipic_do_pending_int(void)
+ipic_setipl(int ipl)
{
struct cpu_info *ci = curcpu();
struct ipic_softc *sc = ipic_sc;
uint32_t mask;
- int level;
+ int s;
- ci->ci_ipending &= SINT_MASK;
- level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCK|SINT_MASK)));
- mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[level];
+ s = ppc_intr_disable();
+ ci->ci_cpl = ipl;
+ mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[ipl];
ipic_write(sc, IPIC_SIMSR_H, mask);
- mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[level];
+ mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[ipl];
ipic_write(sc, IPIC_SIMSR_L, mask);
- mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[level];
+ mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[ipl];
ipic_write(sc, IPIC_SEMSR, mask);
+ ppc_intr_enable(s);
+}
+
+void
+ipic_do_pending(int pcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int s;
+
+ s = ppc_intr_disable();
+ 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 & SI_TO_IRQBIT(SI_SOFTNET)) &&
+ (pcpl < IPL_SOFTNET)) {
+ extern int netisr;
+ int pisr;
+
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
+ ci->ci_cpl = IPL_SOFTNET;
+ ppc_intr_enable(s);
+ KERNEL_LOCK();
+ while ((pisr = netisr) != 0) {
+ atomic_clearbits_int(&netisr, pisr);
+ softnet(pisr);
+ }
+ KERNEL_UNLOCK();
+ ppc_intr_disable();
+ continue;
+ }
+ 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(s);
+ KERNEL_LOCK();
+ softclock();
+ KERNEL_UNLOCK();
+ ppc_intr_disable();
+ continue;
+ }
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
+ ipic_setipl(pcpl); /* Don't use splx... we are here already! */
+
+ atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
+ ppc_intr_enable(s);
}
diff --git a/sys/arch/socppc/socppc/machdep.c b/sys/arch/socppc/socppc/machdep.c
index bf8298c7330..1743306806d 100644
--- a/sys/arch/socppc/socppc/machdep.c
+++ b/sys/arch/socppc/socppc/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.9 2009/02/17 20:35:47 kettenis Exp $ */
+/* $OpenBSD: machdep.c,v 1.10 2009/06/02 21:38:10 drahn Exp $ */
/* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */
/*
@@ -1088,67 +1088,9 @@ boot(int howto)
while(1) /* forever */;
}
-extern void ipic_do_pending_int(void);
-
void
do_pending_int(void)
{
- struct cpu_info *ci = curcpu();
- int pcpl, s;
-
- if (ci->ci_iactive)
- return;
-
- ci->ci_iactive = 1;
- s = ppc_intr_disable();
- pcpl = ci->ci_cpl;
-
- ipic_do_pending_int();
-
- 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);
- KERNEL_LOCK();
- softclock();
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
- }
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
- extern int netisr;
- int pisr;
-
- ci->ci_ipending &= ~SINT_NET;
- ci->ci_cpl = SINT_NET|SINT_TTY;
- while ((pisr = netisr) != 0) {
- atomic_clearbits_int(&netisr, pisr);
- ppc_intr_enable(1);
- KERNEL_LOCK();
- softnet(pisr);
- KERNEL_UNLOCK();
- ppc_intr_disable();
- }
- continue;
- }
-#if 0
- if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
- ci->ci_ipending &= ~SINT_TTY;
- ci->ci_cpl = SINT_TTY;
- ppc_intr_enable(1);
- KERNEL_LOCK();
- softtty();
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
- }
-#endif
- } while ((ci->ci_ipending & SINT_MASK) & ~pcpl);
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
-
- ci->ci_iactive = 0;
- ppc_intr_enable(s);
}
/*