powerpc interrupt rewrite.

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

powerpc interrupt rewrite.

Dale Rahn
At c2k11 I managed to revive the powerpc (macppc/socppc) interrupt
rewrite from a few years ago. It had been backed out because of problems
attributed to other previously fixed bugs. At some prodding the dust
was blown off the diff and it is working on at least two machines.

Please test and see if it works and prevents the 'wdc timeout'
error that occurs frequently.

Index: macppc/dev/macintr.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/dev/macintr.c,v
retrieving revision 1.42
diff -u -p -r1.42 macintr.c
--- macppc/dev/macintr.c 15 Apr 2011 20:52:55 -0000 1.42
+++ macppc/dev/macintr.c 7 Jul 2011 21:26:19 -0000
@@ -1,6 +1,7 @@
 /* $OpenBSD: macintr.c,v 1.42 2011/04/15 20:52:55 deraadt Exp $ */
 
 /*-
+ * Copyright (c) 2008 Dale Rahn <[hidden email]>
  * 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 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, const 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,52 +296,41 @@ 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:
  intr_shared_edge = 1;
  /* FALLTHROUGH */
  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)
- ;
+ ih->ih_fun = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_level = level;
+ ih->ih_irq = irq;
+ evcount_attach(&ih->ih_count, name, &ih->ih_irq);
 
  /*
- * 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();
 
- intr_calculatemasks();
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
+ macintr_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, &m_hwirq[irq]);
- *p = ih;
+ macintr_setipl(ci->ci_cpl);
+ ppc_intr_enable(s);
 
  return (ih);
 }
@@ -302,195 +341,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;
- cpu_imask[level] = irqs | SINT_ALLMASK;
+ 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.
- */
- cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
- cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
- cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
- cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
-
- /*
- * These are pseudo-levels.
- */
- cpu_imask[IPL_NONE] = 0x00000000;
- cpu_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 |= cpu_imask[q->ih_level];
- m_intrmask[irq] = irqs | SINT_ALLMASK;
- }
-
- /* 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. */
+ iq->iq_ipl = maxipl;
 
- 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;
+ if (maxipl == IPL_NONE) {
+ minipl = IPL_NONE; /* Interrupt not enabled */
+ } else {
+ for (i = minipl; i <= maxipl; i++)
+ macintr_pri_share[i] = i;
+ }
 
-/*
- * Map 64 irqs into 32 (bits).
- */
-static int
-mapirq(int irq)
-{
- int v;
- int i;
+ /* Enable interrupts at lower levels */
 
- if (m_virq_inited == 0) {
- m_virq_max = 0;
- for (i = 0; i < ICU_LEN; i++) {
- m_virq[i] = 0;
+ 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;
 }
 
 /*
@@ -500,141 +437,118 @@ void
 mac_ext_intr()
 {
  int irq = 0;
- int o_imen, r_imen;
  int pcpl, ret;
  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;
-
- 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]);
+ irq = macintr_read_irq();
+ while (irq != 255) {
+ iq = &macintr_handler[irq];
+ macintr_setipl(iq->iq_ipl);
 
- ih = m_intrhand[irq];
- while (ih) {
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ ppc_intr_enable(1);
  ret = ((*ih->ih_fun)(ih->ih_arg));
  if (ret) {
  ih->ih_count.ec_count++;
  if (intr_shared_edge == 0 && ret == 1)
  break;
  }
- 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;
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
+    (pcpl < IPL_SOFTCLOCK)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
  softintr_dispatch(SI_SOFTCLOCK);
- }
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
- ci->ci_ipending &= ~SINT_NET;
+ }
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
+    (pcpl < IPL_SOFTNET)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
  softintr_dispatch(SI_SOFTNET);
  }
- if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
- ci->ci_ipending &= ~SINT_TTY;
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
+    (pcpl < IPL_SOFTTTY)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
  softintr_dispatch(SI_SOFTTTY);
  }
- } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
- ci->ci_ipending &= pcpl;
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
+
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
+ macintr_setipl(pcpl);
  ppc_intr_enable(s);
- ci->ci_iactive = 0;
+
+ 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;
 }
Index: macppc/dev/openpic.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/dev/openpic.c,v
retrieving revision 1.64
diff -u -p -r1.64 openpic.c
--- macppc/dev/openpic.c 15 Apr 2011 20:52:55 -0000 1.64
+++ macppc/dev/openpic.c 7 Jul 2011 21:38:05 -0000
@@ -1,6 +1,7 @@
 /* $OpenBSD: openpic.c,v 1.64 2011/04/15 20:52:55 deraadt Exp $ */
 
 /*-
+ * Copyright (c) 2008 Dale Rahn <[hidden email]>
  * Copyright (c) 1995 Per Fogelstrom
  * Copyright (c) 1993, 1994 Charles M. Hannum.
  * Copyright (c) 1990 The Regents of the University of California.
@@ -56,22 +57,18 @@
 #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);
-void openpic_enable_irq_mask(int irq_mask);
 
-#define HWIRQ_MAX (31 - (SI_NQUEUES + 1))
-#define HWIRQ_MASK (0xffffffff >> (SI_NQUEUES + 1))
+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
@@ -82,17 +79,34 @@ static struct evcount ipi_nop[PPC_MAXPRO
 static int ipi_nopirq = IPI_VECTOR_NOP;
 static int ipi_ddbirq = IPI_VECTOR_DDB;
 #endif
+struct evcount openpic_spurious;
+int openpic_spurious_irq = 255;
+
+void openpic_enable_irq(int, int);
+void openpic_disable_irq(int);
+void openpic_init(void);
+void openpic_set_priority(int, int);
+void openpic_ipi_ddb(void);
+void *openpic_intr_establish(void *, int, int, int, int (*)(void *),
+    void *, const char *);
+
+typedef void  (void_f) (void);
+extern void_f *pending_int_f;
+
+vaddr_t openpic_base;
+#if 0
+void * openpic_intr_establish( void * lcv, int irq, int type, int level,
+    int (*ih_fun)(void *), void *ih_arg, const char *name);
+#endif
+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
 
-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_ipi_ddb(void);
-static __inline int openpic_read_irq(int);
-static __inline void openpic_eoi(int);
+u_int openpic_read(int reg);
+void openpic_write(int reg, u_int val);
 
 struct openpic_softc {
  struct device sc_dev;
@@ -100,9 +114,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),
@@ -114,6 +129,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)
 {
@@ -141,22 +192,10 @@ openpic_match(struct device *parent, voi
  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, const 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;
 
@@ -167,12 +206,16 @@ openpic_attach(struct device *parent, st
  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;
@@ -180,18 +223,66 @@ openpic_attach(struct device *parent, st
 #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", &openpic_spurious_irq);
+
+ ppc_intr_func.raise = openpic_splraise;
+ ppc_intr_func.lower = openpic_spllower;
+ ppc_intr_func.x = openpic_splx;
+
+ openpic_set_priority(0, 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(ci->ci_cpuid, 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()
@@ -211,13 +302,6 @@ openpic_collect_preconf_intr()
  }
 }
 
-static int
-fakeintr(void *arg)
-{
-
- return 0;
-}
-
 /*
  * Register an interrupt handler.
  */
@@ -225,75 +309,53 @@ void *
 openpic_intr_establish(void *lcv, int irq, int type, int level,
     int (*ih_fun)(void *), void *ih_arg, const 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:
  intr_shared_edge = 1;
  /* FALLTHROUGH */
  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, &ih->ih_irq);
 
  /*
- * 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, &o_hwirq[irq]);
- *p = ih;
+ ppc_intr_enable(s);
 
  return (ih);
 }
@@ -306,51 +368,27 @@ openpic_intr_disestablish(void *lcp, voi
 {
  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;
 }
 
 /*
@@ -363,260 +401,111 @@ 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(ci->ci_cpuid, 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;
- }
- }
-
- o_intrmaxlvl[irq] = max;
+ for (i = IPL_NONE; i < IPL_NUM; i++) {
+ openpic_pri_share[i] = i;
+ }
 
- /* 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) );
+ for (irq = 0; irq < openpic_numirq; irq++) {
+ int maxipl = IPL_NONE;
+ int minipl = IPL_HIGH;
+ struct intrq *iq = &openpic_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;
  }
 
- 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++)
- cpu_imask[i] &= ~(1 << o_virq[irq]);
- for (; i <= IPL_HIGH; i++)
- cpu_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)
- cpu_imask[i] |= SINT_ALLMASK;
- if (i >= IPL_CLOCK)
- cpu_imask[i] |= SPL_CLOCKMASK;
+ iq->iq_ipl = maxipl;
  }
- cpu_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_cpuid, 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 & ~cpu_imask[pri];
- if (pripending == 0)
- continue;
- irq = 31 - cntlzw(pripending);
- ci->ci_ipending &= ~(1 << irq);
- ci->ci_cpl = cpu_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_ALLMASK;
- 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();
 
- 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);
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
+    (pcpl < IPL_SOFTCLOCK)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
  softintr_dispatch(SI_SOFTCLOCK);
- ppc_intr_disable();
- continue;
- }
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
- ci->ci_ipending &= ~SINT_NET;
- ci->ci_cpl = SINT_NET|SINT_TTY;
- ppc_intr_enable(1);
+ }
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
+    (pcpl < IPL_SOFTNET)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
  softintr_dispatch(SI_SOFTNET);
- 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_SOFTTTY)) &&
+    (pcpl < IPL_SOFTTTY)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
  softintr_dispatch(SI_SOFTTTY);
- ppc_intr_disable();
- continue;
  }
- } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
+ } 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)
-{
- 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);
 }
 
@@ -633,29 +522,10 @@ 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_write(OPENPIC_EOI(cpu), 0);
- openpic_read(OPENPIC_EOI(cpu));
+ openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
 }
 
 #ifdef MULTIPROCESSOR
-
 void
 openpic_send_ipi(struct cpu_info *ci, int id)
 {
@@ -670,107 +540,150 @@ openpic_send_ipi(struct cpu_info *ci, in
  panic("invalid ipi send to cpu %d %d", 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, ret;
- int pcpl, ocpl;
+ int irq, pcpl, ret;
+ 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];
 
- 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)));
+ if (iq->iq_ipl > maxipl)
+ maxipl = iq->iq_ipl;
+ splraise(iq->iq_ipl);
+ openpic_eoi(ci->ci_cpuid);
 
- /* XXX check range */
+ spurious = 1;
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ ppc_intr_enable(1);
+ KERNEL_LOCK();
+ ret = (*ih->ih_fun)(ih->ih_arg);
+ if (ret) {
+ ih->ih_count.ec_count++;
+ spurious = 0;
+ }
+ KERNEL_UNLOCK();
+
+ (void)ppc_intr_disable();
+ if (intr_shared_edge == 00 && ret == 1)
+ break;
+ }
+ if (spurious) {
+ openpic_spurious.ec_count++;
+#ifdef OPENPIC_NOISY
+ printf("spurious intr %d\n", irq);
+#endif
+ }
 
- r_imen = 1 << irq;
+ uvmexp.intrs++;
+ openpic_setipl(pcpl);
 
- if ((pcpl & r_imen) != 0) {
- /* Masked! Mark this as pending. */
- ci->ci_ipending |= r_imen;
- openpic_enable_irq_mask(~cpu_imask[o_intrmaxlvl[realirq]]);
- openpic_eoi(ci->ci_cpuid);
- } else {
- openpic_enable_irq_mask(~cpu_imask[o_intrmaxlvl[realirq]]);
- openpic_eoi(ci->ci_cpuid);
- ocpl = splraise(cpu_imask[o_intrmaxlvl[realirq]]);
+ irq = openpic_read_irq(ci->ci_cpuid);
+ }
 
- ih = o_intrhand[irq];
- while (ih) {
- ppc_intr_enable(1);
-
- KERNEL_LOCK();
- ret = (*ih->ih_fun)(ih->ih_arg);
- if (ret)
- ih->ih_count.ec_count++;
- KERNEL_UNLOCK();
-
- (void)ppc_intr_disable();
- if (intr_shared_edge == 00 && ret == 1)
- break;
- 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(ci->ci_cpuid, 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;
@@ -780,6 +693,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 */
@@ -793,31 +717,33 @@ 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", &ipi_nopirq);
  evcount_attach(&ipi_nop[1], "ipi_nop1", &ipi_nopirq);
  evcount_attach(&ipi_ddb[0], "ipi_ddb0", &ipi_ddbirq);
  evcount_attach(&ipi_ddb[1], "ipi_ddb1", &ipi_ddbirq);
 #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(ci->ci_cpuid, 0);
 }
 
 void
-openpic_ipi_ddb(void)
+openpic_ipi_ddb()
 {
+#ifdef OPENPIC_NOISY
+ printf("ipi_ddb() called\n");
+#endif
  Debugger();
 }
-
Index: macppc/macppc/clock.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/macppc/clock.c,v
retrieving revision 1.31
diff -u -p -r1.31 clock.c
--- macppc/macppc/clock.c 20 Sep 2010 06:33:47 -0000 1.31
+++ macppc/macppc/clock.c 7 Jul 2011 04:23:40 -0000
@@ -225,7 +225,7 @@ decr_intr(struct clockframe *frame)
  */
  ppc_mtdec(nextevent - tb);
 
- if (ci->ci_cpl & SPL_CLOCKMASK) {
+ if (ci->ci_cpl >= IPL_CLOCK) {
  ci->ci_statspending += nstats;
  } else {
  KERNEL_LOCK();
Index: macppc/macppc/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/macppc/machdep.c,v
retrieving revision 1.130
diff -u -p -r1.130 machdep.c
--- macppc/macppc/machdep.c 5 Jul 2011 04:48:01 -0000 1.130
+++ macppc/macppc/machdep.c 7 Jul 2011 05:09:43 -0000
@@ -823,8 +823,6 @@ dumpsys()
 
 }
 
-int cpu_imask[IPL_NUM];
-
 int
 lcsplx(int ipl)
 {
Index: powerpc/include/intr.h
===================================================================
RCS file: /cvs/src/sys/arch/powerpc/include/intr.h,v
retrieving revision 1.46
diff -u -p -r1.46 intr.h
--- powerpc/include/intr.h 8 Jan 2011 18:10:20 -0000 1.46
+++ powerpc/include/intr.h 7 Jul 2011 21:19:38 -0000
@@ -2,7 +2,7 @@
 
 /*
  * 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,15 +36,19 @@
 #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_SCHED 6
-#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_SCHED 10
+#define IPL_HIGH 11
+#define IPL_NUM 12
 
 #define IST_NONE 0
 #define IST_PULSE 1
@@ -56,41 +60,57 @@
 #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
 
 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);
+
+extern struct ppc_intr_func {
+ ppc_splraise_t *raise;
+ ppc_spllower_t *lower;
+ ppc_splx_t *x;
+}ppc_intr_func;
 
-void do_pending_int(void);
+extern int ppc_smask[IPL_NUM];
+
+void ppc_smask_init(void);
+char *ppc_intr_typename(int type);
 
-extern int cpu_imask[IPL_NUM];
+void do_pending_int(void);
 
 /* SPL asserts */
 #define splassert(wantipl) /* nothing */
 #define splsoftassert(wantipl) /* nothing */
 
-#define SINTBIT(q) (31 - (q))
-#define SINTMASK(q) (1 << SINTBIT(q))
-
-#define SPL_CLOCKMASK SINTMASK(SI_NQUEUES)
-
-/* Soft interrupt masks. */
+#define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p)
 
-#define IPL_SOFTCLOCK 0
-#define IPL_SOFTNET 1
-#define IPL_SOFTTTY 2
+#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 SI_TO_IRQBIT(x) (1 << (x))
+
+#define SI_SOFTCLOCK 0 /* for IPL_SOFTCLOCK */
+#define SI_SOFTNET 1 /* for IPL_SOFTNET */
+#define SI_SOFTTTY 2 /* for IPL_SOFTSERIAL */
 
-#define SI_SOFTCLOCK 0 /* for IPL_SOFTCLOCK */
-#define SI_SOFTNET 1 /* for IPL_SOFTNET */
-#define SI_SOFTTTY 2 /* for IPL_SOFTTY */
-
-#define SINT_ALLMASK (SINTMASK(SI_SOFTCLOCK) | \
- SINTMASK(SI_SOFTNET) | SINTMASK(SI_SOFTTTY))
-#define SI_NQUEUES 3
+#define SI_NQUEUES 3
 
 #include <machine/mutex.h>
 #include <sys/queue.h>
@@ -109,38 +129,29 @@ struct soft_intrq {
  struct mutex siq_mtx;
 };
 
-void softintr_disestablish(void *);
-void softintr_dispatch(int);
+
+void softintr_disestablish(void *);
+void softintr_dispatch(int);
 void *softintr_establish(int, void (*)(void *), void *);
-void softintr_init(void);
-void softintr_schedule(void *);
+void softintr_init(void);
+
+void softintr_schedule(void *);
 
-#define SINT_CLOCK SINTMASK(SI_SOFTCLOCK)
-#define SINT_NET SINTMASK(SI_SOFTNET)
-#define SINT_TTY SINTMASK(SI_SOFTTTY)
-
-#define splbio() splraise(cpu_imask[IPL_BIO])
-#define splnet() splraise(cpu_imask[IPL_NET])
-#define spltty() splraise(cpu_imask[IPL_TTY])
-#define splaudio() splraise(cpu_imask[IPL_AUDIO])
-#define splclock() splraise(cpu_imask[IPL_CLOCK])
-#define splvm() splraise(cpu_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 set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p)
 
-#define splhigh() splraise(0xffffffff)
-#define spl0() spllower(0)
+#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;
@@ -148,10 +159,16 @@ struct intrhand {
  int ih_irq;
  const 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 PPC_IPI_NOP 0
 #define PPC_IPI_DDB 1
Index: powerpc/powerpc/intr.c
===================================================================
RCS file: /cvs/src/sys/arch/powerpc/powerpc/intr.c,v
retrieving revision 1.6
diff -u -p -r1.6 intr.c
--- powerpc/powerpc/intr.c 9 Jun 2009 01:12:38 -0000 1.6
+++ powerpc/powerpc/intr.c 7 Jul 2011 23:42:40 -0000
@@ -36,44 +36,114 @@
 #include <machine/cpu.h>
 #include <machine/intr.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 (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)
 {
- struct cpu_info *ci = curcpu();
- int oldcpl;
+ 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");
+        oldcpl = ci->ci_cpl;
+        if (newcpl < oldcpl)
+                newcpl = oldcpl;
+        ci->ci_cpl = newcpl;
 
- return (oldcpl);
+        return (oldcpl);
 }
 
 int
-spllower(int newcpl)
+ppc_dflt_spllower(int newcpl)
 {
- struct cpu_info *ci = curcpu();
- int oldcpl;
+        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");
+        oldcpl = ci->ci_cpl;
 
- return (oldcpl);
+        splx(newcpl);
+
+        return (oldcpl);
 }
 
 void
-splx(int newcpl)
+ppc_dflt_splx(int newcpl)
 {
- struct cpu_info *ci = curcpu();
+        struct cpu_info *ci = curcpu();
 
- __asm__ volatile("":::"memory"); /* reorder protect */
- ci->ci_cpl = newcpl;
- if (ci->ci_ipending & ~newcpl)
+        ci->ci_cpl = 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");
+ }
 }
Index: powerpc/powerpc/mutex.S
===================================================================
RCS file: /cvs/src/sys/arch/powerpc/powerpc/mutex.S,v
retrieving revision 1.12
diff -u -p -r1.12 mutex.S
--- powerpc/powerpc/mutex.S 8 Jan 2011 18:10:22 -0000 1.12
+++ powerpc/powerpc/mutex.S 7 Jul 2011 23:15:09 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: mutex.S,v 1.12 2011/01/08 18:10:22 deraadt Exp $ */
+/* $OpenBSD: mutex.S,v 1.13 2011/07/07 05:43:48 drahn Exp $ */
 
 /*
  * Copyright (c) 2007 Dale Rahn
@@ -33,19 +33,16 @@ ENTRY(mtx_init)
 
 
 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(cpu_imask)@ha # convert into cpl
- slwi %r5,%r5,2
- addi %r5,%r5,_C_LABEL(cpu_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
@@ -55,12 +52,12 @@ ENTRY(mtx_enter)
  cmpl 0,%r4,%r6
  beq- .L_mutex_selflocked
 #endif
- stw %r3,28(%r1) # save mtx during lcsplx
- la %r4,28(%r1)
+ 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:
@@ -72,9 +69,9 @@ ENTRY(mtx_enter)
  stw %r6,CI_MUTEX_LEVEL(%r4)
 #endif
  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
@@ -89,18 +86,15 @@ ENTRY(mtx_enter)
 
 
 ENTRY(mtx_enter_try)
- 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
+ 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(cpu_imask)@ha # convert into cpl
- slwi %r5,%r5,2
- addi %r5,%r5,_C_LABEL(cpu_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
@@ -110,16 +104,16 @@ ENTRY(mtx_enter_try)
  cmpl 0,%r4,%r6
  beq- .L_mutex_try_selflocked
 #endif
- stw %r3,28(%r1) # save mtx during lcsplx
- la %r4,28(%r1)
+ 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 %r0,36(%r1) # load return address
+ lwz %r0,20(%r1) # load return address
  mtlr %r0
- addi %r1,%r1,32 # restore stack
- li %r2,0 # return zero
+ addi %r1,%r1,16 # restore stack
+ li %r3,0 # return zero
  blr
 
 .L_mutex_try_free:
@@ -131,10 +125,10 @@ ENTRY(mtx_enter_try)
  stw %r6,CI_MUTEX_LEVEL(%r4)
 #endif
  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
- li %r2,1 # return nonzero
+ addi %r1,%r1,16 # restore stack
+ li %r3,1 # return nonzero
  blr
 
 #ifdef DIAGNOSTIC
@@ -151,7 +145,7 @@ ENTRY(mtx_enter_try)
 ENTRY(mtx_leave)
 #ifdef DIAGNOSTIC
  lwz %r6,MTX_OWNER(%r3)
- cmpwi   0,%r6,0                         # test owner == 0
+ cmpwi   0,%r6,0 # test owner == 0
 
  beq- .L_mutex_notlocked
 #endif
Index: powerpc/powerpc/softintr.c
===================================================================
RCS file: /cvs/src/sys/arch/powerpc/powerpc/softintr.c,v
retrieving revision 1.3
diff -u -p -r1.3 softintr.c
--- powerpc/powerpc/softintr.c 21 Dec 2010 14:56:24 -0000 1.3
+++ powerpc/powerpc/softintr.c 7 Jul 2011 21:20:55 -0000
@@ -170,7 +170,7 @@ softintr_schedule(void *arg)
  if (sih->sih_pending == 0) {
  TAILQ_INSERT_TAIL(&siq->siq_list, sih, sih_list);
  sih->sih_pending = 1;
- atomic_setbits_int(&ci->ci_ipending, SINTMASK(siq->siq_si));
+ atomic_setbits_int(&ci->ci_ipending, SI_TO_IRQBIT(siq->siq_si));
  }
  mtx_leave(&siq->siq_mtx);
 }
Index: socppc/dev/ipic.c
===================================================================
RCS file: /cvs/src/sys/arch/socppc/dev/ipic.c,v
retrieving revision 1.14
diff -u -p -r1.14 ipic.c
--- socppc/dev/ipic.c 8 Jan 2011 18:10:22 -0000 1.14
+++ socppc/dev/ipic.c 7 Jul 2011 05:51:38 -0000
@@ -65,7 +65,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 *);
@@ -84,10 +84,17 @@ void ipic_write(struct ipic_softc *, bus
 uint32_t ipic_simsr_h(int);
 uint32_t ipic_simsr_l(int);
 uint32_t ipic_semsr(int);
+void ipic_calc_masks(void);
 
-void intr_calculatemasks(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)
@@ -108,6 +115,8 @@ ipic_attach(struct device *parent, struc
  struct ipic_softc *sc = (void *)self;
  struct obio_attach_args *oa = aux;
  int ivec;
+ 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)) {
@@ -120,6 +129,11 @@ ipic_attach(struct device *parent, struc
  /*
  * Deal with pre-established interrupts.
  */
+ for (i = 0; i < IPIC_NVEC; i++) {
+ iq = &ipic_handler[i];
+ TAILQ_INIT(&iq->iq_list);
+ }
+
  for (ivec = 0; ivec < IPIC_NVEC; ivec++) {
  if (ipic_intrhand[ivec]) {
  int level = ipic_intrhand[ivec]->ih_level;
@@ -143,6 +157,11 @@ ipic_attach(struct device *parent, struc
  }
  }
 
+ ppc_smask_init();
+ ppc_intr_func.raise = ipic_splraise;
+ ppc_intr_func.lower = ipic_spllower;
+ ppc_intr_func.x = ipic_splx;
+
  printf("\n");
 }
 
@@ -217,31 +236,9 @@ ipic_semsr(int ivec)
 }
 
 void
-intr_calculatemasks(void)
+ipic_calc_masks(void)
 {
  struct ipic_softc *sc = ipic_sc;
- int level;
-
- for (level = IPL_NONE; level < IPL_NUM; level++)
- cpu_imask[level] = SINT_ALLMASK | (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.
- */
- cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
- cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
- cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
- cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
-
- /*
- * These are pseudo-levels.
- */
- cpu_imask[IPL_NONE] = 0x00000000;
- cpu_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];
@@ -267,36 +264,44 @@ intr_establish(int ivec, int type, int l
     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)
- ;
-
  if (sc) {
  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);
- *p = ih;
 
+ evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+ /*
+ * 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. */
  if (sc) {
- /* Unmask the interrupt. */
  mask = ipic_read(sc, IPIC_SIMSR_H);
  mask |= ipic_simsr_h(ivec);
  ipic_write(sc, IPIC_SIMSR_H, mask);
@@ -317,31 +322,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(cpu_imask[ih->ih_level]);
+ ipic_splraise(ih->ih_level);
  ppc_intr_enable(1);
 
  KERNEL_LOCK();
@@ -350,40 +343,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)
 {
- int a;
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ if (ocpl > newcpl)
+ newcpl = ocpl;
 
- __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x));
+ ipic_setipl(newcpl);
 
- return a;
+ return (ocpl);
+}
+
+int
+ipic_spllower(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ ipic_splx(newcpl);
+
+ return (ocpl);
 }
 
 void
-ipic_do_pending_int(void)
+ipic_splx(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+
+ ipic_setipl(newcpl);
+ if (ci->ci_ipending & ppc_smask[newcpl])
+ ipic_do_pending(newcpl);
+}
+
+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_ALLMASK;
- level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCKMASK|SINT_ALLMASK)));
- 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);
 }
Index: socppc/socppc/clock.c
===================================================================
RCS file: /cvs/src/sys/arch/socppc/socppc/clock.c,v
retrieving revision 1.8
diff -u -p -r1.8 clock.c
--- socppc/socppc/clock.c 20 Sep 2010 06:33:48 -0000 1.8
+++ socppc/socppc/clock.c 7 Jul 2011 04:23:42 -0000
@@ -202,7 +202,7 @@ decr_intr(struct clockframe *frame)
  */
  ppc_mtdec(nextevent - tb);
 
- if (curcpu()->ci_cpl & SPL_CLOCKMASK) {
+ if (ci->ci_cpl >= IPL_CLOCK) {
  ci->ci_statspending += nstats;
  } else {
  KERNEL_LOCK();
Index: socppc/socppc/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/socppc/socppc/machdep.c,v
retrieving revision 1.32
diff -u -p -r1.32 machdep.c
--- socppc/socppc/machdep.c 5 Jul 2011 04:48:02 -0000 1.32
+++ socppc/socppc/machdep.c 7 Jul 2011 06:06:38 -0000
@@ -1095,59 +1095,41 @@ 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;
+ int pcpl = ci->ci_cpl; /* XXX */
+ int s;
  s = ppc_intr_disable();
- pcpl = ci->ci_cpl;
-
- ipic_do_pending_int();
+ 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);
- KERNEL_LOCK();
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
+    (pcpl < IPL_SOFTCLOCK)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
  softintr_dispatch(SI_SOFTCLOCK);
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
- }
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
- ci->ci_ipending &= ~SINT_NET;
- ci->ci_cpl = SINT_NET|SINT_TTY;
- ppc_intr_enable(1);
- KERNEL_LOCK();
+ }
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
+    (pcpl < IPL_SOFTNET)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
  softintr_dispatch(SI_SOFTNET);
- 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);
- KERNEL_LOCK();
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
+    (pcpl < IPL_SOFTTTY)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
  softintr_dispatch(SI_SOFTTTY);
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
  }
- } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
 
- ci->ci_iactive = 0;
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
+ macintr_setipl(pcpl);
  ppc_intr_enable(s);
+
+ atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
 }
 
 /*

Dale Rahn [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: powerpc interrupt rewrite.

Bob Beck-4
This works on my g4 - which was previously damn near unusable with
GENERIC.MP.

It would please me greatly if we could get a few more test reports on this
to dale - even if your machine does not have the wdc timeout problem,
as we need to know if this breaks other macppc's


On 7 July 2011 18:30, Dale Rahn <[hidden email]> wrote:

> At c2k11 I managed to revive the powerpc (macppc/socppc) interrupt
> rewrite from a few years ago. It had been backed out because of problems
> attributed to other previously fixed bugs. At some prodding the dust
> was blown off the diff and it is working on at least two machines.
>
> Please test and see if it works and prevents the 'wdc timeout'
> error that occurs frequently.
>
> Index: macppc/dev/macintr.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/dev/macintr.c,v
> retrieving revision 1.42
> diff -u -p -r1.42 macintr.c
> --- macppc/dev/macintr.c        15 Apr 2011 20:52:55 -0000      1.42
> +++ macppc/dev/macintr.c        7 Jul 2011 21:26:19 -0000
> @@ -1,6 +1,7 @@
>  /*     $OpenBSD: macintr.c,v 1.42 2011/04/15 20:52:55 deraadt Exp $    */
>
>  /*-
> + * Copyright (c) 2008 Dale Rahn <[hidden email]>
>  * 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   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, const 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,52 +296,41 @@ 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:
>                intr_shared_edge = 1;
>                /* FALLTHROUGH */
>        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)
> -               ;
> +       ih->ih_fun = ih_fun;
> +       ih->ih_arg = ih_arg;
> +       ih->ih_level = level;
> +       ih->ih_irq = irq;
> +       evcount_attach(&ih->ih_count, name, &ih->ih_irq);
>
>        /*
> -        * 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();
>
> -       intr_calculatemasks();
> +       TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
> +       macintr_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, &m_hwirq[irq]);
> -       *p = ih;
> +       macintr_setipl(ci->ci_cpl);
> +       ppc_intr_enable(s);
>
>        return (ih);
>  }
> @@ -302,195 +341,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;
> -               cpu_imask[level] = irqs | SINT_ALLMASK;
> +       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.
> -        */
> -       cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
> -       cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
> -       cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
> -       cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
> -
> -       /*
> -        * These are pseudo-levels.
> -        */
> -       cpu_imask[IPL_NONE] = 0x00000000;
> -       cpu_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 |= cpu_imask[q->ih_level];
> -               m_intrmask[irq] = irqs | SINT_ALLMASK;
> -       }
> -
> -       /* 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.
*/

> +               iq->iq_ipl = maxipl;
>
> -       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;
> +               if (maxipl == IPL_NONE) {
> +                       minipl = IPL_NONE; /* Interrupt not enabled */
> +               } else {
> +                       for (i = minipl; i <= maxipl; i++)
> +                               macintr_pri_share[i] = i;
> +               }
>
> -/*
> - * Map 64 irqs into 32 (bits).
> - */
> -static int
> -mapirq(int irq)
> -{
> -       int v;
> -       int i;
> +               /* Enable interrupts at lower levels */
>
> -       if (m_virq_inited == 0) {
> -               m_virq_max = 0;
> -               for (i = 0; i < ICU_LEN; i++) {
> -                       m_virq[i] = 0;
> +               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;
>  }
>
>  /*
> @@ -500,141 +437,118 @@ void
>  mac_ext_intr()
>  {
>        int irq = 0;
> -       int o_imen, r_imen;
>        int pcpl, ret;
>        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;
> -
> -       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]);
> +       irq = macintr_read_irq();
> +       while (irq != 255) {
> +               iq = &macintr_handler[irq];
> +               macintr_setipl(iq->iq_ipl);
>
> -               ih = m_intrhand[irq];
> -               while (ih) {
> +               TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
> +                       ppc_intr_enable(1);
>                        ret = ((*ih->ih_fun)(ih->ih_arg));
>                        if (ret) {
>                                ih->ih_count.ec_count++;
>                                if (intr_shared_edge == 0 && ret == 1)
>                                        break;
>                        }
> -                       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;
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
> +                   (pcpl < IPL_SOFTCLOCK)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
>                        softintr_dispatch(SI_SOFTCLOCK);
> -               }
> -               if((ci->ci_ipending & SINT_NET) & ~pcpl) {
> -                       ci->ci_ipending &= ~SINT_NET;
> +               }
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
> +                   (pcpl < IPL_SOFTNET)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
>                        softintr_dispatch(SI_SOFTNET);
>                }
> -               if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
> -                       ci->ci_ipending &= ~SINT_TTY;
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
> +                   (pcpl < IPL_SOFTTTY)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
>                        softintr_dispatch(SI_SOFTTTY);
>                }
> -       } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
> -       ci->ci_ipending &= pcpl;
> -       ci->ci_cpl = pcpl;      /* Don't use splx... we are here already!
*/

> +
> +       } while (ci->ci_ipending & ppc_smask[pcpl]);
> +       macintr_setipl(pcpl);
>        ppc_intr_enable(s);
> -       ci->ci_iactive = 0;
> +
> +       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;
>  }
> Index: macppc/dev/openpic.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/dev/openpic.c,v
> retrieving revision 1.64
> diff -u -p -r1.64 openpic.c
> --- macppc/dev/openpic.c        15 Apr 2011 20:52:55 -0000      1.64
> +++ macppc/dev/openpic.c        7 Jul 2011 21:38:05 -0000
> @@ -1,6 +1,7 @@
>  /*     $OpenBSD: openpic.c,v 1.64 2011/04/15 20:52:55 deraadt Exp $    */
>
>  /*-
> + * Copyright (c) 2008 Dale Rahn <[hidden email]>
>  * Copyright (c) 1995 Per Fogelstrom
>  * Copyright (c) 1993, 1994 Charles M. Hannum.
>  * Copyright (c) 1990 The Regents of the University of California.
> @@ -56,22 +57,18 @@
>  #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);
> -void openpic_enable_irq_mask(int irq_mask);
>
> -#define HWIRQ_MAX (31 - (SI_NQUEUES + 1))
> -#define HWIRQ_MASK (0xffffffff >> (SI_NQUEUES + 1))
> +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
> @@ -82,17 +79,34 @@ static struct evcount ipi_nop[PPC_MAXPRO
>  static int ipi_nopirq = IPI_VECTOR_NOP;
>  static int ipi_ddbirq = IPI_VECTOR_DDB;
>  #endif
> +struct evcount openpic_spurious;
> +int openpic_spurious_irq = 255;
> +
> +void   openpic_enable_irq(int, int);
> +void   openpic_disable_irq(int);
> +void   openpic_init(void);
> +void   openpic_set_priority(int, int);
> +void   openpic_ipi_ddb(void);
> +void   *openpic_intr_establish(void *, int, int, int, int (*)(void *),
> +    void *, const char *);
> +
> +typedef void  (void_f) (void);
> +extern void_f *pending_int_f;
> +
> +vaddr_t openpic_base;
> +#if 0
> +void * openpic_intr_establish( void * lcv, int irq, int type, int level,
> +    int (*ih_fun)(void *), void *ih_arg, const char *name);
> +#endif
> +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
>
> -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_ipi_ddb(void);
> -static __inline int openpic_read_irq(int);
> -static __inline void openpic_eoi(int);
> +u_int openpic_read(int reg);
> +void openpic_write(int reg, u_int val);
>
>  struct openpic_softc {
>        struct device sc_dev;
> @@ -100,9 +114,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),
> @@ -114,6 +129,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)
>  {
> @@ -141,22 +192,10 @@ openpic_match(struct device *parent, voi
>        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, const 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;
>
> @@ -167,12 +206,16 @@ openpic_attach(struct device *parent, st
>        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;
> @@ -180,18 +223,66 @@ openpic_attach(struct device *parent, st
>  #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",
&openpic_spurious_irq);

> +
> +       ppc_intr_func.raise = openpic_splraise;
> +       ppc_intr_func.lower = openpic_spllower;
> +       ppc_intr_func.x = openpic_splx;
> +
> +       openpic_set_priority(0, 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(ci->ci_cpuid, 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()
> @@ -211,13 +302,6 @@ openpic_collect_preconf_intr()
>        }
>  }
>
> -static int
> -fakeintr(void *arg)
> -{
> -
> -       return 0;
> -}
> -
>  /*
>  * Register an interrupt handler.
>  */
> @@ -225,75 +309,53 @@ void *
>  openpic_intr_establish(void *lcv, int irq, int type, int level,
>     int (*ih_fun)(void *), void *ih_arg, const 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:
>                intr_shared_edge = 1;
>                /* FALLTHROUGH */
>        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, &ih->ih_irq);
>
>        /*
> -        * 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, &o_hwirq[irq]);
> -       *p = ih;
> +       ppc_intr_enable(s);
>
>        return (ih);
>  }
> @@ -306,51 +368,27 @@ openpic_intr_disestablish(void *lcp, voi
>  {
>        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;
>  }
>
>  /*
> @@ -363,260 +401,111 @@ 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(ci->ci_cpuid, 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;
> -                       }
> -               }
> -
> -               o_intrmaxlvl[irq] = max;
> +       for (i = IPL_NONE; i < IPL_NUM; i++) {
> +               openpic_pri_share[i] = i;
> +       }
>
> -               /* 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) );
> +       for (irq = 0; irq < openpic_numirq; irq++) {
> +               int maxipl = IPL_NONE;
> +               int minipl = IPL_HIGH;
> +               struct intrq *iq = &openpic_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;
>                }
>
> -               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++)
> -                               cpu_imask[i] &= ~(1 << o_virq[irq]);
> -                       for (; i <= IPL_HIGH; i++)
> -                               cpu_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)
> -                       cpu_imask[i] |= SINT_ALLMASK;
> -               if (i >= IPL_CLOCK)
> -                       cpu_imask[i] |= SPL_CLOCKMASK;
> +               iq->iq_ipl = maxipl;
>        }
> -       cpu_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_cpuid, 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 & ~cpu_imask[pri];
> -                       if (pripending == 0)
> -                               continue;
> -                       irq = 31 - cntlzw(pripending);
> -                       ci->ci_ipending &= ~(1 << irq);
> -                       ci->ci_cpl = cpu_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_ALLMASK;
> -       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();
>
> -       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);
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
> +                   (pcpl < IPL_SOFTCLOCK)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
>                        softintr_dispatch(SI_SOFTCLOCK);
> -                       ppc_intr_disable();
> -                       continue;
> -               }
> -               if((ci->ci_ipending & SINT_NET) & ~pcpl) {
> -                       ci->ci_ipending &= ~SINT_NET;
> -                       ci->ci_cpl = SINT_NET|SINT_TTY;
> -                       ppc_intr_enable(1);
> +               }
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
> +                   (pcpl < IPL_SOFTNET)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
>                        softintr_dispatch(SI_SOFTNET);
> -                       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_SOFTTTY)) &&
> +                   (pcpl < IPL_SOFTTTY)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
>                        softintr_dispatch(SI_SOFTTTY);
> -                       ppc_intr_disable();
> -                       continue;
>                }
> -       } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
> -       ci->ci_cpl = pcpl;      /* Don't use splx... we are here already!
*/
> +       } 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)
> -{
> -       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);
>  }
>
> @@ -633,29 +522,10 @@ 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_write(OPENPIC_EOI(cpu), 0);
> -       openpic_read(OPENPIC_EOI(cpu));
> +       openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
>  }
>
>  #ifdef MULTIPROCESSOR
> -
>  void
>  openpic_send_ipi(struct cpu_info *ci, int id)
>  {
> @@ -670,107 +540,150 @@ openpic_send_ipi(struct cpu_info *ci, in
>                panic("invalid ipi send to cpu %d %d", 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, ret;
> -       int pcpl, ocpl;
> +       int irq, pcpl, ret;
> +       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];
>
> -               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)));

> +               if (iq->iq_ipl > maxipl)
> +                       maxipl = iq->iq_ipl;
> +               splraise(iq->iq_ipl);
> +               openpic_eoi(ci->ci_cpuid);
>
> -               /* XXX check range */
> +               spurious = 1;
> +               TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
> +                       ppc_intr_enable(1);
> +                       KERNEL_LOCK();
> +                       ret = (*ih->ih_fun)(ih->ih_arg);
> +                       if (ret) {
> +                               ih->ih_count.ec_count++;
> +                               spurious = 0;
> +                       }
> +                       KERNEL_UNLOCK();
> +
> +                       (void)ppc_intr_disable();
> +                       if (intr_shared_edge == 00 && ret == 1)
> +                               break;
> +               }
> +               if (spurious) {
> +                       openpic_spurious.ec_count++;
> +#ifdef OPENPIC_NOISY
> +                       printf("spurious intr %d\n", irq);
> +#endif
> +               }
>
> -               r_imen = 1 << irq;
> +               uvmexp.intrs++;
> +               openpic_setipl(pcpl);
>
> -               if ((pcpl & r_imen) != 0) {
> -                       /* Masked! Mark this as pending. */
> -                       ci->ci_ipending |= r_imen;
> -                      
openpic_enable_irq_mask(~cpu_imask[o_intrmaxlvl[realirq]]);
> -                       openpic_eoi(ci->ci_cpuid);
> -               } else {
> -                      
openpic_enable_irq_mask(~cpu_imask[o_intrmaxlvl[realirq]]);

> -                       openpic_eoi(ci->ci_cpuid);
> -                       ocpl = splraise(cpu_imask[o_intrmaxlvl[realirq]]);
> +               irq = openpic_read_irq(ci->ci_cpuid);
> +       }
>
> -                       ih = o_intrhand[irq];
> -                       while (ih) {
> -                               ppc_intr_enable(1);
> -
> -                               KERNEL_LOCK();
> -                               ret = (*ih->ih_fun)(ih->ih_arg);
> -                               if (ret)
> -                                       ih->ih_count.ec_count++;
> -                               KERNEL_UNLOCK();
> -
> -                               (void)ppc_intr_disable();
> -                               if (intr_shared_edge == 00 && ret == 1)
> -                                       break;
> -                               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(ci->ci_cpuid, 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;
> @@ -780,6 +693,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 */
> @@ -793,31 +717,33 @@ 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", &ipi_nopirq);
>        evcount_attach(&ipi_nop[1], "ipi_nop1", &ipi_nopirq);
>        evcount_attach(&ipi_ddb[0], "ipi_ddb0", &ipi_ddbirq);
>        evcount_attach(&ipi_ddb[1], "ipi_ddb1", &ipi_ddbirq);
>  #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(ci->ci_cpuid, 0);
>  }
>
>  void
> -openpic_ipi_ddb(void)
> +openpic_ipi_ddb()
>  {
> +#ifdef OPENPIC_NOISY
> +       printf("ipi_ddb() called\n");
> +#endif
>        Debugger();
>  }
> -
> Index: macppc/macppc/clock.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/macppc/clock.c,v
> retrieving revision 1.31
> diff -u -p -r1.31 clock.c
> --- macppc/macppc/clock.c       20 Sep 2010 06:33:47 -0000      1.31
> +++ macppc/macppc/clock.c       7 Jul 2011 04:23:40 -0000
> @@ -225,7 +225,7 @@ decr_intr(struct clockframe *frame)
>         */
>        ppc_mtdec(nextevent - tb);
>
> -       if (ci->ci_cpl & SPL_CLOCKMASK) {
> +       if (ci->ci_cpl >= IPL_CLOCK) {
>                ci->ci_statspending += nstats;
>        } else {
>                KERNEL_LOCK();
> Index: macppc/macppc/machdep.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/macppc/machdep.c,v
> retrieving revision 1.130
> diff -u -p -r1.130 machdep.c
> --- macppc/macppc/machdep.c     5 Jul 2011 04:48:01 -0000       1.130
> +++ macppc/macppc/machdep.c     7 Jul 2011 05:09:43 -0000
> @@ -823,8 +823,6 @@ dumpsys()
>
>  }
>
> -int cpu_imask[IPL_NUM];
> -
>  int
>  lcsplx(int ipl)
>  {
> Index: powerpc/include/intr.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/include/intr.h,v
> retrieving revision 1.46
> diff -u -p -r1.46 intr.h
> --- powerpc/include/intr.h      8 Jan 2011 18:10:20 -0000       1.46
> +++ powerpc/include/intr.h      7 Jul 2011 21:19:38 -0000
> @@ -2,7 +2,7 @@
>
>  /*
>  * 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,15 +36,19 @@
>  #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_SCHED       6
> -#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_SCHED       10
> +#define        IPL_HIGH        11
> +#define        IPL_NUM         12
>
>  #define        IST_NONE        0
>  #define        IST_PULSE       1
> @@ -56,41 +60,57 @@
>  #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
>
>  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);
> +
> +extern struct ppc_intr_func {
> +       ppc_splraise_t *raise;
> +       ppc_spllower_t *lower;
> +       ppc_splx_t *x;
> +}ppc_intr_func;
>
> -void do_pending_int(void);
> +extern int ppc_smask[IPL_NUM];
> +
> +void ppc_smask_init(void);
> +char *ppc_intr_typename(int type);
>
> -extern int cpu_imask[IPL_NUM];
> +void do_pending_int(void);
>
>  /* SPL asserts */
>  #define        splassert(wantipl)      /* nothing */
>  #define        splsoftassert(wantipl)  /* nothing */
>
> -#define SINTBIT(q)     (31 - (q))
> -#define SINTMASK(q)    (1 << SINTBIT(q))
> -
> -#define        SPL_CLOCKMASK   SINTMASK(SI_NQUEUES)
> -
> -/* Soft interrupt masks. */
> +#define        set_sint(p)     atomic_setbits_int(&curcpu()->ci_ipending,
p)

>
> -#define        IPL_SOFTCLOCK   0
> -#define        IPL_SOFTNET     1
> -#define        IPL_SOFTTTY     2
> +#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        SI_TO_IRQBIT(x) (1 << (x))
> +
> +#define        SI_SOFTCLOCK            0       /* for IPL_SOFTCLOCK */
> +#define        SI_SOFTNET              1       /* for IPL_SOFTNET */
> +#define        SI_SOFTTTY              2       /* for IPL_SOFTSERIAL */
>
> -#define        SI_SOFTCLOCK    0       /* for IPL_SOFTCLOCK */
> -#define        SI_SOFTNET      1       /* for IPL_SOFTNET */
> -#define        SI_SOFTTTY      2       /* for IPL_SOFTTY */
> -
> -#define        SINT_ALLMASK    (SINTMASK(SI_SOFTCLOCK) | \
> -                        SINTMASK(SI_SOFTNET) | SINTMASK(SI_SOFTTTY))
> -#define        SI_NQUEUES      3
> +#define        SI_NQUEUES              3
>
>  #include <machine/mutex.h>
>  #include <sys/queue.h>
> @@ -109,38 +129,29 @@ struct soft_intrq {
>        struct mutex siq_mtx;
>  };
>
> -void    softintr_disestablish(void *);
> -void    softintr_dispatch(int);
> +
> +void   softintr_disestablish(void *);
> +void   softintr_dispatch(int);
>  void   *softintr_establish(int, void (*)(void *), void *);
> -void    softintr_init(void);
> -void    softintr_schedule(void *);
> +void   softintr_init(void);
> +
> +void   softintr_schedule(void *);
>
> -#define        SINT_CLOCK      SINTMASK(SI_SOFTCLOCK)
> -#define        SINT_NET        SINTMASK(SI_SOFTNET)
> -#define        SINT_TTY        SINTMASK(SI_SOFTTTY)
> -
> -#define splbio()       splraise(cpu_imask[IPL_BIO])
> -#define splnet()       splraise(cpu_imask[IPL_NET])
> -#define spltty()       splraise(cpu_imask[IPL_TTY])
> -#define splaudio()     splraise(cpu_imask[IPL_AUDIO])
> -#define splclock()     splraise(cpu_imask[IPL_CLOCK])
> -#define splvm()                splraise(cpu_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        set_sint(p)     atomic_setbits_int(&curcpu()->ci_ipending,
p)

>
> -#define        splhigh()       splraise(0xffffffff)
> -#define        spl0()          spllower(0)
> +#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;
> @@ -148,10 +159,16 @@ struct intrhand {
>        int             ih_irq;
>        const 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 PPC_IPI_NOP            0
>  #define PPC_IPI_DDB            1
> Index: powerpc/powerpc/intr.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/powerpc/intr.c,v
> retrieving revision 1.6
> diff -u -p -r1.6 intr.c
> --- powerpc/powerpc/intr.c      9 Jun 2009 01:12:38 -0000       1.6
> +++ powerpc/powerpc/intr.c      7 Jul 2011 23:42:40 -0000
> @@ -36,44 +36,114 @@
>  #include <machine/cpu.h>
>  #include <machine/intr.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 (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)
>  {
> -       struct cpu_info *ci = curcpu();
> -       int oldcpl;
> +       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");
> +        oldcpl = ci->ci_cpl;
> +        if (newcpl < oldcpl)
> +                newcpl = oldcpl;
> +        ci->ci_cpl = newcpl;
>
> -       return (oldcpl);
> +        return (oldcpl);
>  }
>
>  int
> -spllower(int newcpl)
> +ppc_dflt_spllower(int newcpl)
>  {
> -       struct cpu_info *ci = curcpu();
> -       int oldcpl;
> +        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");
> +        oldcpl = ci->ci_cpl;
>
> -       return (oldcpl);
> +        splx(newcpl);
> +
> +        return (oldcpl);
>  }
>
>  void
> -splx(int newcpl)
> +ppc_dflt_splx(int newcpl)
>  {
> -       struct cpu_info *ci = curcpu();
> +        struct cpu_info *ci = curcpu();
>
> -       __asm__ volatile("":::"memory");        /* reorder protect */
> -       ci->ci_cpl = newcpl;
> -       if (ci->ci_ipending & ~newcpl)
> +        ci->ci_cpl = 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");
> +       }
>  }
> Index: powerpc/powerpc/mutex.S
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/powerpc/mutex.S,v
> retrieving revision 1.12
> diff -u -p -r1.12 mutex.S
> --- powerpc/powerpc/mutex.S     8 Jan 2011 18:10:22 -0000       1.12
> +++ powerpc/powerpc/mutex.S     7 Jul 2011 23:15:09 -0000
> @@ -1,4 +1,4 @@
> -/*     $OpenBSD: mutex.S,v 1.12 2011/01/08 18:10:22 deraadt Exp $      */
> +/*     $OpenBSD: mutex.S,v 1.13 2011/07/07 05:43:48 drahn Exp $        */
>
>  /*
>  * Copyright (c) 2007 Dale Rahn
> @@ -33,19 +33,16 @@ ENTRY(mtx_init)
>
>
>  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(cpu_imask)@ha      # convert into cpl
> -       slwi    %r5,%r5,2
> -       addi    %r5,%r5,_C_LABEL(cpu_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
> @@ -55,12 +52,12 @@ ENTRY(mtx_enter)
>        cmpl    0,%r4,%r6
>        beq-    .L_mutex_selflocked
>  #endif
> -       stw     %r3,28(%r1)                     # save mtx during lcsplx
> -       la      %r4,28(%r1)
> +       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:
> @@ -72,9 +69,9 @@ ENTRY(mtx_enter)
>        stw     %r6,CI_MUTEX_LEVEL(%r4)
>  #endif
>        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
> @@ -89,18 +86,15 @@ ENTRY(mtx_enter)
>
>
>  ENTRY(mtx_enter_try)
> -       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
> +       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(cpu_imask)@ha      # convert into cpl
> -       slwi    %r5,%r5,2
> -       addi    %r5,%r5,_C_LABEL(cpu_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
> @@ -110,16 +104,16 @@ ENTRY(mtx_enter_try)
>        cmpl    0,%r4,%r6
>        beq-    .L_mutex_try_selflocked
>  #endif
> -       stw     %r3,28(%r1)                     # save mtx during lcsplx
> -       la      %r4,28(%r1)
> +       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     %r0,36(%r1)                     # load return address
> +       lwz     %r0,20(%r1)                     # load return address
>        mtlr    %r0
> -       addi    %r1,%r1,32                      # restore stack
> -       li      %r2,0                           # return zero
> +       addi    %r1,%r1,16                      # restore stack
> +       li      %r3,0                           # return zero
>        blr
>
>  .L_mutex_try_free:
> @@ -131,10 +125,10 @@ ENTRY(mtx_enter_try)
>        stw     %r6,CI_MUTEX_LEVEL(%r4)
>  #endif
>        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
> -       li      %r2,1                           # return nonzero
> +       addi    %r1,%r1,16                      # restore stack
> +       li      %r3,1                           # return nonzero
>        blr
>
>  #ifdef DIAGNOSTIC
> @@ -151,7 +145,7 @@ ENTRY(mtx_enter_try)
>  ENTRY(mtx_leave)
>  #ifdef DIAGNOSTIC
>        lwz     %r6,MTX_OWNER(%r3)
> -       cmpwi   0,%r6,0                         # test owner == 0
> +       cmpwi   0,%r6,0                         # test owner == 0
>
>        beq-    .L_mutex_notlocked
>  #endif
> Index: powerpc/powerpc/softintr.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/powerpc/softintr.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 softintr.c
> --- powerpc/powerpc/softintr.c  21 Dec 2010 14:56:24 -0000      1.3
> +++ powerpc/powerpc/softintr.c  7 Jul 2011 21:20:55 -0000
> @@ -170,7 +170,7 @@ softintr_schedule(void *arg)
>        if (sih->sih_pending == 0) {
>                TAILQ_INSERT_TAIL(&siq->siq_list, sih, sih_list);
>                sih->sih_pending = 1;
> -               atomic_setbits_int(&ci->ci_ipending,
SINTMASK(siq->siq_si));
> +               atomic_setbits_int(&ci->ci_ipending,
SI_TO_IRQBIT(siq->siq_si));

>        }
>        mtx_leave(&siq->siq_mtx);
>  }
> Index: socppc/dev/ipic.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/socppc/dev/ipic.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 ipic.c
> --- socppc/dev/ipic.c   8 Jan 2011 18:10:22 -0000       1.14
> +++ socppc/dev/ipic.c   7 Jul 2011 05:51:38 -0000
> @@ -65,7 +65,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 *);
> @@ -84,10 +84,17 @@ void        ipic_write(struct ipic_softc *, bus
>  uint32_t ipic_simsr_h(int);
>  uint32_t ipic_simsr_l(int);
>  uint32_t ipic_semsr(int);
> +void   ipic_calc_masks(void);
>
> -void   intr_calculatemasks(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)
> @@ -108,6 +115,8 @@ ipic_attach(struct device *parent, struc
>        struct ipic_softc *sc = (void *)self;
>        struct obio_attach_args *oa = aux;
>        int ivec;
> +       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)) {
> @@ -120,6 +129,11 @@ ipic_attach(struct device *parent, struc
>        /*
>         * Deal with pre-established interrupts.
>         */
> +       for (i = 0; i < IPIC_NVEC; i++) {
> +               iq = &ipic_handler[i];
> +               TAILQ_INIT(&iq->iq_list);
> +       }
> +
>        for (ivec = 0; ivec < IPIC_NVEC; ivec++) {
>                if (ipic_intrhand[ivec]) {
>                        int level = ipic_intrhand[ivec]->ih_level;
> @@ -143,6 +157,11 @@ ipic_attach(struct device *parent, struc
>                }
>        }
>
> +       ppc_smask_init();
> +       ppc_intr_func.raise = ipic_splraise;
> +       ppc_intr_func.lower = ipic_spllower;
> +       ppc_intr_func.x = ipic_splx;
> +
>        printf("\n");
>  }
>
> @@ -217,31 +236,9 @@ ipic_semsr(int ivec)
>  }
>
>  void
> -intr_calculatemasks(void)
> +ipic_calc_masks(void)
>  {
>        struct ipic_softc *sc = ipic_sc;
> -       int level;
> -
> -       for (level = IPL_NONE; level < IPL_NUM; level++)
> -               cpu_imask[level] = SINT_ALLMASK | (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.
> -        */
> -       cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
> -       cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
> -       cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
> -       cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
> -
> -       /*
> -        * These are pseudo-levels.
> -        */
> -       cpu_imask[IPL_NONE] = 0x00000000;
> -       cpu_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];
> @@ -267,36 +264,44 @@ intr_establish(int ivec, int type, int l
>     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)
> -               ;
> -
>        if (sc) {
>                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);
> -       *p = ih;
>
> +       evcount_attach(&ih->ih_count, name, &ih->ih_irq);
> +
> +       /*
> +        * 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. */
>        if (sc) {
> -               /* Unmask the interrupt. */
>                mask = ipic_read(sc, IPIC_SIMSR_H);
>                mask |= ipic_simsr_h(ivec);
>                ipic_write(sc, IPIC_SIMSR_H, mask);
> @@ -317,31 +322,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(cpu_imask[ih->ih_level]);
> +               ipic_splraise(ih->ih_level);
>                ppc_intr_enable(1);
>
>                KERNEL_LOCK();
> @@ -350,40 +343,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)
>  {
> -       int a;
> +       struct cpu_info *ci = curcpu();
> +       int ocpl = ci->ci_cpl;
> +
> +       if (ocpl > newcpl)
> +               newcpl = ocpl;
>
> -       __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x));
> +       ipic_setipl(newcpl);
>
> -       return a;
> +       return (ocpl);
> +}
> +
> +int
> +ipic_spllower(int newcpl)
> +{
> +       struct cpu_info *ci = curcpu();
> +       int ocpl = ci->ci_cpl;
> +
> +       ipic_splx(newcpl);
> +
> +       return (ocpl);
>  }
>
>  void
> -ipic_do_pending_int(void)
> +ipic_splx(int newcpl)
> +{
> +       struct cpu_info *ci = curcpu();
> +
> +       ipic_setipl(newcpl);
> +       if (ci->ci_ipending & ppc_smask[newcpl])
> +               ipic_do_pending(newcpl);
> +}
> +
> +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_ALLMASK;
> -       level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCKMASK|SINT_ALLMASK)));
> -       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);
>  }
> Index: socppc/socppc/clock.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/socppc/socppc/clock.c,v
> retrieving revision 1.8
> diff -u -p -r1.8 clock.c
> --- socppc/socppc/clock.c       20 Sep 2010 06:33:48 -0000      1.8
> +++ socppc/socppc/clock.c       7 Jul 2011 04:23:42 -0000
> @@ -202,7 +202,7 @@ decr_intr(struct clockframe *frame)
>         */
>        ppc_mtdec(nextevent - tb);
>
> -       if (curcpu()->ci_cpl & SPL_CLOCKMASK) {
> +       if (ci->ci_cpl >= IPL_CLOCK) {
>                ci->ci_statspending += nstats;
>        } else {
>                KERNEL_LOCK();
> Index: socppc/socppc/machdep.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/socppc/socppc/machdep.c,v
> retrieving revision 1.32
> diff -u -p -r1.32 machdep.c
> --- socppc/socppc/machdep.c     5 Jul 2011 04:48:02 -0000       1.32
> +++ socppc/socppc/machdep.c     7 Jul 2011 06:06:38 -0000
> @@ -1095,59 +1095,41 @@ 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;
> +       int pcpl = ci->ci_cpl; /* XXX */
> +       int s;
>        s = ppc_intr_disable();
> -       pcpl = ci->ci_cpl;
> -
> -       ipic_do_pending_int();
> +       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);
> -                       KERNEL_LOCK();
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
> +                   (pcpl < IPL_SOFTCLOCK)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
>                        softintr_dispatch(SI_SOFTCLOCK);
> -                       KERNEL_UNLOCK();
> -                       ppc_intr_disable();
> -                       continue;
> -               }
> -               if((ci->ci_ipending & SINT_NET) & ~pcpl) {
> -                       ci->ci_ipending &= ~SINT_NET;
> -                       ci->ci_cpl = SINT_NET|SINT_TTY;
> -                       ppc_intr_enable(1);
> -                       KERNEL_LOCK();
> +               }
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
> +                   (pcpl < IPL_SOFTNET)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
>                        softintr_dispatch(SI_SOFTNET);
> -                       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);
> -                       KERNEL_LOCK();
> +               if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
> +                   (pcpl < IPL_SOFTTTY)) {
> +                       ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
>                        softintr_dispatch(SI_SOFTTTY);
> -                       KERNEL_UNLOCK();
> -                       ppc_intr_disable();
> -                       continue;
>                }
> -       } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
> -       ci->ci_cpl = pcpl;      /* Don't use splx... we are here already!
*/

>
> -       ci->ci_iactive = 0;
> +       } while (ci->ci_ipending & ppc_smask[pcpl]);
> +       macintr_setipl(pcpl);
>        ppc_intr_enable(s);
> +
> +       atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
>  }
>
>  /*
>
> Dale Rahn                               [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: powerpc interrupt rewrite.

Stuart Henderson
In reply to this post by Dale Rahn
On 2011/07/07 19:30, Dale Rahn wrote:
> At c2k11 I managed to revive the powerpc (macppc/socppc) interrupt
> rewrite from a few years ago. It had been backed out because of problems
> attributed to other previously fixed bugs. At some prodding the dust
> was blown off the diff and it is working on at least two machines.

Can you update this for the powerpc/powerpc/mutex.S commit please,
I don't see the wdc timeouts but it needs testing anyway

Reply | Threaded
Open this post in threaded view
|

Re: powerpc interrupt rewrite.

Francois B.-2
In reply to this post by Dale Rahn
 When is this going in? Tested on my headless emac G4 (2005),
 and it solves the problem.

 Before: using dd & scp (big files) resulted in the following:

 wdc1:0:0: intr with DRQ (st=0x58<DRDY,DSC,DRQ>)
 wd0g: device timeout writing fsbn 68857312 of 68857312-68857343
 (wd0 bn 150653472; cn 149457 tn 12 sn 60), retrying
 wd0: soft error (corrected)
 wdc1:0:0: intr with DRQ (st=0x58<DRDY,DSC,DRQ>)
 wd0g: device timeout writing fsbn 69257216 of 69257216-69257247
 (wd0 bn 151053376; cn 149854 tn 8 sn 40), retrying
 wd0: soft error (corrected)

 $ sysctl hw.product
 hw.product=PowerMac6,4
 $ sysctl -a|grep 744
 hw.model=7447A (Revision 0x102)

 $ sysctl kern.version
 kern.version=OpenBSD 5.0-beta (GENERIC) #0: Tue Jul 19 14:04:02 EDT 2011
     [hidden email]:/usr/src/sys/arch/macppc/compile/GENERIC

 Now, the box works fine and no more 'wdc timeout' (tested with about
 125 gb <-> of data)

 best regards,
 Francois B.

On Thu, Jul 07, 2011 at 07:30:21PM -0500, Dale Rahn wrote:

> At c2k11 I managed to revive the powerpc (macppc/socppc) interrupt
> rewrite from a few years ago. It had been backed out because of problems
> attributed to other previously fixed bugs. At some prodding the dust
> was blown off the diff and it is working on at least two machines.
>
> Please test and see if it works and prevents the 'wdc timeout'
> error that occurs frequently.
>
> Index: macppc/dev/macintr.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/dev/macintr.c,v
> retrieving revision 1.42
> diff -u -p -r1.42 macintr.c
> --- macppc/dev/macintr.c 15 Apr 2011 20:52:55 -0000 1.42
> +++ macppc/dev/macintr.c 7 Jul 2011 21:26:19 -0000
> @@ -1,6 +1,7 @@
>  /* $OpenBSD: macintr.c,v 1.42 2011/04/15 20:52:55 deraadt Exp $ */
>  
>  /*-
> + * Copyright (c) 2008 Dale Rahn <[hidden email]>
>   * 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 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, const 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,52 +296,41 @@ 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:
>   intr_shared_edge = 1;
>   /* FALLTHROUGH */
>   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)
> - ;
> + ih->ih_fun = ih_fun;
> + ih->ih_arg = ih_arg;
> + ih->ih_level = level;
> + ih->ih_irq = irq;
> + evcount_attach(&ih->ih_count, name, &ih->ih_irq);
>  
>   /*
> - * 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();
>  
> - intr_calculatemasks();
> + TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
> + macintr_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, &m_hwirq[irq]);
> - *p = ih;
> + macintr_setipl(ci->ci_cpl);
> + ppc_intr_enable(s);
>  
>   return (ih);
>  }
> @@ -302,195 +341,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;
> - cpu_imask[level] = irqs | SINT_ALLMASK;
> + 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.
> - */
> - cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
> - cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
> - cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
> - cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
> -
> - /*
> - * These are pseudo-levels.
> - */
> - cpu_imask[IPL_NONE] = 0x00000000;
> - cpu_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 |= cpu_imask[q->ih_level];
> - m_intrmask[irq] = irqs | SINT_ALLMASK;
> - }
> -
> - /* 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. */
> + iq->iq_ipl = maxipl;
>  
> - 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;
> + if (maxipl == IPL_NONE) {
> + minipl = IPL_NONE; /* Interrupt not enabled */
> + } else {
> + for (i = minipl; i <= maxipl; i++)
> + macintr_pri_share[i] = i;
> + }
>  
> -/*
> - * Map 64 irqs into 32 (bits).
> - */
> -static int
> -mapirq(int irq)
> -{
> - int v;
> - int i;
> + /* Enable interrupts at lower levels */
>  
> - if (m_virq_inited == 0) {
> - m_virq_max = 0;
> - for (i = 0; i < ICU_LEN; i++) {
> - m_virq[i] = 0;
> + 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;
>  }
>  
>  /*
> @@ -500,141 +437,118 @@ void
>  mac_ext_intr()
>  {
>   int irq = 0;
> - int o_imen, r_imen;
>   int pcpl, ret;
>   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;
> -
> - 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]);
> + irq = macintr_read_irq();
> + while (irq != 255) {
> + iq = &macintr_handler[irq];
> + macintr_setipl(iq->iq_ipl);
>  
> - ih = m_intrhand[irq];
> - while (ih) {
> + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
> + ppc_intr_enable(1);
>   ret = ((*ih->ih_fun)(ih->ih_arg));
>   if (ret) {
>   ih->ih_count.ec_count++;
>   if (intr_shared_edge == 0 && ret == 1)
>   break;
>   }
> - 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;
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
> +    (pcpl < IPL_SOFTCLOCK)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
>   softintr_dispatch(SI_SOFTCLOCK);
> - }
> - if((ci->ci_ipending & SINT_NET) & ~pcpl) {
> - ci->ci_ipending &= ~SINT_NET;
> + }
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
> +    (pcpl < IPL_SOFTNET)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
>   softintr_dispatch(SI_SOFTNET);
>   }
> - if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
> - ci->ci_ipending &= ~SINT_TTY;
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
> +    (pcpl < IPL_SOFTTTY)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
>   softintr_dispatch(SI_SOFTTTY);
>   }
> - } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
> - ci->ci_ipending &= pcpl;
> - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
> +
> + } while (ci->ci_ipending & ppc_smask[pcpl]);
> + macintr_setipl(pcpl);
>   ppc_intr_enable(s);
> - ci->ci_iactive = 0;
> +
> + 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;
>  }
> Index: macppc/dev/openpic.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/dev/openpic.c,v
> retrieving revision 1.64
> diff -u -p -r1.64 openpic.c
> --- macppc/dev/openpic.c 15 Apr 2011 20:52:55 -0000 1.64
> +++ macppc/dev/openpic.c 7 Jul 2011 21:38:05 -0000
> @@ -1,6 +1,7 @@
>  /* $OpenBSD: openpic.c,v 1.64 2011/04/15 20:52:55 deraadt Exp $ */
>  
>  /*-
> + * Copyright (c) 2008 Dale Rahn <[hidden email]>
>   * Copyright (c) 1995 Per Fogelstrom
>   * Copyright (c) 1993, 1994 Charles M. Hannum.
>   * Copyright (c) 1990 The Regents of the University of California.
> @@ -56,22 +57,18 @@
>  #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);
> -void openpic_enable_irq_mask(int irq_mask);
>  
> -#define HWIRQ_MAX (31 - (SI_NQUEUES + 1))
> -#define HWIRQ_MASK (0xffffffff >> (SI_NQUEUES + 1))
> +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
> @@ -82,17 +79,34 @@ static struct evcount ipi_nop[PPC_MAXPRO
>  static int ipi_nopirq = IPI_VECTOR_NOP;
>  static int ipi_ddbirq = IPI_VECTOR_DDB;
>  #endif
> +struct evcount openpic_spurious;
> +int openpic_spurious_irq = 255;
> +
> +void openpic_enable_irq(int, int);
> +void openpic_disable_irq(int);
> +void openpic_init(void);
> +void openpic_set_priority(int, int);
> +void openpic_ipi_ddb(void);
> +void *openpic_intr_establish(void *, int, int, int, int (*)(void *),
> +    void *, const char *);
> +
> +typedef void  (void_f) (void);
> +extern void_f *pending_int_f;
> +
> +vaddr_t openpic_base;
> +#if 0
> +void * openpic_intr_establish( void * lcv, int irq, int type, int level,
> +    int (*ih_fun)(void *), void *ih_arg, const char *name);
> +#endif
> +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
>  
> -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_ipi_ddb(void);
> -static __inline int openpic_read_irq(int);
> -static __inline void openpic_eoi(int);
> +u_int openpic_read(int reg);
> +void openpic_write(int reg, u_int val);
>  
>  struct openpic_softc {
>   struct device sc_dev;
> @@ -100,9 +114,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),
> @@ -114,6 +129,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)
>  {
> @@ -141,22 +192,10 @@ openpic_match(struct device *parent, voi
>   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, const 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;
>  
> @@ -167,12 +206,16 @@ openpic_attach(struct device *parent, st
>   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;
> @@ -180,18 +223,66 @@ openpic_attach(struct device *parent, st
>  #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", &openpic_spurious_irq);
> +
> + ppc_intr_func.raise = openpic_splraise;
> + ppc_intr_func.lower = openpic_spllower;
> + ppc_intr_func.x = openpic_splx;
> +
> + openpic_set_priority(0, 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(ci->ci_cpuid, 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()
> @@ -211,13 +302,6 @@ openpic_collect_preconf_intr()
>   }
>  }
>  
> -static int
> -fakeintr(void *arg)
> -{
> -
> - return 0;
> -}
> -
>  /*
>   * Register an interrupt handler.
>   */
> @@ -225,75 +309,53 @@ void *
>  openpic_intr_establish(void *lcv, int irq, int type, int level,
>      int (*ih_fun)(void *), void *ih_arg, const 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:
>   intr_shared_edge = 1;
>   /* FALLTHROUGH */
>   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, &ih->ih_irq);
>  
>   /*
> - * 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, &o_hwirq[irq]);
> - *p = ih;
> + ppc_intr_enable(s);
>  
>   return (ih);
>  }
> @@ -306,51 +368,27 @@ openpic_intr_disestablish(void *lcp, voi
>  {
>   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;
>  }
>  
>  /*
> @@ -363,260 +401,111 @@ 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(ci->ci_cpuid, 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;
> - }
> - }
> -
> - o_intrmaxlvl[irq] = max;
> + for (i = IPL_NONE; i < IPL_NUM; i++) {
> + openpic_pri_share[i] = i;
> + }
>  
> - /* 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) );
> + for (irq = 0; irq < openpic_numirq; irq++) {
> + int maxipl = IPL_NONE;
> + int minipl = IPL_HIGH;
> + struct intrq *iq = &openpic_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;
>   }
>  
> - 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++)
> - cpu_imask[i] &= ~(1 << o_virq[irq]);
> - for (; i <= IPL_HIGH; i++)
> - cpu_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)
> - cpu_imask[i] |= SINT_ALLMASK;
> - if (i >= IPL_CLOCK)
> - cpu_imask[i] |= SPL_CLOCKMASK;
> + iq->iq_ipl = maxipl;
>   }
> - cpu_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_cpuid, 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 & ~cpu_imask[pri];
> - if (pripending == 0)
> - continue;
> - irq = 31 - cntlzw(pripending);
> - ci->ci_ipending &= ~(1 << irq);
> - ci->ci_cpl = cpu_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_ALLMASK;
> - 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();
>  
> - 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);
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
> +    (pcpl < IPL_SOFTCLOCK)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
>   softintr_dispatch(SI_SOFTCLOCK);
> - ppc_intr_disable();
> - continue;
> - }
> - if((ci->ci_ipending & SINT_NET) & ~pcpl) {
> - ci->ci_ipending &= ~SINT_NET;
> - ci->ci_cpl = SINT_NET|SINT_TTY;
> - ppc_intr_enable(1);
> + }
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
> +    (pcpl < IPL_SOFTNET)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
>   softintr_dispatch(SI_SOFTNET);
> - 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_SOFTTTY)) &&
> +    (pcpl < IPL_SOFTTTY)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
>   softintr_dispatch(SI_SOFTTTY);
> - ppc_intr_disable();
> - continue;
>   }
> - } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
> - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
> + } 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)
> -{
> - 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);
>  }
>  
> @@ -633,29 +522,10 @@ 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_write(OPENPIC_EOI(cpu), 0);
> - openpic_read(OPENPIC_EOI(cpu));
> + openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
>  }
>  
>  #ifdef MULTIPROCESSOR
> -
>  void
>  openpic_send_ipi(struct cpu_info *ci, int id)
>  {
> @@ -670,107 +540,150 @@ openpic_send_ipi(struct cpu_info *ci, in
>   panic("invalid ipi send to cpu %d %d", 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, ret;
> - int pcpl, ocpl;
> + int irq, pcpl, ret;
> + 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];
>  
> - 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)));
> + if (iq->iq_ipl > maxipl)
> + maxipl = iq->iq_ipl;
> + splraise(iq->iq_ipl);
> + openpic_eoi(ci->ci_cpuid);
>  
> - /* XXX check range */
> + spurious = 1;
> + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
> + ppc_intr_enable(1);
> + KERNEL_LOCK();
> + ret = (*ih->ih_fun)(ih->ih_arg);
> + if (ret) {
> + ih->ih_count.ec_count++;
> + spurious = 0;
> + }
> + KERNEL_UNLOCK();
> +
> + (void)ppc_intr_disable();
> + if (intr_shared_edge == 00 && ret == 1)
> + break;
> + }
> + if (spurious) {
> + openpic_spurious.ec_count++;
> +#ifdef OPENPIC_NOISY
> + printf("spurious intr %d\n", irq);
> +#endif
> + }
>  
> - r_imen = 1 << irq;
> + uvmexp.intrs++;
> + openpic_setipl(pcpl);
>  
> - if ((pcpl & r_imen) != 0) {
> - /* Masked! Mark this as pending. */
> - ci->ci_ipending |= r_imen;
> - openpic_enable_irq_mask(~cpu_imask[o_intrmaxlvl[realirq]]);
> - openpic_eoi(ci->ci_cpuid);
> - } else {
> - openpic_enable_irq_mask(~cpu_imask[o_intrmaxlvl[realirq]]);
> - openpic_eoi(ci->ci_cpuid);
> - ocpl = splraise(cpu_imask[o_intrmaxlvl[realirq]]);
> + irq = openpic_read_irq(ci->ci_cpuid);
> + }
>  
> - ih = o_intrhand[irq];
> - while (ih) {
> - ppc_intr_enable(1);
> -
> - KERNEL_LOCK();
> - ret = (*ih->ih_fun)(ih->ih_arg);
> - if (ret)
> - ih->ih_count.ec_count++;
> - KERNEL_UNLOCK();
> -
> - (void)ppc_intr_disable();
> - if (intr_shared_edge == 00 && ret == 1)
> - break;
> - 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(ci->ci_cpuid, 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;
> @@ -780,6 +693,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 */
> @@ -793,31 +717,33 @@ 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", &ipi_nopirq);
>   evcount_attach(&ipi_nop[1], "ipi_nop1", &ipi_nopirq);
>   evcount_attach(&ipi_ddb[0], "ipi_ddb0", &ipi_ddbirq);
>   evcount_attach(&ipi_ddb[1], "ipi_ddb1", &ipi_ddbirq);
>  #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(ci->ci_cpuid, 0);
>  }
>  
>  void
> -openpic_ipi_ddb(void)
> +openpic_ipi_ddb()
>  {
> +#ifdef OPENPIC_NOISY
> + printf("ipi_ddb() called\n");
> +#endif
>   Debugger();
>  }
> -
> Index: macppc/macppc/clock.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/macppc/clock.c,v
> retrieving revision 1.31
> diff -u -p -r1.31 clock.c
> --- macppc/macppc/clock.c 20 Sep 2010 06:33:47 -0000 1.31
> +++ macppc/macppc/clock.c 7 Jul 2011 04:23:40 -0000
> @@ -225,7 +225,7 @@ decr_intr(struct clockframe *frame)
>   */
>   ppc_mtdec(nextevent - tb);
>  
> - if (ci->ci_cpl & SPL_CLOCKMASK) {
> + if (ci->ci_cpl >= IPL_CLOCK) {
>   ci->ci_statspending += nstats;
>   } else {
>   KERNEL_LOCK();
> Index: macppc/macppc/machdep.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/macppc/macppc/machdep.c,v
> retrieving revision 1.130
> diff -u -p -r1.130 machdep.c
> --- macppc/macppc/machdep.c 5 Jul 2011 04:48:01 -0000 1.130
> +++ macppc/macppc/machdep.c 7 Jul 2011 05:09:43 -0000
> @@ -823,8 +823,6 @@ dumpsys()
>  
>  }
>  
> -int cpu_imask[IPL_NUM];
> -
>  int
>  lcsplx(int ipl)
>  {
> Index: powerpc/include/intr.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/include/intr.h,v
> retrieving revision 1.46
> diff -u -p -r1.46 intr.h
> --- powerpc/include/intr.h 8 Jan 2011 18:10:20 -0000 1.46
> +++ powerpc/include/intr.h 7 Jul 2011 21:19:38 -0000
> @@ -2,7 +2,7 @@
>  
>  /*
>   * 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,15 +36,19 @@
>  #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_SCHED 6
> -#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_SCHED 10
> +#define IPL_HIGH 11
> +#define IPL_NUM 12
>  
>  #define IST_NONE 0
>  #define IST_PULSE 1
> @@ -56,41 +60,57 @@
>  #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
>  
>  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);
> +
> +extern struct ppc_intr_func {
> + ppc_splraise_t *raise;
> + ppc_spllower_t *lower;
> + ppc_splx_t *x;
> +}ppc_intr_func;
>  
> -void do_pending_int(void);
> +extern int ppc_smask[IPL_NUM];
> +
> +void ppc_smask_init(void);
> +char *ppc_intr_typename(int type);
>  
> -extern int cpu_imask[IPL_NUM];
> +void do_pending_int(void);
>  
>  /* SPL asserts */
>  #define splassert(wantipl) /* nothing */
>  #define splsoftassert(wantipl) /* nothing */
>  
> -#define SINTBIT(q) (31 - (q))
> -#define SINTMASK(q) (1 << SINTBIT(q))
> -
> -#define SPL_CLOCKMASK SINTMASK(SI_NQUEUES)
> -
> -/* Soft interrupt masks. */
> +#define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p)
>  
> -#define IPL_SOFTCLOCK 0
> -#define IPL_SOFTNET 1
> -#define IPL_SOFTTTY 2
> +#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 SI_TO_IRQBIT(x) (1 << (x))
> +
> +#define SI_SOFTCLOCK 0 /* for IPL_SOFTCLOCK */
> +#define SI_SOFTNET 1 /* for IPL_SOFTNET */
> +#define SI_SOFTTTY 2 /* for IPL_SOFTSERIAL */
>  
> -#define SI_SOFTCLOCK 0 /* for IPL_SOFTCLOCK */
> -#define SI_SOFTNET 1 /* for IPL_SOFTNET */
> -#define SI_SOFTTTY 2 /* for IPL_SOFTTY */
> -
> -#define SINT_ALLMASK (SINTMASK(SI_SOFTCLOCK) | \
> - SINTMASK(SI_SOFTNET) | SINTMASK(SI_SOFTTTY))
> -#define SI_NQUEUES 3
> +#define SI_NQUEUES 3
>  
>  #include <machine/mutex.h>
>  #include <sys/queue.h>
> @@ -109,38 +129,29 @@ struct soft_intrq {
>   struct mutex siq_mtx;
>  };
>  
> -void softintr_disestablish(void *);
> -void softintr_dispatch(int);
> +
> +void softintr_disestablish(void *);
> +void softintr_dispatch(int);
>  void *softintr_establish(int, void (*)(void *), void *);
> -void softintr_init(void);
> -void softintr_schedule(void *);
> +void softintr_init(void);
> +
> +void softintr_schedule(void *);
>  
> -#define SINT_CLOCK SINTMASK(SI_SOFTCLOCK)
> -#define SINT_NET SINTMASK(SI_SOFTNET)
> -#define SINT_TTY SINTMASK(SI_SOFTTTY)
> -
> -#define splbio() splraise(cpu_imask[IPL_BIO])
> -#define splnet() splraise(cpu_imask[IPL_NET])
> -#define spltty() splraise(cpu_imask[IPL_TTY])
> -#define splaudio() splraise(cpu_imask[IPL_AUDIO])
> -#define splclock() splraise(cpu_imask[IPL_CLOCK])
> -#define splvm() splraise(cpu_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 set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p)
>  
> -#define splhigh() splraise(0xffffffff)
> -#define spl0() spllower(0)
> +#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;
> @@ -148,10 +159,16 @@ struct intrhand {
>   int ih_irq;
>   const 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 PPC_IPI_NOP 0
>  #define PPC_IPI_DDB 1
> Index: powerpc/powerpc/intr.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/powerpc/intr.c,v
> retrieving revision 1.6
> diff -u -p -r1.6 intr.c
> --- powerpc/powerpc/intr.c 9 Jun 2009 01:12:38 -0000 1.6
> +++ powerpc/powerpc/intr.c 7 Jul 2011 23:42:40 -0000
> @@ -36,44 +36,114 @@
>  #include <machine/cpu.h>
>  #include <machine/intr.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 (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)
>  {
> - struct cpu_info *ci = curcpu();
> - int oldcpl;
> + 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");
> +        oldcpl = ci->ci_cpl;
> +        if (newcpl < oldcpl)
> +                newcpl = oldcpl;
> +        ci->ci_cpl = newcpl;
>  
> - return (oldcpl);
> +        return (oldcpl);
>  }
>  
>  int
> -spllower(int newcpl)
> +ppc_dflt_spllower(int newcpl)
>  {
> - struct cpu_info *ci = curcpu();
> - int oldcpl;
> +        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");
> +        oldcpl = ci->ci_cpl;
>  
> - return (oldcpl);
> +        splx(newcpl);
> +
> +        return (oldcpl);
>  }
>  
>  void
> -splx(int newcpl)
> +ppc_dflt_splx(int newcpl)
>  {
> - struct cpu_info *ci = curcpu();
> +        struct cpu_info *ci = curcpu();
>  
> - __asm__ volatile("":::"memory"); /* reorder protect */
> - ci->ci_cpl = newcpl;
> - if (ci->ci_ipending & ~newcpl)
> +        ci->ci_cpl = 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");
> + }
>  }
> Index: powerpc/powerpc/mutex.S
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/powerpc/mutex.S,v
> retrieving revision 1.12
> diff -u -p -r1.12 mutex.S
> --- powerpc/powerpc/mutex.S 8 Jan 2011 18:10:22 -0000 1.12
> +++ powerpc/powerpc/mutex.S 7 Jul 2011 23:15:09 -0000
> @@ -1,4 +1,4 @@
> -/* $OpenBSD: mutex.S,v 1.12 2011/01/08 18:10:22 deraadt Exp $ */
> +/* $OpenBSD: mutex.S,v 1.13 2011/07/07 05:43:48 drahn Exp $ */
>  
>  /*
>   * Copyright (c) 2007 Dale Rahn
> @@ -33,19 +33,16 @@ ENTRY(mtx_init)
>  
>  
>  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(cpu_imask)@ha # convert into cpl
> - slwi %r5,%r5,2
> - addi %r5,%r5,_C_LABEL(cpu_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
> @@ -55,12 +52,12 @@ ENTRY(mtx_enter)
>   cmpl 0,%r4,%r6
>   beq- .L_mutex_selflocked
>  #endif
> - stw %r3,28(%r1) # save mtx during lcsplx
> - la %r4,28(%r1)
> + 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:
> @@ -72,9 +69,9 @@ ENTRY(mtx_enter)
>   stw %r6,CI_MUTEX_LEVEL(%r4)
>  #endif
>   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
> @@ -89,18 +86,15 @@ ENTRY(mtx_enter)
>  
>  
>  ENTRY(mtx_enter_try)
> - 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
> + 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(cpu_imask)@ha # convert into cpl
> - slwi %r5,%r5,2
> - addi %r5,%r5,_C_LABEL(cpu_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
> @@ -110,16 +104,16 @@ ENTRY(mtx_enter_try)
>   cmpl 0,%r4,%r6
>   beq- .L_mutex_try_selflocked
>  #endif
> - stw %r3,28(%r1) # save mtx during lcsplx
> - la %r4,28(%r1)
> + 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 %r0,36(%r1) # load return address
> + lwz %r0,20(%r1) # load return address
>   mtlr %r0
> - addi %r1,%r1,32 # restore stack
> - li %r2,0 # return zero
> + addi %r1,%r1,16 # restore stack
> + li %r3,0 # return zero
>   blr
>  
>  .L_mutex_try_free:
> @@ -131,10 +125,10 @@ ENTRY(mtx_enter_try)
>   stw %r6,CI_MUTEX_LEVEL(%r4)
>  #endif
>   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
> - li %r2,1 # return nonzero
> + addi %r1,%r1,16 # restore stack
> + li %r3,1 # return nonzero
>   blr
>  
>  #ifdef DIAGNOSTIC
> @@ -151,7 +145,7 @@ ENTRY(mtx_enter_try)
>  ENTRY(mtx_leave)
>  #ifdef DIAGNOSTIC
>   lwz %r6,MTX_OWNER(%r3)
> - cmpwi   0,%r6,0                         # test owner == 0
> + cmpwi   0,%r6,0 # test owner == 0
>  
>   beq- .L_mutex_notlocked
>  #endif
> Index: powerpc/powerpc/softintr.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/powerpc/powerpc/softintr.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 softintr.c
> --- powerpc/powerpc/softintr.c 21 Dec 2010 14:56:24 -0000 1.3
> +++ powerpc/powerpc/softintr.c 7 Jul 2011 21:20:55 -0000
> @@ -170,7 +170,7 @@ softintr_schedule(void *arg)
>   if (sih->sih_pending == 0) {
>   TAILQ_INSERT_TAIL(&siq->siq_list, sih, sih_list);
>   sih->sih_pending = 1;
> - atomic_setbits_int(&ci->ci_ipending, SINTMASK(siq->siq_si));
> + atomic_setbits_int(&ci->ci_ipending, SI_TO_IRQBIT(siq->siq_si));
>   }
>   mtx_leave(&siq->siq_mtx);
>  }
> Index: socppc/dev/ipic.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/socppc/dev/ipic.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 ipic.c
> --- socppc/dev/ipic.c 8 Jan 2011 18:10:22 -0000 1.14
> +++ socppc/dev/ipic.c 7 Jul 2011 05:51:38 -0000
> @@ -65,7 +65,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 *);
> @@ -84,10 +84,17 @@ void ipic_write(struct ipic_softc *, bus
>  uint32_t ipic_simsr_h(int);
>  uint32_t ipic_simsr_l(int);
>  uint32_t ipic_semsr(int);
> +void ipic_calc_masks(void);
>  
> -void intr_calculatemasks(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)
> @@ -108,6 +115,8 @@ ipic_attach(struct device *parent, struc
>   struct ipic_softc *sc = (void *)self;
>   struct obio_attach_args *oa = aux;
>   int ivec;
> + 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)) {
> @@ -120,6 +129,11 @@ ipic_attach(struct device *parent, struc
>   /*
>   * Deal with pre-established interrupts.
>   */
> + for (i = 0; i < IPIC_NVEC; i++) {
> + iq = &ipic_handler[i];
> + TAILQ_INIT(&iq->iq_list);
> + }
> +
>   for (ivec = 0; ivec < IPIC_NVEC; ivec++) {
>   if (ipic_intrhand[ivec]) {
>   int level = ipic_intrhand[ivec]->ih_level;
> @@ -143,6 +157,11 @@ ipic_attach(struct device *parent, struc
>   }
>   }
>  
> + ppc_smask_init();
> + ppc_intr_func.raise = ipic_splraise;
> + ppc_intr_func.lower = ipic_spllower;
> + ppc_intr_func.x = ipic_splx;
> +
>   printf("\n");
>  }
>  
> @@ -217,31 +236,9 @@ ipic_semsr(int ivec)
>  }
>  
>  void
> -intr_calculatemasks(void)
> +ipic_calc_masks(void)
>  {
>   struct ipic_softc *sc = ipic_sc;
> - int level;
> -
> - for (level = IPL_NONE; level < IPL_NUM; level++)
> - cpu_imask[level] = SINT_ALLMASK | (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.
> - */
> - cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
> - cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
> - cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
> - cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
> -
> - /*
> - * These are pseudo-levels.
> - */
> - cpu_imask[IPL_NONE] = 0x00000000;
> - cpu_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];
> @@ -267,36 +264,44 @@ intr_establish(int ivec, int type, int l
>      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)
> - ;
> -
>   if (sc) {
>   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);
> - *p = ih;
>  
> + evcount_attach(&ih->ih_count, name, &ih->ih_irq);
> +
> + /*
> + * 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. */
>   if (sc) {
> - /* Unmask the interrupt. */
>   mask = ipic_read(sc, IPIC_SIMSR_H);
>   mask |= ipic_simsr_h(ivec);
>   ipic_write(sc, IPIC_SIMSR_H, mask);
> @@ -317,31 +322,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(cpu_imask[ih->ih_level]);
> + ipic_splraise(ih->ih_level);
>   ppc_intr_enable(1);
>  
>   KERNEL_LOCK();
> @@ -350,40 +343,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)
>  {
> - int a;
> + struct cpu_info *ci = curcpu();
> + int ocpl = ci->ci_cpl;
> +
> + if (ocpl > newcpl)
> + newcpl = ocpl;
>  
> - __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x));
> + ipic_setipl(newcpl);
>  
> - return a;
> + return (ocpl);
> +}
> +
> +int
> +ipic_spllower(int newcpl)
> +{
> + struct cpu_info *ci = curcpu();
> + int ocpl = ci->ci_cpl;
> +
> + ipic_splx(newcpl);
> +
> + return (ocpl);
>  }
>  
>  void
> -ipic_do_pending_int(void)
> +ipic_splx(int newcpl)
> +{
> + struct cpu_info *ci = curcpu();
> +
> + ipic_setipl(newcpl);
> + if (ci->ci_ipending & ppc_smask[newcpl])
> + ipic_do_pending(newcpl);
> +}
> +
> +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_ALLMASK;
> - level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCKMASK|SINT_ALLMASK)));
> - 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);
>  }
> Index: socppc/socppc/clock.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/socppc/socppc/clock.c,v
> retrieving revision 1.8
> diff -u -p -r1.8 clock.c
> --- socppc/socppc/clock.c 20 Sep 2010 06:33:48 -0000 1.8
> +++ socppc/socppc/clock.c 7 Jul 2011 04:23:42 -0000
> @@ -202,7 +202,7 @@ decr_intr(struct clockframe *frame)
>   */
>   ppc_mtdec(nextevent - tb);
>  
> - if (curcpu()->ci_cpl & SPL_CLOCKMASK) {
> + if (ci->ci_cpl >= IPL_CLOCK) {
>   ci->ci_statspending += nstats;
>   } else {
>   KERNEL_LOCK();
> Index: socppc/socppc/machdep.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/socppc/socppc/machdep.c,v
> retrieving revision 1.32
> diff -u -p -r1.32 machdep.c
> --- socppc/socppc/machdep.c 5 Jul 2011 04:48:02 -0000 1.32
> +++ socppc/socppc/machdep.c 7 Jul 2011 06:06:38 -0000
> @@ -1095,59 +1095,41 @@ 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;
> + int pcpl = ci->ci_cpl; /* XXX */
> + int s;
>   s = ppc_intr_disable();
> - pcpl = ci->ci_cpl;
> -
> - ipic_do_pending_int();
> + 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);
> - KERNEL_LOCK();
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
> +    (pcpl < IPL_SOFTCLOCK)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
>   softintr_dispatch(SI_SOFTCLOCK);
> - KERNEL_UNLOCK();
> - ppc_intr_disable();
> - continue;
> - }
> - if((ci->ci_ipending & SINT_NET) & ~pcpl) {
> - ci->ci_ipending &= ~SINT_NET;
> - ci->ci_cpl = SINT_NET|SINT_TTY;
> - ppc_intr_enable(1);
> - KERNEL_LOCK();
> + }
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
> +    (pcpl < IPL_SOFTNET)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
>   softintr_dispatch(SI_SOFTNET);
> - 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);
> - KERNEL_LOCK();
> + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
> +    (pcpl < IPL_SOFTTTY)) {
> + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
>   softintr_dispatch(SI_SOFTTTY);
> - KERNEL_UNLOCK();
> - ppc_intr_disable();
> - continue;
>   }
> - } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
> - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
>  
> - ci->ci_iactive = 0;
> + } while (ci->ci_ipending & ppc_smask[pcpl]);
> + macintr_setipl(pcpl);
>   ppc_intr_enable(s);
> +
> + atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
>  }
>  
>  /*
>
> Dale Rahn [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: powerpc interrupt rewrite.

Mike Small
"Francois B." <[hidden email]> writes:

>  When is this going in? Tested on my headless emac G4 (2005),
>  and it solves the problem.

I was going to wait until I run my back up (dump over a network to
another machine) to report, since that reliably gave the timeout
messages on my machine, but I also have been happily running (building
ports, reading mail in emacs, viewing pages in xxxterm, reading ps files
in gv) with this patch since Sunday and haven't seen the error or any
clear problems.  I thought the other day that the machine seemed
slightly more responsive using Gnus in emacs (which can be a little
soupy), but that's totally subjective and is in comparison to the 4.9
release as opposed to current without the patch.

I do now see two gem0 timeout messages in my log, but there's one before
as well as one after I applied the patch.  Harmless and unrelated?

gem0 timeout 1  (4.9 release)
----------------------
Jul 16 09:56:12 holly /bsd: OpenBSD 4.9 (GENERIC) #48: Wed Mar  2 07:02:32 MST 2011
Jul 16 09:56:12 holly /bsd:     [hidden email]:/usr/src/sys/arch/macppc/compile/GENERIC
...
Jul 16 10:01:43 holly ntpd[31193]: bad peer from pool pool.ntp.org (169.229.70.64)
Jul 16 14:03:42 holly /bsd: gem0: device timeout
Jul 16 21:00:01 holly syslogd: restart


gem0 timeout 2 (current with patch applied)
----------------------
Jul 17 06:04:10 holly /bsd: OpenBSD 4.9-current (GENERIC) #0: Sat Jul 16 23:32:20 EDT 2011
Jul 17 06:04:10 holly /bsd: [hidden email]:/usr/src/sys/arch/macppc/compile/GENERIC
...
Jul 17 08:38:36 holly ntpd[17064]: bad peer from pool pool.ntp.org (63.141.244.130)
Jul 17 10:00:01 holly syslogd: restart
Jul 18 07:58:11 holly /bsd: gem0: device timeout
Jul 18 08:51:28 holly /bsd: uid 0 on /usr: file system full


/var/log/messages excerpt from a recent snapshot showing the timeout message...
============================================
Jul 16 21:40:45 holly /bsd: OpenBSD 4.9-current (GENERIC) #40: Wed Jul 13 16:48:53 MDT 2011
Jul 16 21:40:45 holly /bsd:     [hidden email]:/usr/src/sys/arch/macppc/compile/GENERIC
Jul 16 21:40:45 holly /bsd: real mem = 402653184 (384MB)
Jul 16 21:40:45 holly /bsd: avail mem = 376946688 (359MB)
Jul 16 21:40:45 holly /bsd: mainbus0 at root: model PowerMac3,4
Jul 16 21:40:45 holly /bsd: cpu0 at mainbus0: 7400 (Revision 0x209): 466 MHz: 1MB backside cache
Jul 16 21:40:45 holly /bsd: mem0 at mainbus0
...
Jul 16 22:06:18 holly /bsd: wd0(wdc0:0:0): timeout
Jul 16 22:06:18 holly /bsd: type: ata
Jul 16 22:06:18 holly /bsd: c_bcount: 2048
Jul 16 22:06:19 holly /bsd: c_skip: 0
Jul 16 22:06:19 holly /bsd: wd0f: device timeout writing fsbn 3509636 of 3509636-3509639 (wd0 bn 9264516; cn 9190 tn 15 sn 51), retrying
Jul 16 22:06:19 holly /bsd: wd0: soft error (corrected)


Dmesg with the patch, no wd0 timeouts since then...

rebooting

[ using 490664 bytes of bsd ELF symbol table ]
console out [ATY,Rage128Pd]console in [keyboard] , using USB
: memaddr 94000000 size 4000000, : consaddr 96008000, : ioaddr 90020000, size 20000: memtag 8000, iotag 8000: width 1280 linebytes 1280 height 960 depth 8
Copyright (c) 1982, 1986, 1989, 1991, 1993
        The Regents of the University of California.  All rights reserved.
Copyright (c) 1995-2011 OpenBSD. All rights reserved.  http://www.OpenBSD.org

OpenBSD 4.9-current (GENERIC) #0: Sat Jul 16 23:32:20 EDT 2011
    [hidden email]:/usr/src/sys/arch/macppc/compile/GENERIC
real mem = 402653184 (384MB)
avail mem = 376954880 (359MB)
mainbus0 at root: model PowerMac3,4
cpu0 at mainbus0: 7400 (Revision 0x209): 466 MHz: 1MB backside cache
mem0 at mainbus0
spdmem0 at mem0: 128MB SDRAM non-parity PC133CL2
spdmem1 at mem0: 256MB SDRAM non-parity PC133CL3
memc0 at mainbus0: uni-n
kiic0 at memc0 offset 0xf8001000
iic0 at kiic0
mpcpcibr0 at mainbus0 pci: uni-north, Revision 0xff
pci0 at mpcpcibr0 bus 0
pchb0 at pci0 dev 11 function 0 "Apple Uni-N2 AGP" rev 0x00
vgafb0 at pci0 dev 16 function 0 "ATI Rage Fury" rev 0x00, mmio
wsdisplay0 at vgafb0 mux 1: console (std, vt100 emulation)
mpcpcibr1 at mainbus0 pci: uni-north, Revision 0x0
pci1 at mpcpcibr1 bus 0
pchb1 at pci1 dev 11 function 0 "Apple Uni-N2 Host" rev 0x00
bge0 at pci1 dev 20 function 0 "Altima AC9100" rev 0x15, BCM5701 B5 (0x105): irq 54, address 00:40:f4:46:f0:3f
brgphy0 at bge0 phy 1: BCM5701 10/100/1000baseT PHY, rev. 0
macobio0 at pci1 dev 23 function 0 "Apple Keylargo" rev 0x03
openpic0 at macobio0 offset 0x40000: version 0x4614 feature 3f0302 LE
macgpio0 at macobio0 offset 0x50
macgpio1 at macgpio0 irq 47
pgs0 at macgpio0: irq 55
"gpio5" at macgpio0 not configured
"gpio6" at macgpio0 not configured
"gpio11" at macgpio0 not configured
"extint-gpio15" at macgpio0 not configured
"extint-gpio16" at macgpio0 not configured
"escc-legacy" at macobio0 offset 0x12000 not configured
zsc0 at macobio0 offset 0x13000: irq 22,50
zstty0 at zsc0 channel 0
zstty1 at zsc0 channel 1
tumbler0 at macobio0 offset 0x10000: irq 30,1,2
"timer" at macobio0 offset 0x15000 not configured
adb0 at macobio0 offset 0x16000 irq 25: via-pmu, 0 targets
apm0 at adb0: battery flags 0x9, 0% charged
kiic1 at macobio0 offset 0x18000
iic1 at kiic1
wdc0 at macobio0 offset 0x1f000 irq 19: DMA
wd0 at wdc0 channel 0 drive 0: <WDC WD3200AAJB-00J3A0>
wd0: 16-sector PIO, LBA48, 305245MB, 625142448 sectors
wd0(wdc0:0:0): using PIO mode 4, DMA mode 2, Ultra-DMA mode 4
wdc1 at macobio0 offset 0x20000 irq 20: DMA
atapiscsi0 at wdc1 channel 0 drive 0
scsibus0 at atapiscsi0: 2 targets
cd0 at scsibus0 targ 0 lun 0: <PIONEER, DVD-RW DVR-115D, 1.18> ATAPI 5/cdrom removable
cd0(wdc1:0:0): using BIOS timings, DMA mode 2
wdc2 at macobio0 offset 0x21000 irq 21: DMA
audio0 at tumbler0
ohci0 at pci1 dev 24 function 0 "Apple USB" rev 0x00: irq 27, version 1.0
ohci1 at pci1 dev 25 function 0 "Apple USB" rev 0x00: irq 28, version 1.0
usb0 at ohci0: USB revision 1.0
uhub0 at usb0 "Apple OHCI root hub" rev 1.00/1.00 addr 1
usb1 at ohci1: USB revision 1.0
uhub1 at usb1 "Apple OHCI root hub" rev 1.00/1.00 addr 1
mpcpcibr2 at mainbus0 pci: uni-north, Revision 0x16
pci2 at mpcpcibr2 bus 0
pchb2 at pci2 dev 11 function 0 "Apple Uni-N2 Host" rev 0x00
"AT&T/Lucent FW322 1394" rev 0x00 at pci2 dev 14 function 0 not configured
gem0 at pci2 dev 15 function 0 "Apple Uni-N GMAC" rev 0x01: irq 41, address 00:03:93:04:f9:b2
brgphy1 at gem0 phy 0: BCM5401 10/100/1000baseT PHY, rev. 3
uhub2 at uhub1 port 1 "Chicony Generic USB Hub" rev 1.10/1.00 addr 2
uhidev0 at uhub2 port 1 configuration 1 interface 0 "Chicony PFU-65 USB Keyboard" rev 1.10/1.00 addr 3
uhidev0: iclass 3/1
ukbd0 at uhidev0: 8 modifier keys, 6 key codes
wskbd0 at ukbd0: console keyboard, using wsdisplay0
uhidev1 at uhub2 port 2 configuration 1 interface 0 "Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)" rev 1.10/3.00 addr 4
uhidev1: iclass 3/1
ums0 at uhidev1: 3 buttons, Z dir
wsmouse0 at ums0 mux 0
vscsi0 at root
scsibus1 at vscsi0: 256 targets
softraid0 at root
scsibus2 at softraid0: 256 targets
bootpath: /pci@f2000000/mac-io@17/ata-4@1f000/disk@0:/bsd
root on wd0a swap on wd0b dump on wd0b
gem0: device timeout

When I applied the patch, part of mutex.s was rejected.  In case I
messed up the hand merge, here's what that part of the file looks like
in what I built from...

a) mutex.S.rej
------------------------------------------------------------------------
@@ -110,16 +104,16 @@
  cmpl 0,%r4,%r6
  beq- .L_mutex_try_selflocked
 #endif
- stw %r3,28(%r1) # save mtx during lcsplx
- la %r4,28(%r1)
+ 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 %r0,36(%r1) # load return address
+ lwz %r0,20(%r1) # load return address
  mtlr %r0
- addi %r1,%r1,32 # restore stack
- li %r2,0 # return zero
+ addi %r1,%r1,16 # restore stack
+ li %r3,0 # return zero
  blr
 
 .L_mutex_try_free:
@@ -131,10 +125,10 @@
  stw %r6,CI_MUTEX_LEVEL(%r4)
 #endif
  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
- li %r2,1 # return nonzero
+ addi %r1,%r1,16 # restore stack
+ li %r3,1 # return nonzero
  blr
 
 #ifdef DIAGNOSTIC


b) that part of mutex.S after I manually applied the changes:
------------------------------------------------------------------------
        cmpl 0,%r4,%r6
        beq- .L_mutex_try_selflocked
#endif
        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 %r0,20(%r1) # load return address
        mtlr %r0
        addi %r1,%r1,16 # restore stack
        li %r3,0 # return zero
        blr

.L_mutex_try_free:
        stwcx. %r4,%r5,%r3 # old owner was 0 cond store
        bne- .L_mutex_try_locked # branch if reserve cancelled
#ifdef DIAGNOSTIC
        lwz %r6,CI_MUTEX_LEVEL(%r4)
        addi %r6,%r6,1 # curpcu->ci_mutex_level++
        stw %r6,CI_MUTEX_LEVEL(%r4)
#endif
        stw %r7,MTX_OLDCPL(%r3) # save old ipl
        lwz %r0,20(%r1) # load return address
        mtlr %r0
        addi %r1,%r1,16 # restore stack
        li %r3,1 # return nonzero
        blr

#ifdef DIAGNOSTIC


- Mike

Reply | Threaded
Open this post in threaded view
|

Re: powerpc interrupt rewrite.

Francois B.-2
On Wed, Jul 20, 2011 at 11:44:14AM -0400, Mike Small wrote:
>
> I do now see two gem0 timeout messages in my log, but there's one before
> as well as one after I applied the patch.  Harmless and unrelated?
>
> gem0: device timeout

 I cannot reproduce the problem on my box, I tryed so hard but nothing,
 the box seems pretty stable under high load.

 dmesg & eeprom dump : http://brouille.tuxfamily.org/dmesg/

 fb (still testing w/ports building/backup etc...)