diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2009-06-02 21:38:11 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2009-06-02 21:38:11 +0000 |
commit | f70288906283f2a7276a9ce61eff992b7cb8b159 (patch) | |
tree | d2d247a2dfdaa434991b7979c084feeb181ce8ff /sys | |
parent | 09f980458916221509f840029a090c38d3b759ac (diff) |
Reintroduce the macppc interrupt subsystem rewrite. Several bugs have
been found and corrected.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/macppc/dev/macintr.c | 547 | ||||
-rw-r--r-- | sys/arch/macppc/dev/openpic.c | 766 | ||||
-rw-r--r-- | sys/arch/macppc/include/intr.h | 4 | ||||
-rw-r--r-- | sys/arch/macppc/macppc/clock.c | 4 | ||||
-rw-r--r-- | sys/arch/macppc/macppc/cpu.c | 4 | ||||
-rw-r--r-- | sys/arch/macppc/macppc/genassym.cf | 3 | ||||
-rw-r--r-- | sys/arch/macppc/macppc/machdep.c | 4 | ||||
-rw-r--r-- | sys/arch/powerpc/include/intr.h | 117 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/intr.c | 104 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/mutex.S | 44 | ||||
-rw-r--r-- | sys/arch/socppc/dev/ipic.c | 209 | ||||
-rw-r--r-- | sys/arch/socppc/socppc/machdep.c | 60 |
12 files changed, 931 insertions, 935 deletions
diff --git a/sys/arch/macppc/dev/macintr.c b/sys/arch/macppc/dev/macintr.c index 73235f28e77..baf88edcb88 100644 --- a/sys/arch/macppc/dev/macintr.c +++ b/sys/arch/macppc/dev/macintr.c @@ -1,6 +1,7 @@ -/* $OpenBSD: macintr.c,v 1.35 2008/11/21 17:35:52 deraadt Exp $ */ +/* $OpenBSD: macintr.c,v 1.36 2009/06/02 21:38:09 drahn Exp $ */ /*- + * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org> * Copyright (c) 1995 Per Fogelstrom * Copyright (c) 1993, 1994 Charles M. Hannum. * Copyright (c) 1990 The Regents of the University of California. @@ -58,25 +59,17 @@ #define ICU_LEN 64 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) -int m_intrtype[ICU_LEN], m_intrmask[ICU_LEN], m_intrlevel[ICU_LEN]; -struct intrhand *m_intrhand[ICU_LEN]; -int m_hwirq[ICU_LEN], m_virq[64]; -unsigned int imen_m = 0xffffffff; -int m_virq_max = 0; - -static int fakeintr(void *); -static char *intr_typename(int type); -static void intr_calculatemasks(void); -static void enable_irq(int x); -static __inline int cntlzw(int x); -static int mapirq(int irq); -static int read_irq(void); -static void mac_intr_do_pending_int(void); +int macintr_ienable_l[IPL_NUM], macintr_ienable_h[IPL_NUM]; +int macintr_pri_share[IPL_NUM]; -extern u_int32_t *heathrow_FCR; +struct intrq macintr_handler[ICU_LEN]; + +void macintr_calc_mask(void); +void macintr_eoi(int irq); +int macintr_read_irq(void); +static void macintr_do_pending_int(void); -#define HWIRQ_MAX 27 -#define HWIRQ_MASK 0x0fffffff +extern u_int32_t *heathrow_FCR; #define INT_STATE_REG0 (interrupt_reg + 0x20) #define INT_ENABLE_REG0 (interrupt_reg + 0x24) @@ -95,6 +88,8 @@ int macintr_match(struct device *parent, void *cf, void *aux); void macintr_attach(struct device *, struct device *, void *); void mac_do_pending_int(void); void mac_ext_intr(void); +void macintr_collect_preconf_intr(void); +void macintr_setipl(int ipl); struct cfattach macintr_ca = { sizeof(struct macintr_softc), @@ -140,31 +135,84 @@ intr_establish_t macintr_establish; intr_disestablish_t macintr_disestablish; extern intr_establish_t *mac_intr_establish_func; extern intr_disestablish_t *mac_intr_disestablish_func; -void macintr_collect_preconf_intr(void); + +ppc_splraise_t macintr_splraise; +ppc_spllower_t macintr_spllower; +ppc_splx_t macintr_splx; + + +int +macintr_splraise(int newcpl) +{ + struct cpu_info *ci = curcpu(); + newcpl = macintr_pri_share[newcpl]; + int ocpl = ci->ci_cpl; + if (ocpl > newcpl) + newcpl = ocpl; + + macintr_setipl(newcpl); + + return ocpl; +} + +int +macintr_spllower(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int ocpl = ci->ci_cpl; + + macintr_splx(newcpl); + + return ocpl; +} + +void +macintr_splx(int newcpl) +{ + struct cpu_info *ci = curcpu(); + + macintr_setipl(newcpl); + if (ci->ci_ipending & ppc_smask[newcpl]) + macintr_do_pending_int(); +} void macintr_attach(struct device *parent, struct device *self, void *aux) { + struct cpu_info *ci = curcpu(); struct confargs *ca = aux; extern intr_establish_t *intr_establish_func; extern intr_disestablish_t *intr_disestablish_func; + struct intrq *iq; + int i; interrupt_reg = (void *)mapiodev(ca->ca_baseaddr,0x100); /* XXX */ + for (i = 0; i < ICU_LEN; i++) { + iq = &macintr_handler[i]; + TAILQ_INIT(&iq->iq_list); + } + ppc_smask_init(); + install_extint(mac_ext_intr); - pending_int_f = mac_intr_do_pending_int; + pending_int_f = macintr_do_pending_int; intr_establish_func = macintr_establish; intr_disestablish_func = macintr_disestablish; mac_intr_establish_func = macintr_establish; mac_intr_disestablish_func = macintr_disestablish; + ppc_intr_func.raise = macintr_splraise; + ppc_intr_func.lower = macintr_spllower; + ppc_intr_func.x = macintr_splx; + + ci->ci_iactive = 0; + macintr_collect_preconf_intr(); mac_intr_establish(parent, 0x14, IST_LEVEL, IPL_HIGH, macintr_prog_button, (void *)0x14, "progbutton"); ppc_intr_enable(1); - printf("\n"); } @@ -209,11 +257,19 @@ macintr_prog_button (void *arg) return 1; } -static int -fakeintr(void *arg) +void +macintr_setipl(int ipl) { + struct cpu_info *ci = curcpu(); + int s; + s = ppc_intr_disable(); + ci->ci_cpl = ipl; + if (heathrow_FCR) + out32rb(INT_ENABLE_REG1, + macintr_ienable_h[macintr_pri_share[ipl]]); - return 0; + out32rb(INT_ENABLE_REG0, macintr_ienable_l[macintr_pri_share[ipl]]); + ppc_intr_enable(s); } /* @@ -223,19 +279,13 @@ void * macintr_establish(void * lcv, int irq, int type, int level, int (*ih_fun)(void *), void *ih_arg, char *name) { - struct intrhand **p, *q, *ih; - static struct intrhand fakehand; - - fakehand.ih_next = NULL; - fakehand.ih_fun = fakeintr; + struct cpu_info *ci = curcpu(); + struct intrq *iq; + struct intrhand *ih; + int s; #if 0 -printf("macintr_establish, hI %d L %d ", irq, type); -printf("addr reg0 %x\n", INT_STATE_REG0); -#endif - irq = mapirq(irq); -#if 0 -printf("vI %d ", irq); +printf("macintr_establish, hI %d L %d %s", irq, level, ppc_intr_typename(type)); #endif /* no point in sleeping unless someone can free memory. */ @@ -246,51 +296,40 @@ printf("vI %d ", irq); if (!LEGAL_IRQ(irq) || type == IST_NONE) panic("intr_establish: bogus irq or type"); - switch (m_intrtype[irq]) { + iq = &macintr_handler[irq]; + switch (iq->iq_ist) { case IST_NONE: - m_intrtype[irq] = type; + iq->iq_ist = type; break; case IST_EDGE: case IST_LEVEL: - if (type == m_intrtype[irq]) + if (type == iq->iq_ist) break; case IST_PULSE: if (type != IST_NONE) panic("intr_establish: can't share %s with %s", - intr_typename(m_intrtype[irq]), - intr_typename(type)); + ppc_intr_typename(iq->iq_ist), + ppc_intr_typename(type)); break; } - /* - * Figure out where to put the handler. - * This is O(N^2), but we want to preserve the order, and N is - * generally small. - */ - for (p = &m_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) - ; - - /* - * Actually install a fake handler momentarily, since we might be doing - * this with interrupts enabled and DON'T WANt the real routine called - * until masking is set up. - */ - fakehand.ih_level = level; - *p = &fakehand; - - intr_calculatemasks(); - - /* - * Poke the real handler in now. - */ ih->ih_fun = ih_fun; ih->ih_arg = ih_arg; - ih->ih_next = NULL; ih->ih_level = level; ih->ih_irq = irq; - evcount_attach(&ih->ih_count, name, (void *)&m_hwirq[irq], + evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq, &evcount_intr); - *p = ih; + + /* + * Append handler to end of list + */ + s = ppc_intr_disable(); + + TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); + macintr_calc_mask(); + + macintr_setipl(ci->ci_cpl); + ppc_intr_enable(s); return (ih); } @@ -301,195 +340,93 @@ printf("vI %d ", irq); void macintr_disestablish(void *lcp, void *arg) { + struct cpu_info *ci = curcpu(); struct intrhand *ih = arg; int irq = ih->ih_irq; - struct intrhand **p, *q; + int s; + struct intrq *iq; if (!LEGAL_IRQ(irq)) panic("intr_disestablish: bogus irq"); /* * Remove the handler from the chain. - * This is O(n^2), too. */ - for (p = &m_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next) - ; - if (q) - *p = q->ih_next; - else - panic("intr_disestablish: handler not registered"); - evcount_detach(&ih->ih_count); - free((void *)ih, M_DEVBUF); + iq = &macintr_handler[irq]; + s = ppc_intr_disable(); - intr_calculatemasks(); + TAILQ_REMOVE(&iq->iq_list, ih, ih_list); + macintr_calc_mask(); - if (m_intrhand[irq] == NULL) - m_intrtype[irq] = IST_NONE; -} + macintr_setipl(ci->ci_cpl); + ppc_intr_enable(s); + evcount_detach(&ih->ih_count); + free((void *)ih, M_DEVBUF); -static char * -intr_typename(int type) -{ - switch (type) { - case IST_NONE : - return ("none"); - case IST_PULSE: - return ("pulsed"); - case IST_EDGE: - return ("edge-triggered"); - case IST_LEVEL: - return ("level-triggered"); - default: - panic("intr_typename: invalid type %d", type); -#if 1 /* XXX */ - return ("unknown"); -#endif - } + if (TAILQ_EMPTY(&iq->iq_list)) + iq->iq_ist = IST_NONE; } + /* * Recalculate the interrupt masks from scratch. * We could code special registry and deregistry versions of this function that * would be faster, but the code would be nastier, and we don't expect this to * happen very much anyway. */ -static void -intr_calculatemasks() +void +macintr_calc_mask() { - int irq, level; - struct intrhand *q; - - /* First, figure out which levels each IRQ uses. */ - for (irq = 0; irq < ICU_LEN; irq++) { - register int levels = 0; - for (q = m_intrhand[irq]; q; q = q->ih_next) - levels |= 1 << q->ih_level; - m_intrlevel[irq] = levels; - } + int irq; + struct intrhand *ih; + int i; - /* Then figure out which IRQs use each level. */ - for (level = IPL_NONE; level < IPL_NUM; level++) { - register int irqs = 0; - for (irq = 0; irq < ICU_LEN; irq++) - if (m_intrlevel[irq] & (1 << level)) - irqs |= 1 << irq; - imask[level] = irqs | SINT_MASK; + for (i = IPL_NONE; i < IPL_NUM; i++) { + macintr_pri_share[i] = i; } - /* - * There are tty, network and disk drivers that use free() at interrupt - * time, so vm > (tty | net | bio). - * - * Enforce a hierarchy that gives slow devices a better chance at not - * dropping data. - */ - imask[IPL_NET] |= imask[IPL_BIO]; - imask[IPL_TTY] |= imask[IPL_NET]; - imask[IPL_VM] |= imask[IPL_TTY]; - imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK; - - /* - * These are pseudo-levels. - */ - imask[IPL_NONE] = 0x00000000; - imask[IPL_HIGH] = 0xffffffff; - - /* And eventually calculate the complete masks. */ for (irq = 0; irq < ICU_LEN; irq++) { - register int irqs = 1 << irq; - for (q = m_intrhand[irq]; q; q = q->ih_next) - irqs |= imask[q->ih_level]; - m_intrmask[irq] = irqs | SINT_MASK; - } - - /* Lastly, determine which IRQs are actually in use. */ - { - register int irqs = 0; - for (irq = 0; irq < ICU_LEN; irq++) { - if (m_intrhand[irq]) - irqs |= 1 << irq; + int maxipl = IPL_NONE; + int minipl = IPL_HIGH; + struct intrq *iq = &macintr_handler[irq]; + + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { + if (ih->ih_level > maxipl) + maxipl = ih->ih_level; + if (ih->ih_level < minipl) + minipl = ih->ih_level; } - imen_m = ~irqs; - enable_irq(~imen_m); - } -} -static void -enable_irq(int x) -{ - int state0, state1, v; - int irq; - x &= HWIRQ_MASK; /* XXX Higher bits are software interrupts. */ - - state0 = state1 = 0; - while (x) { - v = 31 - cntlzw(x); - irq = m_hwirq[v]; - if (irq < 32) - state0 |= 1 << irq; - else - state1 |= 1 << (irq - 32); - - x &= ~(1 << v); - } - - if (heathrow_FCR) - out32rb(INT_ENABLE_REG1, state1); + iq->iq_ipl = maxipl; - out32rb(INT_ENABLE_REG0, state0); -} - -int m_virq_inited = 0; - -/* - * Map 64 irqs into 32 (bits). - */ -static int -mapirq(int irq) -{ - int v; - int i; + if (maxipl == IPL_NONE) { + minipl = IPL_NONE; /* Interrupt not enabled */ + } else { + for (i = minipl; i <= maxipl; i++) + macintr_pri_share[i] = i; + } - if (m_virq_inited == 0) { - m_virq_max = 0; - for (i = 0; i < ICU_LEN; i++) { - m_virq[i] = 0; + /* Enable interrupts at lower levels */ + + if (irq < 32) { + for (i = IPL_NONE; i < minipl; i++) + macintr_ienable_l[i] |= (1 << irq); + for (; i <= IPL_HIGH; i++) + macintr_ienable_l[i] &= ~(1 << irq); + } else { + for (i = IPL_NONE; i < minipl; i++) + macintr_ienable_h[i] |= (1 << (irq-32)); + for (; i <= IPL_HIGH; i++) + macintr_ienable_h[i] &= ~(1 << (irq-32)); } - m_virq_inited = 1; } - /* irq in table already? */ - if (m_virq[irq] != 0) - return m_virq[irq]; - - if (irq < 0 || irq >= 64) - panic("invalid irq %d", irq); - m_virq_max++; - v = m_virq_max; - if (v > HWIRQ_MAX) - panic("virq overflow"); - - m_hwirq[v] = irq; - m_virq[irq] = v; #if 0 -printf("\nmapirq %x to %x\n", irq, v); + for (i = 0; i < IPL_NUM; i++) + printf("imask[%d] %x %x\n", i, macintr_ienable_l[i], + macintr_ienable_h[i]); #endif - - return v; -} - -/* - * Count leading zeros. - */ -static __inline int -cntlzw(int x) -{ - int a; - - __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x)); - - return a; } /* @@ -499,143 +436,135 @@ void mac_ext_intr() { int irq = 0; - int o_imen, r_imen; int pcpl; struct cpu_info *ci = curcpu(); + struct intrq *iq; struct intrhand *ih; - volatile unsigned long int_state; pcpl = ci->ci_cpl; /* Turn off all */ - int_state = read_irq(); - if (int_state == 0) - goto out; - -start: - irq = 31 - cntlzw(int_state); + irq = macintr_read_irq(); + while (irq != 255) { + iq = &macintr_handler[irq]; + macintr_setipl(iq->iq_ipl); - o_imen = imen_m; - r_imen = 1 << irq; - - if ((ci->ci_cpl & r_imen) != 0) { - /* Masked! Mark this as pending. */ - ci->ci_ipending |= r_imen; - imen_m |= r_imen; - enable_irq(~imen_m); - } else { - splraise(m_intrmask[irq]); - - ih = m_intrhand[irq]; - while (ih) { + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { + ppc_intr_enable(1); if ((*ih->ih_fun)(ih->ih_arg)) ih->ih_count.ec_count++; - ih = ih->ih_next; + (void)ppc_intr_disable(); } + macintr_eoi(irq); + macintr_setipl(pcpl); uvmexp.intrs++; + + irq = macintr_read_irq(); } - int_state &= ~r_imen; - if (int_state) - goto start; -out: + ppc_intr_enable(1); splx(pcpl); /* Process pendings. */ } void -mac_intr_do_pending_int() +macintr_do_pending_int() { struct cpu_info *ci = curcpu(); - struct intrhand *ih; - int irq; - int pcpl; - int hwpend; + int pcpl = ci->ci_cpl; /* XXX */ int s; - - if (ci->ci_iactive) - return; - - ci->ci_iactive = 1; - pcpl = splhigh(); /* Turn off all */ s = ppc_intr_disable(); - - hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */ - imen_m &= ~hwpend; - enable_irq(~imen_m); - hwpend &= HWIRQ_MASK; - while (hwpend) { - irq = 31 - cntlzw(hwpend); - hwpend &= ~(1L << irq); - ih = m_intrhand[irq]; - while(ih) { - if ((*ih->ih_fun)(ih->ih_arg)) - ih->ih_count.ec_count++; - ih = ih->ih_next; - } + if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { + ppc_intr_enable(s); + return; } - - /*out32rb(INT_ENABLE_REG, ~imen_m);*/ + atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); do { - if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) { - ci->ci_ipending &= ~SINT_CLOCK; - softclock(); + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && (pcpl < IPL_SOFTTTY)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); + ci->ci_cpl = IPL_SOFTTTY; + ppc_intr_enable(1); + KERNEL_LOCK(); + softtty(); + KERNEL_UNLOCK(); + ppc_intr_disable(); + ci->ci_cpl = pcpl; + continue; } - if((ci->ci_ipending & SINT_NET) & ~pcpl) { + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && (pcpl < IPL_SOFTNET)) { extern int netisr; int pisr; - ci->ci_ipending &= ~SINT_NET; + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); while ((pisr = netisr) != 0) { atomic_clearbits_int(&netisr, pisr); + ci->ci_cpl = IPL_SOFTNET; + ppc_intr_enable(1); + KERNEL_LOCK(); softnet(pisr); + KERNEL_UNLOCK(); + ppc_intr_disable(); + ci->ci_cpl = pcpl; } + continue; } - if((ci->ci_ipending & SINT_TTY) & ~pcpl) { - ci->ci_ipending &= ~SINT_TTY; - softtty(); + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && (pcpl < IPL_SOFTCLOCK)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); + ci->ci_cpl = IPL_SOFTCLOCK; + ppc_intr_enable(1); + KERNEL_LOCK(); + softclock(); + KERNEL_UNLOCK(); + ppc_intr_disable(); + ci->ci_cpl = pcpl; + continue; } - } while ((ci->ci_ipending & SINT_MASK) & ~pcpl); - ci->ci_ipending &= pcpl; - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ - ppc_intr_enable(s); - ci->ci_iactive = 0; + } while (ci->ci_ipending & ppc_smask[pcpl]); + macintr_setipl(pcpl); + atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); } -static int -read_irq() +void +macintr_eoi(int irq) { - int rv = 0; - int state0, state1, p; - int state0save, state1save; + u_int32_t state0, state1; - state0 = in32rb(INT_STATE_REG0); - if (state0) + if (irq < 32) { + state0 = 1 << irq; out32rb(INT_CLEAR_REG0, state0); - state0save = state0; - while (state0) { - p = 31 - cntlzw(state0); - rv |= 1 << m_virq[p]; - state0 &= ~(1 << p); + } else { + if (heathrow_FCR) { /* has heathrow? */ + state1 = 1 << (irq - 32); + out32rb(INT_CLEAR_REG1, state1); + } } +} + +int +macintr_read_irq() +{ + struct cpu_info *ci = curcpu(); + u_int32_t state0, state1, irq_mask; + int ipl, irq; + + state0 = in32rb(INT_STATE_REG0); if (heathrow_FCR) /* has heathrow? */ state1 = in32rb(INT_STATE_REG1); else state1 = 0; - if (state1) - out32rb(INT_CLEAR_REG1, state1); - state1save = state1; - while (state1) { - p = 31 - cntlzw(state1); - rv |= 1 << m_virq[p + 32]; - state1 &= ~(1 << p); + for (ipl = IPL_HIGH; ipl >= ci->ci_cpl; ipl --) { + irq_mask = state0 & macintr_ienable_l[ipl]; + if (irq_mask) { + irq = ffs(irq_mask) - 1; + return irq; + } + irq_mask = state1 & macintr_ienable_h[ipl]; + if (irq_mask) { + irq = ffs(irq_mask) + 31; + return irq; + } } -#if 0 -printf("mac_intr int_stat 0:%x 1:%x\n", state0save, state1save); -#endif - - /* 1 << 0 is invalid. */ - return rv & ~1; + return 255; } diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c index bedd55017fd..d68949d13f2 100644 --- a/sys/arch/macppc/dev/openpic.c +++ b/sys/arch/macppc/dev/openpic.c @@ -1,6 +1,7 @@ -/* $OpenBSD: openpic.c,v 1.52 2008/11/21 17:35:52 deraadt Exp $ */ +/* $OpenBSD: openpic.c,v 1.53 2009/06/02 21:38:09 drahn Exp $ */ /*- + * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org> * Copyright (c) 1995 Per Fogelstrom * Copyright (c) 1993, 1994 Charles M. Hannum. * Copyright (c) 1990 The Regents of the University of California. @@ -56,23 +57,19 @@ #include <dev/ofw/openfirm.h> #define ICU_LEN 128 +int openpic_numirq = ICU_LEN; #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) -int o_intrtype[ICU_LEN], o_intrmaxlvl[ICU_LEN]; -struct intrhand *o_intrhand[ICU_LEN] = { 0 }; -int o_hwirq[ICU_LEN], o_virq[ICU_LEN]; -int o_virq_max; +int openpic_pri_share[IPL_NUM]; + +struct intrq openpic_handler[ICU_LEN]; -static int fakeintr(void *); -static char *intr_typename(int type); void openpic_calc_mask(void); -static __inline int cntlzw(int x); -static int mapirq(int irq); int openpic_prog_button(void *arg); -void openpic_enable_irq_mask(int irq_mask); -#define HWIRQ_MAX 27 -#define HWIRQ_MASK 0x0fffffff +ppc_splraise_t openpic_splraise; +ppc_spllower_t openpic_spllower; +ppc_splx_t openpic_splx; /* IRQ vector used for inter-processor interrupts. */ #define IPI_VECTOR_NOP 64 @@ -83,17 +80,30 @@ static struct evcount ipi_nop[PPC_MAXPROCS]; static int ipi_nopirq = IPI_VECTOR_NOP; static int ipi_ddbirq = IPI_VECTOR_DDB; #endif +struct evcount openpic_spurious; +int openpic_spurious_irq = 255; -static __inline u_int openpic_read(int); -static __inline void openpic_write(int, u_int); -void openpic_set_enable_irq(int, int); -void openpic_enable_irq(int); -void openpic_disable_irq(int); -void openpic_init(void); -void openpic_set_priority(int, int); +void openpic_enable_irq(int, int); +void openpic_disable_irq(int); +void openpic_init(void); +void openpic_set_priority(int); void openpic_ipi_ddb(void); -static __inline int openpic_read_irq(int); -static __inline void openpic_eoi(int); + +typedef void (void_f) (void); +extern void_f *pending_int_f; + +vaddr_t openpic_base; +void * openpic_intr_establish( void * lcv, int irq, int type, int level, + int (*ih_fun)(void *), void *ih_arg, char *name); +void openpic_intr_disestablish( void *lcp, void *arg); +void openpic_collect_preconf_intr(void); +int openpic_big_endian; +#ifdef MULTIPROCESSOR +intr_send_ipi_t openpic_send_ipi; +#endif + +u_int openpic_read(int reg); +void openpic_write(int reg, u_int val); struct openpic_softc { struct device sc_dev; @@ -101,9 +111,10 @@ struct openpic_softc { int openpic_match(struct device *parent, void *cf, void *aux); void openpic_attach(struct device *, struct device *, void *); -void openpic_do_pending_int(void); +void openpic_do_pending_int(int pcpl); +void openpic_do_pending_int_dis(int pcpl, int s); void openpic_collect_preconf_intr(void); -void ext_intr_openpic(void); +void openpic_ext_intr(void); struct cfattach openpic_ca = { sizeof(struct openpic_softc), @@ -115,6 +126,42 @@ struct cfdriver openpic_cd = { NULL, "openpic", DV_DULL }; +u_int +openpic_read(int reg) +{ + char *addr = (void *)(openpic_base + reg); + + asm volatile("eieio"::: "memory"); + if (openpic_big_endian) + return in32(addr); + else + return in32rb(addr); +} + +void +openpic_write(int reg, u_int val) +{ + char *addr = (void *)(openpic_base + reg); + + if (openpic_big_endian) + out32(addr, val); + else + out32rb(addr, val); + asm volatile("eieio"::: "memory"); +} + +static inline int +openpic_read_irq(int cpu) +{ + return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK; +} + +static inline void +openpic_eoi(int cpu) +{ + openpic_write(OPENPIC_EOI(cpu), 0); +} + int openpic_match(struct device *parent, void *cf, void *aux) { @@ -142,22 +189,10 @@ openpic_match(struct device *parent, void *cf, void *aux) return 1; } -typedef void (void_f) (void); -extern void_f *pending_int_f; - -vaddr_t openpic_base; -void * openpic_intr_establish( void * lcv, int irq, int type, int level, - int (*ih_fun)(void *), void *ih_arg, char *name); -void openpic_intr_disestablish( void *lcp, void *arg); -#ifdef MULTIPROCESSOR -intr_send_ipi_t openpic_send_ipi; -#endif -void openpic_collect_preconf_intr(void); -int openpic_big_endian; - void openpic_attach(struct device *parent, struct device *self, void *aux) { + struct cpu_info *ci = curcpu(); struct confargs *ca = aux; u_int32_t reg; @@ -168,12 +203,16 @@ openpic_attach(struct device *parent, struct device *self, void *aux) openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr + ca->ca_reg[0], 0x40000); - printf(": version 0x%x %s endian", openpic_read(OPENPIC_VENDOR_ID), - openpic_big_endian ? "big" : "little" ); + /* openpic may support more than 128 interupts but driver doesn't */ + openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1; + + printf(": version 0x%x feature %x %s", + openpic_read(OPENPIC_VENDOR_ID), + openpic_read(OPENPIC_FEATURE), + openpic_big_endian ? "BE" : "LE" ); openpic_init(); - pending_int_f = openpic_do_pending_int; intr_establish_func = openpic_intr_establish; intr_disestablish_func = openpic_intr_disestablish; mac_intr_establish_func = openpic_intr_establish; @@ -181,22 +220,73 @@ openpic_attach(struct device *parent, struct device *self, void *aux) #ifdef MULTIPROCESSOR intr_send_ipi_func = openpic_send_ipi; #endif - install_extint(ext_intr_openpic); -#if 1 + ppc_smask_init(); + openpic_collect_preconf_intr(); -#endif + + evcount_attach(&openpic_spurious, "spurious", + (void *)&openpic_spurious_irq, &evcount_intr); #if 1 mac_intr_establish(parent, 0x37, IST_LEVEL, IPL_HIGH, openpic_prog_button, (void *)0x37, "progbutton"); #endif + ppc_intr_func.raise = openpic_splraise; + ppc_intr_func.lower = openpic_spllower; + ppc_intr_func.x = openpic_splx; + + openpic_set_priority(ci->ci_cpl); + ppc_intr_enable(1); printf("\n"); } +static inline void +openpic_setipl(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int s; + /* XXX - try do to this without the disable */ + s = ppc_intr_disable(); + ci->ci_cpl = newcpl; + openpic_set_priority(newcpl); + ppc_intr_enable(s); +} + +int +openpic_splraise(int newcpl) +{ + struct cpu_info *ci = curcpu(); + newcpl = openpic_pri_share[newcpl]; + int ocpl = ci->ci_cpl; + if (ocpl > newcpl) + newcpl = ocpl; + + openpic_setipl(newcpl); + + return ocpl; +} + +int +openpic_spllower(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int ocpl = ci->ci_cpl; + + openpic_splx(newcpl); + + return ocpl; +} + +void +openpic_splx(int newcpl) +{ + openpic_do_pending_int(newcpl); +} + void openpic_collect_preconf_intr() { @@ -215,13 +305,6 @@ openpic_collect_preconf_intr() } } -static int -fakeintr(void *arg) -{ - - return 0; -} - /* * Register an interrupt handler. */ @@ -229,74 +312,52 @@ void * openpic_intr_establish(void *lcv, int irq, int type, int level, int (*ih_fun)(void *), void *ih_arg, char *name) { - struct intrhand **p, *q, *ih; - static struct intrhand fakehand; - - fakehand.ih_next = NULL; - fakehand.ih_fun = fakeintr; - -#if 0 -printf("mac_intr_establish, hI %d L %d ", irq, type); -#endif - - irq = mapirq(irq); -#if 0 -printf("vI %d ", irq); -#endif + struct intrhand *ih; + struct intrq *iq; + int s; /* no point in sleeping unless someone can free memory. */ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) panic("intr_establish: can't malloc handler info"); + iq = &openpic_handler[irq]; if (!LEGAL_IRQ(irq) || type == IST_NONE) panic("intr_establish: bogus irq or type"); - switch (o_intrtype[irq]) { + switch (iq->iq_ist) { case IST_NONE: - o_intrtype[irq] = type; + iq->iq_ist = type; break; case IST_EDGE: case IST_LEVEL: - if (type == o_intrtype[irq]) + if (type == iq->iq_ist) break; case IST_PULSE: if (type != IST_NONE) panic("intr_establish: can't share %s with %s", - intr_typename(o_intrtype[irq]), - intr_typename(type)); + ppc_intr_typename(iq->iq_ist), + ppc_intr_typename(type)); break; } - /* - * Figure out where to put the handler. - * This is O(N^2), but we want to preserve the order, and N is - * generally small. - */ - for (p = &o_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) - ; + ih->ih_fun = ih_fun; + ih->ih_arg = ih_arg; + ih->ih_level = level; + ih->ih_irq = irq; + + evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq, + &evcount_intr); /* - * Actually install a fake handler momentarily, since we might be doing - * this with interrupts enabled and DON'T WANt the real routine called - * until masking is set up. + * Append handler to end of list */ - fakehand.ih_level = level; - *p = &fakehand; + s = ppc_intr_disable(); + TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); openpic_calc_mask(); - /* - * Poke the real handler in now. - */ - ih->ih_fun = ih_fun; - ih->ih_arg = ih_arg; - ih->ih_next = NULL; - ih->ih_level = level; - ih->ih_irq = irq; - evcount_attach(&ih->ih_count, name, (void *)&o_hwirq[irq], - &evcount_intr); - *p = ih; + ppc_intr_enable(s); return (ih); } @@ -309,51 +370,27 @@ openpic_intr_disestablish(void *lcp, void *arg) { struct intrhand *ih = arg; int irq = ih->ih_irq; - struct intrhand **p, *q; + struct intrq *iq = &openpic_handler[irq]; + int s; if (!LEGAL_IRQ(irq)) panic("intr_disestablish: bogus irq"); /* * Remove the handler from the chain. - * This is O(n^2), too. */ - for (p = &o_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next) - ; - if (q) - *p = q->ih_next; - else - panic("intr_disestablish: handler not registered"); - - evcount_detach(&ih->ih_count); - free((void *)ih, M_DEVBUF); + s = ppc_intr_disable(); + TAILQ_REMOVE(&iq->iq_list, ih, ih_list); openpic_calc_mask(); - if (o_intrhand[irq] == NULL) - o_intrtype[irq] = IST_NONE; -} - + ppc_intr_enable(s); -static char * -intr_typename(int type) -{ + evcount_detach(&ih->ih_count); + free((void *)ih, M_DEVBUF); - switch (type) { - case IST_NONE: - return ("none"); - case IST_PULSE: - return ("pulsed"); - case IST_EDGE: - return ("edge-triggered"); - case IST_LEVEL: - return ("level-triggered"); - default: - panic("intr_typename: invalid type %d", type); -#if 1 /* XXX */ - return ("unknown"); -#endif - } + if (TAILQ_EMPTY(&iq->iq_list)) + iq->iq_ist = IST_NONE; } /* @@ -366,268 +403,142 @@ intr_typename(int type) void openpic_calc_mask() { + struct cpu_info *ci = curcpu(); int irq; struct intrhand *ih; int i; /* disable all openpic interrupts */ - openpic_set_priority(0, 15); + openpic_set_priority(15); - for (irq = 0; irq < ICU_LEN; irq++) { - int max = IPL_NONE; - int min = IPL_HIGH; - int reg; - if (o_virq[irq] != 0) { - for (ih = o_intrhand[o_virq[irq]]; ih; - ih = ih->ih_next) { - if (ih->ih_level > max) - max = ih->ih_level; - if (ih->ih_level < min) - min = ih->ih_level; - } - } + for (i = IPL_NONE; i < IPL_NUM; i++) { + openpic_pri_share[i] = i; + } - o_intrmaxlvl[irq] = max; + for (irq = 0; irq < openpic_numirq; irq++) { + int maxipl = IPL_NONE; + int minipl = IPL_HIGH; + struct intrq *iq = &openpic_handler[irq]; - /* adjust priority if it changes */ - reg = openpic_read(OPENPIC_SRC_VECTOR(irq)); - if (max != ((reg >> OPENPIC_PRIORITY_SHIFT) & 0xf)) { - openpic_write(OPENPIC_SRC_VECTOR(irq), - (reg & ~(0xf << OPENPIC_PRIORITY_SHIFT)) | - (max << OPENPIC_PRIORITY_SHIFT) ); + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { + if (ih->ih_level > maxipl) + maxipl = ih->ih_level; + if (ih->ih_level < minipl) + minipl = ih->ih_level; } - if (max == IPL_NONE) - min = IPL_NONE; /* Interrupt not enabled */ + if (maxipl == IPL_NONE) { + minipl = IPL_NONE; /* Interrupt not enabled */ - if (o_virq[irq] != 0) { - /* Enable (dont mask) interrupts at lower levels */ - for (i = IPL_NONE; i < min; i++) - imask[i] &= ~(1 << o_virq[irq]); - for (; i <= IPL_HIGH; i++) - imask[i] |= (1 << o_virq[irq]); + openpic_disable_irq(irq); + } else { + for (i = minipl; i <= maxipl; i++) { + openpic_pri_share[i] = maxipl; + } + openpic_enable_irq(irq, maxipl); } - } - - /* restore interrupts */ - openpic_set_priority(0, 0); - for (i = IPL_NONE; i <= IPL_HIGH; i++) { - if (i > IPL_NONE) - imask[i] |= SINT_MASK; + iq->iq_ipl = maxipl; } - imask[IPL_HIGH] = 0xffffffff; -} - -/* - * Map 64 irqs into 32 (bits). - */ -static int -mapirq(int irq) -{ - int v; - - /* irq in table already? */ - if (o_virq[irq] != 0) - return o_virq[irq]; - - if (irq < 0 || irq >= ICU_LEN) - panic("invalid irq %d", irq); - - o_virq_max++; - v = o_virq_max; - if (v > HWIRQ_MAX) - panic("virq overflow"); - - o_hwirq[v] = irq; - o_virq[irq] = v; -#if 0 -printf("\nmapirq %x to %x\n", irq, v); -#endif - return v; -} - -/* - * Count leading zeros. - */ -static __inline int -cntlzw(int x) -{ - int a; - - __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x)); - - return a; + /* restore interrupts */ + openpic_set_priority(ci->ci_cpl); } -void openpic_do_pending_softint(int pcpl); - void -openpic_do_pending_int() +openpic_do_pending_int(int pcpl) { - struct cpu_info *ci = curcpu(); - struct intrhand *ih; - int irq; - int pcpl; - int hwpend; - int pri, pripending; int s; - - if (ci->ci_iactive & CI_IACTIVE_PROCESSING_HARD) - return; - - atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_HARD); s = ppc_intr_disable(); - pcpl = ci->ci_cpl; - - hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */ - hwpend &= HWIRQ_MASK; - while (hwpend) { - /* this still doesn't handle the interrupts in priority order */ - for (pri = IPL_HIGH; pri >= IPL_NONE; pri--) { - pripending = hwpend & ~imask[pri]; - irq = 31 - cntlzw(pripending); - ci->ci_ipending &= ~(1L << irq); - ci->ci_cpl = imask[o_intrmaxlvl[o_hwirq[irq]]]; - openpic_enable_irq_mask(~ci->ci_cpl); - ih = o_intrhand[irq]; - while(ih) { - ppc_intr_enable(1); - - KERNEL_LOCK(); - if ((*ih->ih_fun)(ih->ih_arg)) - ih->ih_count.ec_count++; - KERNEL_UNLOCK(); - - (void)ppc_intr_disable(); - - ih = ih->ih_next; - } - } - hwpend = ci->ci_ipending & ~pcpl;/* Catch new pendings */ - hwpend &= HWIRQ_MASK; - } - ci->ci_cpl = pcpl | SINT_MASK; - openpic_enable_irq_mask(~ci->ci_cpl); - atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_HARD); - - openpic_do_pending_softint(pcpl); - + openpic_do_pending_int_dis(pcpl, s); ppc_intr_enable(s); + } +/* + * This function expect interrupts disabled on entry and exit, + * the s argument indicates if interrupts may be enabled during + * the processing of off level interrupts, s 'should' always be 1. + */ void -openpic_do_pending_softint(int pcpl) +openpic_do_pending_int_dis(int pcpl, int s) { struct cpu_info *ci = curcpu(); + int loopcount = 0; - if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) + if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { + /* soft interrupts are being processed, just set ipl/return */ + openpic_setipl(pcpl); return; + } atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); do { - if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) { - ci->ci_ipending &= ~SINT_CLOCK; - ci->ci_cpl = SINT_CLOCK|SINT_NET|SINT_TTY; - ppc_intr_enable(1); + loopcount ++; + if (loopcount > 50) + printf("do_pending looping %d pcpl %x %x\n", loopcount, + pcpl, ci->ci_cpl); + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && + (pcpl < IPL_SOFTTTY)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); + + openpic_setipl(IPL_SOFTTTY); + ppc_intr_enable(s); KERNEL_LOCK(); - softclock(); + softtty(); KERNEL_UNLOCK(); ppc_intr_disable(); continue; } - if((ci->ci_ipending & SINT_NET) & ~pcpl) { + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && + (pcpl < IPL_SOFTNET)) { extern int netisr; int pisr; - - ci->ci_ipending &= ~SINT_NET; - ci->ci_cpl = SINT_NET|SINT_TTY; + + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); + openpic_setipl(IPL_SOFTNET); + ppc_intr_enable(s); + KERNEL_LOCK(); while ((pisr = netisr) != 0) { atomic_clearbits_int(&netisr, pisr); - ppc_intr_enable(1); - KERNEL_LOCK(); softnet(pisr); - KERNEL_UNLOCK(); - ppc_intr_disable(); } + KERNEL_UNLOCK(); + ppc_intr_disable(); continue; } - if((ci->ci_ipending & SINT_TTY) & ~pcpl) { - ci->ci_ipending &= ~SINT_TTY; - ci->ci_cpl = SINT_TTY; - ppc_intr_enable(1); + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && + (pcpl < IPL_SOFTCLOCK)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); + openpic_setipl(IPL_SOFTCLOCK); + ppc_intr_enable(s); KERNEL_LOCK(); - softtty(); + softclock(); KERNEL_UNLOCK(); ppc_intr_disable(); continue; } - } while ((ci->ci_ipending & SINT_MASK) & ~pcpl); - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ + break; + } while (ci->ci_ipending & ppc_smask[pcpl]); + openpic_setipl(pcpl); /* Don't use splx... we are here already! */ atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); } -u_int -openpic_read(int reg) -{ - char *addr = (void *)(openpic_base + reg); - - if (openpic_big_endian) - return in32(addr); - else - return in32rb(addr); -} - void -openpic_write(int reg, u_int val) -{ - char *addr = (void *)(openpic_base + reg); - - if (openpic_big_endian) - out32(addr, val); - else - out32rb(addr, val); -} - -void -openpic_enable_irq_mask(int irq_mask) -{ - int irq; - for ( irq = 0; irq <= o_virq_max; irq++) { - if (irq_mask & (1 << irq)) - openpic_enable_irq(o_hwirq[irq]); - else - openpic_disable_irq(o_hwirq[irq]); - } -} - -void -openpic_set_enable_irq(int irq, int type) +openpic_enable_irq(int irq, int pri) { u_int x; + struct intrq *iq = &openpic_handler[irq]; - x = openpic_read(OPENPIC_SRC_VECTOR(irq)); - x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE); - if (type == IST_LEVEL) - x |= OPENPIC_SENSE_LEVEL; - else - x |= OPENPIC_SENSE_EDGE; - openpic_write(OPENPIC_SRC_VECTOR(irq), x); -} -void -openpic_enable_irq(int irq) -{ - u_int x; - - x = openpic_read(OPENPIC_SRC_VECTOR(irq)); - x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE); - if (o_intrtype[o_virq[irq]] == IST_LEVEL) + x = irq; + if (iq->iq_ist == IST_LEVEL) x |= OPENPIC_SENSE_LEVEL; else x |= OPENPIC_SENSE_EDGE; + x |= OPENPIC_POLARITY_POSITIVE; + x |= pri << OPENPIC_PRIORITY_SHIFT; openpic_write(OPENPIC_SRC_VECTOR(irq), x); } @@ -642,31 +553,13 @@ openpic_disable_irq(int irq) } void -openpic_set_priority(int cpu, int pri) +openpic_set_priority(int pri) { - u_int x; - - x = openpic_read(OPENPIC_CPU_PRIORITY(cpu)); - x &= ~OPENPIC_CPU_PRIORITY_MASK; - x |= pri; - openpic_write(OPENPIC_CPU_PRIORITY(cpu), x); -} - -int -openpic_read_irq(int cpu) -{ - return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK; -} - -void -openpic_eoi(int cpu) -{ - openpic_write(OPENPIC_EOI(cpu), 0); - openpic_read(OPENPIC_EOI(cpu)); + struct cpu_info *ci = curcpu(); + openpic_write(OPENPIC_CPU_PRIORITY(ci->ci_cpuid), pri); } #ifdef MULTIPROCESSOR - void openpic_send_ipi(struct cpu_info *ci, int id) { @@ -681,104 +574,148 @@ openpic_send_ipi(struct cpu_info *ci, int id) panic("invalid ipi send to cpu %d %d\n", ci->ci_cpuid, id); } - openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid); } #endif +int openpic_irqnest[PPC_MAXPROCS]; +int openpic_irqloop[PPC_MAXPROCS]; void -ext_intr_openpic() +openpic_ext_intr() { struct cpu_info *ci = curcpu(); - int irq, realirq; - int r_imen; - int pcpl, ocpl; + int irq; + int pcpl; + int maxipl = IPL_NONE; struct intrhand *ih; + struct intrq *iq; + int spurious; pcpl = ci->ci_cpl; - realirq = openpic_read_irq(ci->ci_cpuid); - - while (realirq != 255) { + openpic_irqloop[ci->ci_cpuid] = 0; + irq = openpic_read_irq(ci->ci_cpuid); + openpic_irqnest[ci->ci_cpuid]++; + + while (irq != 255) { + openpic_irqloop[ci->ci_cpuid]++; + if (openpic_irqloop[ci->ci_cpuid] > 20 || + openpic_irqnest[ci->ci_cpuid] > 3) { + printf("irqloop %d irqnest %d\n", + openpic_irqloop[ci->ci_cpuid], + openpic_irqnest[ci->ci_cpuid]); + } #ifdef MULTIPROCESSOR - if (realirq == IPI_VECTOR_NOP) { + if (irq == IPI_VECTOR_NOP) { ipi_nop[ci->ci_cpuid].ec_count++; openpic_eoi(ci->ci_cpuid); - realirq = openpic_read_irq(ci->ci_cpuid); + irq = openpic_read_irq(ci->ci_cpuid); continue; } - if (realirq == IPI_VECTOR_DDB) { + if (irq == IPI_VECTOR_DDB) { ipi_ddb[ci->ci_cpuid].ec_count++; openpic_eoi(ci->ci_cpuid); openpic_ipi_ddb(); - realirq = openpic_read_irq(ci->ci_cpuid); + irq = openpic_read_irq(ci->ci_cpuid); continue; } #endif + iq = &openpic_handler[irq]; + + if (iq->iq_ipl <= ci->ci_cpl) + printf("invalid interrupt %d lvl %d at %d hw %d\n", + irq, iq->iq_ipl, ci->ci_cpl, + openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid))); + if (iq->iq_ipl > maxipl) + maxipl = iq->iq_ipl; + splraise(iq->iq_ipl); + openpic_eoi(ci->ci_cpuid); + + spurious = 1; + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { + ppc_intr_enable(1); + KERNEL_LOCK(); + if ((*ih->ih_fun)(ih->ih_arg)) { + ih->ih_count.ec_count++; + spurious = 0; + } + KERNEL_UNLOCK(); - irq = o_virq[realirq]; - - /* XXX check range */ - - r_imen = 1 << irq; - - if ((pcpl & r_imen) != 0) { - /* Masked! Mark this as pending. */ - ci->ci_ipending |= r_imen; - openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]); - openpic_eoi(ci->ci_cpuid); - } else { - openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]); - openpic_eoi(ci->ci_cpuid); - ocpl = splraise(imask[o_intrmaxlvl[realirq]]); + (void)ppc_intr_disable(); + } + if (spurious) { + openpic_spurious.ec_count++; +#ifdef OPENPIC_NOISY + printf("spurious intr %d\n", irq); +#endif + } - ih = o_intrhand[irq]; - while (ih) { - ppc_intr_enable(1); + uvmexp.intrs++; + openpic_setipl(pcpl); - KERNEL_LOCK(); - if ((*ih->ih_fun)(ih->ih_arg)) - ih->ih_count.ec_count++; - KERNEL_UNLOCK(); + irq = openpic_read_irq(ci->ci_cpuid); + } - (void)ppc_intr_disable(); - ih = ih->ih_next; + if (openpic_irqnest[ci->ci_cpuid] == 1) { + openpic_irqloop[ci->ci_cpuid] = 0; + /* raise IPL back to max until do_pending will lower it back */ + openpic_setipl(maxipl); + /* + * we must not process pending soft interrupts when nested, can + * cause excessive recursion. + * + * The loop here is because an interrupt could case a pending + * soft interrupt between the finishing of the + * openpic_do_pending_int, but before ppc_intr_disable + */ + do { + openpic_irqloop[ci->ci_cpuid]++; + if (openpic_irqloop[ci->ci_cpuid] > 5) { + printf("ext_intr: do_pending loop %d\n", + openpic_irqloop[ci->ci_cpuid]); } - - uvmexp.intrs++; - __asm__ volatile("":::"memory"); /* don't reorder.... */ - ci->ci_cpl = ocpl; - __asm__ volatile("":::"memory"); /* don't reorder.... */ - openpic_enable_irq_mask(~pcpl); - } - - realirq = openpic_read_irq(ci->ci_cpuid); + if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { + openpic_setipl(pcpl); + /* + * some may be pending but someone else is + * processing them + */ + break; + } else { + openpic_do_pending_int_dis(pcpl, 1); + } + } while (ci->ci_ipending & ppc_smask[pcpl]); } - ppc_intr_enable(1); - - splx(pcpl); /* Process pendings. */ + openpic_irqnest[ci->ci_cpuid]--; } void openpic_init() { + struct cpu_info *ci = curcpu(); + struct intrq *iq; int irq; u_int x; + int i; + + openpic_set_priority(15); /* disable all interrupts */ - for (irq = 0; irq < 255; irq++) + for (irq = 0; irq < openpic_numirq; irq++) openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK); - openpic_set_priority(0, 15); + + for (i = 0; i < openpic_numirq; i++) { + iq = &openpic_handler[i]; + TAILQ_INIT(&iq->iq_list); + } /* we don't need 8259 pass through mode */ x = openpic_read(OPENPIC_CONFIG); x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; openpic_write(OPENPIC_CONFIG, x); - /* send all interrupts to cpu 0 */ - for (irq = 0; irq < ICU_LEN; irq++) - openpic_write(OPENPIC_IDEST(irq), 1 << 0); + /* initialize all vectors to something sane */ for (irq = 0; irq < ICU_LEN; irq++) { x = irq; x |= OPENPIC_IMASK; @@ -788,6 +725,17 @@ openpic_init() openpic_write(OPENPIC_SRC_VECTOR(irq), x); } + /* send all interrupts to cpu 0 */ + for (irq = 0; irq < openpic_numirq; irq++) + openpic_write(OPENPIC_IDEST(irq), 1 << 0); + + /* clear all pending interrunts */ + for (irq = 0; irq < ICU_LEN; irq++) { + openpic_read_irq(ci->ci_cpuid); + openpic_eoi(ci->ci_cpuid); + } + + #ifdef MULTIPROCESSOR /* Set up inter-processor interrupts. */ /* IPI0 - NOP */ @@ -801,6 +749,7 @@ openpic_init() x |= (15 << OPENPIC_PRIORITY_SHIFT) | IPI_VECTOR_DDB; openpic_write(OPENPIC_IPI_VECTOR(1), x); + /* XXX - ncpus */ evcount_attach(&ipi_nop[0], "ipi_nop0", (void *)&ipi_nopirq, &evcount_intr); evcount_attach(&ipi_nop[1], "ipi_nop1", (void *)&ipi_nopirq, @@ -811,21 +760,21 @@ openpic_init() &evcount_intr); #endif - /* XXX set spurious intr vector */ - - openpic_set_priority(0, 0); - /* clear all pending interrunts */ for (irq = 0; irq < ICU_LEN; irq++) { openpic_read_irq(0); openpic_eoi(0); } - for (irq = 0; irq < ICU_LEN; irq++) - openpic_disable_irq(irq); +#if 0 + openpic_write(OPENPIC_SPURIOUS_VECTOR, 255); +#endif + + install_extint(openpic_ext_intr); - install_extint(ext_intr_openpic); + openpic_set_priority(0); } + /* * programmer_button function to fix args to Debugger. * deal with any enables/disables, if necessary. @@ -842,10 +791,11 @@ openpic_prog_button (void *arg) return 1; } - void -openpic_ipi_ddb(void) +openpic_ipi_ddb() { +#ifdef OPENPIC_NOISY + printf("ipi_ddb() called\n"); +#endif Debugger(); } - diff --git a/sys/arch/macppc/include/intr.h b/sys/arch/macppc/include/intr.h index c881dc54add..92ef9bfec34 100644 --- a/sys/arch/macppc/include/intr.h +++ b/sys/arch/macppc/include/intr.h @@ -1,9 +1,9 @@ -/* $OpenBSD: intr.h,v 1.6 2008/11/21 17:35:52 deraadt Exp $ */ +/* $OpenBSD: intr.h,v 1.7 2009/06/02 21:38:09 drahn Exp $ */ #include <powerpc/intr.h> #ifndef _LOCORE void softtty(void); -void openpic_set_priority(int, int); +void openpic_set_priority(int); #endif diff --git a/sys/arch/macppc/macppc/clock.c b/sys/arch/macppc/macppc/clock.c index 3ff3e9243cf..f74bcdfa750 100644 --- a/sys/arch/macppc/macppc/clock.c +++ b/sys/arch/macppc/macppc/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.27 2009/06/02 21:23:55 drahn Exp $ */ +/* $OpenBSD: clock.c,v 1.28 2009/06/02 21:38:09 drahn Exp $ */ /* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */ /* @@ -225,7 +225,7 @@ decr_intr(struct clockframe *frame) */ ppc_mtdec(nextevent - tb); - if (ci->ci_cpl & SPL_CLOCK) { + if (ci->ci_cpl >= IPL_CLOCK) { ci->ci_statspending += nstats; } else { KERNEL_LOCK(); diff --git a/sys/arch/macppc/macppc/cpu.c b/sys/arch/macppc/macppc/cpu.c index e76832070d2..87b31161710 100644 --- a/sys/arch/macppc/macppc/cpu.c +++ b/sys/arch/macppc/macppc/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.61 2009/04/14 16:01:04 oga Exp $ */ +/* $OpenBSD: cpu.c,v 1.62 2009/06/02 21:38:09 drahn Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -790,7 +790,7 @@ cpu_hatch(void) ppc_intr_enable(intrstate); /* Enable inter-processor interrupts. */ - openpic_set_priority(curcpu()->ci_cpuid, 14); + openpic_set_priority(14); SCHED_LOCK(s); cpu_switchto(NULL, sched_chooseproc()); diff --git a/sys/arch/macppc/macppc/genassym.cf b/sys/arch/macppc/macppc/genassym.cf index 50438c0f76e..a8c1410305b 100644 --- a/sys/arch/macppc/macppc/genassym.cf +++ b/sys/arch/macppc/macppc/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.19 2008/11/21 17:35:52 deraadt Exp $ +# $OpenBSD: genassym.cf,v 1.20 2009/06/02 21:38:09 drahn Exp $ # # Copyright (c) 1982, 1990 The Regents of the University of California. # All rights reserved. @@ -86,7 +86,6 @@ member ci_curproc member ci_curpcb member ci_curpm member ci_want_resched -member ci_cpl member ci_intrdepth member ci_intstk member ci_tempsave diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c index 67005512a79..bf30d430a40 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.104 2009/01/22 22:41:42 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.105 2009/06/02 21:38:09 drahn Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -877,8 +877,6 @@ dumpsys() } -int imask[IPL_NUM]; - /* * this is a hack interface to allow zs to work better until * a true soft interrupt mechanism is created. diff --git a/sys/arch/powerpc/include/intr.h b/sys/arch/powerpc/include/intr.h index d2f85d51aaf..fd930ce08e9 100644 --- a/sys/arch/powerpc/include/intr.h +++ b/sys/arch/powerpc/include/intr.h @@ -1,8 +1,8 @@ -/* $OpenBSD: intr.h,v 1.39 2009/03/15 19:40:40 miod Exp $ */ +/* $OpenBSD: intr.h,v 1.40 2009/06/02 21:38:10 drahn Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,14 +36,18 @@ #define _POWERPC_INTR_H_ #define IPL_NONE 0 -#define IPL_BIO 1 +#define IPL_SOFT 1 +#define IPL_SOFTCLOCK 2 +#define IPL_SOFTNET 3 +#define IPL_SOFTTTY 4 +#define IPL_BIO 5 #define IPL_AUDIO IPL_BIO /* XXX - was defined this val in audio_if.h */ -#define IPL_NET 2 -#define IPL_TTY 3 -#define IPL_VM 4 -#define IPL_CLOCK 5 -#define IPL_HIGH 6 -#define IPL_NUM 7 +#define IPL_NET 6 +#define IPL_TTY 7 +#define IPL_VM 8 +#define IPL_CLOCK 9 +#define IPL_HIGH 10 +#define IPL_NUM 11 #define IST_NONE 0 #define IST_PULSE 1 @@ -55,9 +59,9 @@ #include <sys/evcount.h> #include <machine/atomic.h> -#define PPC_NIRQ 66 -#define PPC_CLK_IRQ 64 -#define PPC_STAT_IRQ 65 +#define PPC_NIRQ 66 +#define PPC_CLK_IRQ 64 +#define PPC_STAT_IRQ 65 void setsoftclock(void); void clearsoftclock(void); @@ -70,10 +74,22 @@ int splraise(int); int spllower(int); void splx(int); +typedef int (ppc_splraise_t) (int); +typedef int (ppc_spllower_t) (int); +typedef void (ppc_splx_t) (int); -void do_pending_int(void); +extern struct ppc_intr_func { + ppc_splraise_t *raise; + ppc_spllower_t *lower; + ppc_splx_t *x; +}ppc_intr_func; + +extern int ppc_smask[IPL_NUM]; -extern int imask[IPL_NUM]; +void ppc_smask_init(void); +char *ppc_intr_typename(int type); + +void do_pending_int(void); /* SPL asserts */ #define splassert(wantipl) /* nothing */ @@ -81,38 +97,32 @@ extern int imask[IPL_NUM]; #define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p) -#define SINT_CLOCK 0x10000000 -#define SINT_NET 0x20000000 -#define SINT_TTY 0x40000000 -#define SPL_CLOCK 0x80000000 -#define SINT_MASK (SINT_CLOCK|SINT_NET|SINT_TTY) - -#define splbio() splraise(imask[IPL_BIO]) -#define splnet() splraise(imask[IPL_NET]) -#define spltty() splraise(imask[IPL_TTY]) -#define splaudio() splraise(imask[IPL_AUDIO]) -#define splclock() splraise(imask[IPL_CLOCK]) -#define splvm() splraise(imask[IPL_VM]) -#define splsched() splhigh() -#define spllock() splhigh() -#define splstatclock() splhigh() -#define splsoftclock() splraise(SINT_CLOCK) -#define splsoftnet() splraise(SINT_NET|SINT_CLOCK) -#define splsofttty() splraise(SINT_TTY|SINT_NET|SINT_CLOCK) - -#define setsoftclock() set_sint(SINT_CLOCK); -#define setsoftnet() set_sint(SINT_NET); -#define setsofttty() set_sint(SINT_TTY); - -#define splhigh() splraise(0xffffffff) -#define spl0() spllower(0) +#define splbio() splraise(IPL_BIO) +#define splnet() splraise(IPL_NET) +#define spltty() splraise(IPL_TTY) +#define splaudio() splraise(IPL_AUDIO) +#define splclock() splraise(IPL_CLOCK) +#define splvm() splraise(IPL_VM) +#define splsched() splhigh() +#define spllock() splhigh() +#define splstatclock() splhigh() +#define splsoftclock() splraise(IPL_SOFTCLOCK) +#define splsoftnet() splraise(IPL_SOFTNET) +#define splsofttty() splraise(IPL_SOFTTTY) + +#define setsoftclock() set_sint(SI_TO_IRQBIT(SI_SOFTCLOCK)) +#define setsoftnet() set_sint(SI_TO_IRQBIT(SI_SOFTNET)) +#define setsofttty() set_sint(SI_TO_IRQBIT(SI_SOFTTTY)) + +#define splhigh() splraise(IPL_HIGH) +#define spl0() spllower(IPL_NONE) /* * Interrupt control struct used to control the ICU setup. */ struct intrhand { - struct intrhand *ih_next; + TAILQ_ENTRY(intrhand) ih_list; int (*ih_fun)(void *); void *ih_arg; struct evcount ih_count; @@ -120,11 +130,36 @@ struct intrhand { int ih_irq; char *ih_what; }; + +struct intrq { + TAILQ_HEAD(, intrhand) iq_list; /* handler list */ + int iq_ipl; /* IPL_ to mask while handling */ + int iq_ist; /* share type */ +}; + extern int ppc_configed_intr_cnt; -#define MAX_PRECONF_INTR 16 +#define MAX_PRECONF_INTR 16 extern struct intrhand ppc_configed_intr[MAX_PRECONF_INTR]; void softnet(int isr); +#define SI_TO_IRQBIT(x) (1 << (x)) + +#define SI_SOFT 0 /* for IPL_SOFT */ +#define SI_SOFTCLOCK 1 /* for IPL_SOFTCLOCK */ +#define SI_SOFTNET 2 /* for IPL_SOFTNET */ +#define SI_SOFTTTY 3 /* for IPL_SOFTSERIAL */ + +#if 0 +#define SI_NQUEUES 4 + +#define SI_QUEUENAMES { \ + "generic", \ + "clock", \ + "net", \ + "serial", \ +} +#endif + #define PPC_IPI_NOP 0 #define PPC_IPI_DDB 1 diff --git a/sys/arch/powerpc/powerpc/intr.c b/sys/arch/powerpc/powerpc/intr.c index 722477c74cd..56e919dbe58 100644 --- a/sys/arch/powerpc/powerpc/intr.c +++ b/sys/arch/powerpc/powerpc/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.4 2008/11/21 17:35:52 deraadt Exp $ */ +/* $OpenBSD: intr.c,v 1.5 2009/06/02 21:38:10 drahn Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. @@ -35,45 +35,121 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/lock.h> + +int ppc_dflt_splraise(int); +int ppc_dflt_spllower(int); +void ppc_dflt_splx(int); + +/* provide a function for asm code to call */ +#undef splraise +#undef spllower +#undef splx + +int ppc_smask[IPL_NUM]; + +void +ppc_smask_init() +{ + int i; + + for (i = IPL_NONE; i <= IPL_HIGH; i++) { + ppc_smask[i] = 0; +#if 0 + /* NOT YET */ + if (i < IPL_SOFT) + ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFT); +#endif + if (i < IPL_SOFTCLOCK) + ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK); + if (i < IPL_SOFTNET) + ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET); + if (i < IPL_SOFTTTY) + ppc_smask[i] |= SI_TO_IRQBIT(SI_SOFTTTY); + } +} + int splraise(int newcpl) { + return ppc_intr_func.raise(newcpl); +} + +int +spllower(int newcpl) +{ + return ppc_intr_func.lower(newcpl); +} + +void +splx(int newcpl) +{ + ppc_intr_func.x(newcpl); +} + +/* + * functions with 'default' behavior to use before the real + * interrupt controller attaches + */ +int +ppc_dflt_splraise(int newcpl) +{ struct cpu_info *ci = curcpu(); int oldcpl; - __asm__ volatile("":::"memory"); /* reorder protect */ oldcpl = ci->ci_cpl; - ci->ci_cpl = oldcpl | newcpl; - __asm__ volatile("":::"memory"); + if (newcpl < oldcpl) + newcpl = oldcpl; + ci->ci_cpl = newcpl; return (oldcpl); } int -spllower(int newcpl) +ppc_dflt_spllower(int newcpl) { struct cpu_info *ci = curcpu(); int oldcpl; - __asm__ volatile("":::"memory"); /* reorder protect */ oldcpl = ci->ci_cpl; - ci->ci_cpl = newcpl; - if (ci->ci_ipending & ~newcpl) - do_pending_int(); - __asm__ volatile("":::"memory"); + + splx(newcpl); return (oldcpl); } void -splx(int newcpl) +ppc_dflt_splx(int newcpl) { struct cpu_info *ci = curcpu(); - __asm__ volatile("":::"memory"); /* reorder protect */ ci->ci_cpl = newcpl; - if (ci->ci_ipending & ~newcpl) + + if (ci->ci_ipending & ppc_smask[newcpl]) do_pending_int(); - __asm__ volatile("":::"memory"); +} + +struct ppc_intr_func ppc_intr_func = +{ + ppc_dflt_splraise, + ppc_dflt_spllower, + ppc_dflt_splx +}; + +char * +ppc_intr_typename(int type) +{ + switch (type) { + case IST_NONE : + return ("none"); + case IST_PULSE: + return ("pulsed"); + case IST_EDGE: + return ("edge-triggered"); + case IST_LEVEL: + return ("level-triggered"); + default: + return ("unknown"); + } } diff --git a/sys/arch/powerpc/powerpc/mutex.S b/sys/arch/powerpc/powerpc/mutex.S index 5f45f1f7673..6511203f606 100644 --- a/sys/arch/powerpc/powerpc/mutex.S +++ b/sys/arch/powerpc/powerpc/mutex.S @@ -1,4 +1,4 @@ -/* $OpenBSD: mutex.S,v 1.7 2009/04/27 21:48:56 kettenis Exp $ */ +/* $OpenBSD: mutex.S,v 1.8 2009/06/02 21:38:10 drahn Exp $ */ /* * Copyright (c) 2007 Dale Rahn @@ -22,7 +22,11 @@ #include <machine/asm.h> /* XXX */ +#ifdef USERLAND +#define GET_CPUINFO(r) mr r, %r4 +#else #define GET_CPUINFO(r) mfsprg r,0 +#endif ENTRY(mtx_init) li %r5,0 @@ -32,44 +36,44 @@ ENTRY(mtx_init) blr +/* + * mtx_enter(struct mutex *mtx[%r3]) + */ ENTRY(mtx_enter) - stwu %r1,-32(%r1) # reserve stack + stwu %r1,-16(%r1) # reserve stack mflr %r0 - stw %r0,36(%r1) # save return address + stw %r0,20(%r1) # save return address .L_retry: + stw %r3, 12(%r1) + lwz %r3,MTX_WANTIPL(%r3) # load new ipl + bl _C_LABEL(splraise) + mr %r7, %r3 GET_CPUINFO(%r4) - lwz %r5,MTX_WANTIPL(%r3) # load new ipl - lis %r6,_C_LABEL(imask)@ha # convert into cpl - slwi %r5,%r5,2 - addi %r5,%r5,_C_LABEL(imask)@l - lwzx %r5,%r5,%r6 - lwz %r7,CI_CPL(%r4) # load current cpl - or %r6,%r5,%r7 # raise cpl - stw %r6,CI_CPL(%r4) # store new cpl + lwz %r3,12(%r1) li %r5,MTX_OWNER # load offset constant lwarx %r6,%r5,%r3 # load reserve owner cmpwi 0,%r6,0 # test owner == 0 beq+ 0,.L_mutex_free # if owner == 0 branch free -.L_mutex_locked: #ifdef DIAGNOSTIC cmpl 0,%r4,%r6 beq- .L_mutex_selflocked #endif - stw %r3,28(%r1) # save mtx during lcsplx - la %r4,28(%r1) +.L_mutex_busy: + stw %r3,12(%r1) # save mtx during lcsplx + la %r4,12(%r1) stwcx. %r3,0,%r4 # unreserve owner mr %r3,%r7 # move old cpl to arg0 bl _C_LABEL(lcsplx) # call splx on old cpl - lwz %r3,28(%r1) + lwz %r3,12(%r1) b .L_retry .L_mutex_free: stwcx. %r4,%r5,%r3 # old owner was 0 cond store - bne- .L_mutex_locked # branch if reserve cancelled + bne- .L_mutex_busy # branch if reserve cancelled stw %r7,MTX_OLDCPL(%r3) # save old ipl - lwz %r0,36(%r1) # load return address + lwz %r0,20(%r1) # load return address mtlr %r0 - addi %r1,%r1,32 # restore stack + addi %r1,%r1,16 # restore stack blr #ifdef DIAGNOSTIC @@ -94,11 +98,7 @@ ENTRY(mtx_leave) lwz %r5,MTX_OLDCPL(%r3) stw %r4,MTX_OLDCPL(%r3) stw %r4,MTX_OWNER(%r3) - GET_CPUINFO(%r4) mr %r3,%r5 - lwz %r5,CI_CPL(%r4) - cmpl 0,%r3,%r5 - beq 1f b _C_LABEL(lcsplx) 1: blr diff --git a/sys/arch/socppc/dev/ipic.c b/sys/arch/socppc/dev/ipic.c index f48770b9efb..364a0e401b3 100644 --- a/sys/arch/socppc/dev/ipic.c +++ b/sys/arch/socppc/dev/ipic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipic.c,v 1.6 2008/12/04 16:02:20 maja Exp $ */ +/* $OpenBSD: ipic.c,v 1.7 2009/06/02 21:38:10 drahn Exp $ */ /* * Copyright (c) 2008 Mark Kettenis @@ -63,7 +63,7 @@ struct ipic_softc { }; uint32_t ipic_imask; -struct intrhand *ipic_intrhand[IPIC_NVEC]; +struct intrq ipic_handler[IPIC_NVEC]; struct ipic_softc *ipic_sc; int ipic_match(struct device *, void *, void *); @@ -82,9 +82,17 @@ void ipic_write(struct ipic_softc *, bus_addr_t, uint32_t); uint32_t ipic_simsr_h(int); uint32_t ipic_simsr_l(int); uint32_t ipic_semsr(int); +void ipic_calc_masks(void); void ext_intr(void); -void ipic_do_pending_int(void); + +ppc_splraise_t ipic_splraise; +ppc_spllower_t ipic_spllower; +ppc_splx_t ipic_splx; + +void ipic_setipl(int); +void ipic_do_pending(int); + int ipic_match(struct device *parent, void *cfdata, void *aux) @@ -97,6 +105,8 @@ ipic_attach(struct device *parent, struct device *self, void *aux) { struct ipic_softc *sc = (void *)self; struct obio_attach_args *oa = aux; + struct intrq *iq; + int i; sc->sc_iot = oa->oa_iot; if (bus_space_map(sc->sc_iot, oa->oa_offset, 128, 0, &sc->sc_ioh)) { @@ -105,6 +115,17 @@ ipic_attach(struct device *parent, struct device *self, void *aux) } ipic_sc = sc; + + for (i = 0; i < IPIC_NVEC; i++) { + iq = &ipic_handler[i]; + TAILQ_INIT(&iq->iq_list); + } + + ppc_smask_init(); + ppc_intr_func.raise = ipic_splraise; + ppc_intr_func.lower = ipic_spllower; + ppc_intr_func.x = ipic_splx; + printf("\n"); } @@ -176,32 +197,10 @@ ipic_semsr(int ivec) return 0; } -static void -intr_calculatemasks(void) +void +ipic_calc_masks(void) { struct ipic_softc *sc = ipic_sc; - int level; - - for (level = IPL_NONE; level < IPL_NUM; level++) - imask[level] = SINT_MASK | (1 << level); - - /* - * There are tty, network and disk drivers that use free() at interrupt - * time, so vm > (tty | net | bio). - * - * Enforce a hierarchy that gives slow devices a better chance at not - * dropping data. - */ - imask[IPL_NET] |= imask[IPL_BIO]; - imask[IPL_TTY] |= imask[IPL_NET]; - imask[IPL_VM] |= imask[IPL_TTY]; - imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK; - - /* - * These are pseudo-levels. - */ - imask[IPL_NONE] = 0x00000000; - imask[IPL_HIGH] = 0xffffffff; sc->sc_simsr_h[IPL_NET] |= sc->sc_simsr_h[IPL_BIO]; sc->sc_simsr_h[IPL_TTY] |= sc->sc_simsr_h[IPL_NET]; @@ -227,31 +226,40 @@ intr_establish(int ivec, int type, int level, int (*ih_fun)(void *), void *ih_arg, const char *name) { struct ipic_softc *sc = ipic_sc; - struct intrhand **p, *q, *ih; + struct intrhand *ih; + struct intrq *iq; uint32_t mask; + int s; ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) panic("%s: malloc failed", __func__); + iq = &ipic_handler[ivec]; if (ivec < 0 || ivec >= IPIC_NVEC) panic("%s: invalid vector %d", __func__, ivec); - for (p = &ipic_intrhand[ivec]; (q = *p) != NULL; p = &q->ih_next) - ; - sc->sc_simsr_h[level] |= ipic_simsr_h(ivec); sc->sc_simsr_l[level] |= ipic_simsr_l(ivec); sc->sc_semsr[level] |= ipic_semsr(ivec); - intr_calculatemasks(); ih->ih_fun = ih_fun; ih->ih_arg = ih_arg; - ih->ih_next = NULL; ih->ih_level = level; ih->ih_irq = ivec; - evcount_attach(&ih->ih_count, name, NULL, &evcount_intr); - *p = ih; + + evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq, + &evcount_intr); + + /* + * Append handler to end of list + */ + s = ppc_intr_disable(); + + TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); + ipic_calc_masks(); + + ppc_intr_enable(s); /* Unmask the interrupt. */ mask = ipic_read(sc, IPIC_SIMSR_H); @@ -273,31 +281,19 @@ ext_intr(void) struct cpu_info *ci = curcpu(); struct ipic_softc *sc = ipic_sc; struct intrhand *ih; - uint32_t simsr_h, simsr_l, semsr; - int pcpl, ocpl; + struct intrq *iq; + int pcpl; int ivec; pcpl = ci->ci_cpl; ivec = ipic_read(sc, IPIC_SIVCR) & 0x7f; - simsr_h = ipic_read(sc, IPIC_SIMSR_H); - simsr_l = ipic_read(sc, IPIC_SIMSR_L); - semsr = ipic_read(sc, IPIC_SEMSR); - ipic_write(sc, IPIC_SIMSR_H, simsr_h & ~ipic_simsr_h(ivec)); - ipic_write(sc, IPIC_SIMSR_L, simsr_l & ~ipic_simsr_l(ivec)); - ipic_write(sc, IPIC_SEMSR, semsr & ~ipic_semsr(ivec)); - - ih = ipic_intrhand[ivec]; - while (ih) { - if (ci->ci_cpl & (1 << ih->ih_level)) { - ci->ci_ipending |= (1 << ih->ih_level); - return; - } + iq = &ipic_handler[ivec]; + TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { + if (ih->ih_level < pcpl) + continue; - ipic_write(sc, IPIC_SIMSR_H, sc->sc_simsr_h[ih->ih_level]); - ipic_write(sc, IPIC_SIMSR_L, sc->sc_simsr_l[ih->ih_level]); - ipic_write(sc, IPIC_SEMSR, sc->sc_semsr[ih->ih_level]); - ocpl = splraise(imask[ih->ih_level]); + ipic_splraise(ih->ih_level); ppc_intr_enable(1); KERNEL_LOCK(); @@ -306,40 +302,111 @@ ext_intr(void) KERNEL_UNLOCK(); ppc_intr_disable(); - ci->ci_cpl = ocpl; - ih = ih->ih_next; } - ipic_write(sc, IPIC_SIMSR_H, simsr_h); - ipic_write(sc, IPIC_SIMSR_L, simsr_l); - ipic_write(sc, IPIC_SEMSR, semsr); splx(pcpl); } -static __inline int -cntlzw(int x) +int +ipic_splraise(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int ocpl = ci->ci_cpl; + + if (ocpl > newcpl) + newcpl = ocpl; + + ipic_setipl(newcpl); + + return (ocpl); +} + +int +ipic_spllower(int newcpl) { - int a; + struct cpu_info *ci = curcpu(); + int ocpl = ci->ci_cpl; + + ipic_splx(newcpl); + + return (ocpl); +} - __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x)); +void +ipic_splx(int newcpl) +{ + struct cpu_info *ci = curcpu(); - return a; + ipic_setipl(newcpl); + if (ci->ci_ipending & ppc_smask[newcpl]) + ipic_do_pending(newcpl); } void -ipic_do_pending_int(void) +ipic_setipl(int ipl) { struct cpu_info *ci = curcpu(); struct ipic_softc *sc = ipic_sc; uint32_t mask; - int level; + int s; - ci->ci_ipending &= SINT_MASK; - level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCK|SINT_MASK))); - mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[level]; + s = ppc_intr_disable(); + ci->ci_cpl = ipl; + mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[ipl]; ipic_write(sc, IPIC_SIMSR_H, mask); - mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[level]; + mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[ipl]; ipic_write(sc, IPIC_SIMSR_L, mask); - mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[level]; + mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[ipl]; ipic_write(sc, IPIC_SEMSR, mask); + ppc_intr_enable(s); +} + +void +ipic_do_pending(int pcpl) +{ + struct cpu_info *ci = curcpu(); + int s; + + s = ppc_intr_disable(); + if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { + ppc_intr_enable(s); + return; + } + + atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); + + do { + if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && + (pcpl < IPL_SOFTNET)) { + extern int netisr; + int pisr; + + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); + ci->ci_cpl = IPL_SOFTNET; + ppc_intr_enable(s); + KERNEL_LOCK(); + while ((pisr = netisr) != 0) { + atomic_clearbits_int(&netisr, pisr); + softnet(pisr); + } + KERNEL_UNLOCK(); + ppc_intr_disable(); + continue; + } + if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && + (pcpl < IPL_SOFTCLOCK)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); + ci->ci_cpl = IPL_SOFTCLOCK; + ppc_intr_enable(s); + KERNEL_LOCK(); + softclock(); + KERNEL_UNLOCK(); + ppc_intr_disable(); + continue; + } + } while (ci->ci_ipending & ppc_smask[pcpl]); + ipic_setipl(pcpl); /* Don't use splx... we are here already! */ + + atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); + ppc_intr_enable(s); } diff --git a/sys/arch/socppc/socppc/machdep.c b/sys/arch/socppc/socppc/machdep.c index bf8298c7330..1743306806d 100644 --- a/sys/arch/socppc/socppc/machdep.c +++ b/sys/arch/socppc/socppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.9 2009/02/17 20:35:47 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.10 2009/06/02 21:38:10 drahn Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -1088,67 +1088,9 @@ boot(int howto) while(1) /* forever */; } -extern void ipic_do_pending_int(void); - void do_pending_int(void) { - struct cpu_info *ci = curcpu(); - int pcpl, s; - - if (ci->ci_iactive) - return; - - ci->ci_iactive = 1; - s = ppc_intr_disable(); - pcpl = ci->ci_cpl; - - ipic_do_pending_int(); - - do { - if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) { - ci->ci_ipending &= ~SINT_CLOCK; - ci->ci_cpl = SINT_CLOCK|SINT_NET|SINT_TTY; - ppc_intr_enable(1); - KERNEL_LOCK(); - softclock(); - KERNEL_UNLOCK(); - ppc_intr_disable(); - continue; - } - if((ci->ci_ipending & SINT_NET) & ~pcpl) { - extern int netisr; - int pisr; - - ci->ci_ipending &= ~SINT_NET; - ci->ci_cpl = SINT_NET|SINT_TTY; - while ((pisr = netisr) != 0) { - atomic_clearbits_int(&netisr, pisr); - ppc_intr_enable(1); - KERNEL_LOCK(); - softnet(pisr); - KERNEL_UNLOCK(); - ppc_intr_disable(); - } - continue; - } -#if 0 - if((ci->ci_ipending & SINT_TTY) & ~pcpl) { - ci->ci_ipending &= ~SINT_TTY; - ci->ci_cpl = SINT_TTY; - ppc_intr_enable(1); - KERNEL_LOCK(); - softtty(); - KERNEL_UNLOCK(); - ppc_intr_disable(); - continue; - } -#endif - } while ((ci->ci_ipending & SINT_MASK) & ~pcpl); - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ - - ci->ci_iactive = 0; - ppc_intr_enable(s); } /* |