diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-11-21 17:35:53 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-11-21 17:35:53 +0000 |
commit | 76896b893429a73b9185282e75299828ce0ce9df (patch) | |
tree | e566d29fce5ec807bfa5e4e206315fcc8cda91bb | |
parent | a2be99af5ddd1479186a12e21cbba9915c1c8929 (diff) |
back out the new interrupt subsystem because some little bug still lurks in there
-rw-r--r-- | sys/arch/macppc/dev/macintr.c | 550 | ||||
-rw-r--r-- | sys/arch/macppc/dev/openpic.c | 721 | ||||
-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 | 118 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/intr.c | 104 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/mutex.S | 46 |
10 files changed, 802 insertions, 756 deletions
diff --git a/sys/arch/macppc/dev/macintr.c b/sys/arch/macppc/dev/macintr.c index e327b99c2c1..73235f28e77 100644 --- a/sys/arch/macppc/dev/macintr.c +++ b/sys/arch/macppc/dev/macintr.c @@ -1,7 +1,6 @@ -/* $OpenBSD: macintr.c,v 1.34 2008/09/18 03:56:25 drahn Exp $ */ +/* $OpenBSD: macintr.c,v 1.35 2008/11/21 17:35:52 deraadt 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. @@ -59,18 +58,26 @@ #define ICU_LEN 64 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) -int macintr_ienable_l[IPL_NUM], macintr_ienable_h[IPL_NUM]; -int macintr_pri_share[IPL_NUM]; - -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); +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); extern u_int32_t *heathrow_FCR; +#define HWIRQ_MAX 27 +#define HWIRQ_MASK 0x0fffffff + #define INT_STATE_REG0 (interrupt_reg + 0x20) #define INT_ENABLE_REG0 (interrupt_reg + 0x24) #define INT_CLEAR_REG0 (interrupt_reg + 0x28) @@ -88,8 +95,6 @@ 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), @@ -135,84 +140,31 @@ 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; - -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_collect_preconf_intr(void); 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 = macintr_do_pending_int; + pending_int_f = mac_intr_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"); } @@ -257,19 +209,11 @@ macintr_prog_button (void *arg) return 1; } -void -macintr_setipl(int ipl) +static int +fakeintr(void *arg) { - 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]]); - out32rb(INT_ENABLE_REG0, macintr_ienable_l[macintr_pri_share[ipl]]); - ppc_intr_enable(s); + return 0; } /* @@ -279,13 +223,19 @@ void * macintr_establish(void * lcv, int irq, int type, int level, int (*ih_fun)(void *), void *ih_arg, char *name) { - struct cpu_info *ci = curcpu(); - struct intrq *iq; - struct intrhand *ih; - int s; + struct intrhand **p, *q, *ih; + static struct intrhand fakehand; + + fakehand.ih_next = NULL; + fakehand.ih_fun = fakeintr; #if 0 -printf("macintr_establish, hI %d L %d %s", irq, level, ppc_intr_typename(type)); +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); #endif /* no point in sleeping unless someone can free memory. */ @@ -296,40 +246,51 @@ printf("macintr_establish, hI %d L %d %s", irq, level, ppc_intr_typename(type)); if (!LEGAL_IRQ(irq) || type == IST_NONE) panic("intr_establish: bogus irq or type"); - iq = &macintr_handler[irq]; - switch (iq->iq_ist) { + switch (m_intrtype[irq]) { case IST_NONE: - iq->iq_ist = type; + m_intrtype[irq] = type; break; case IST_EDGE: case IST_LEVEL: - if (type == iq->iq_ist) + if (type == m_intrtype[irq]) break; case IST_PULSE: if (type != IST_NONE) panic("intr_establish: can't share %s with %s", - ppc_intr_typename(iq->iq_ist), - ppc_intr_typename(type)); + intr_typename(m_intrtype[irq]), + intr_typename(type)); break; } - 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); + /* + * 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) + ; /* - * Append handler to end of list + * 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. */ - s = ppc_intr_disable(); + fakehand.ih_level = level; + *p = &fakehand; - TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); - macintr_calc_mask(); + intr_calculatemasks(); - macintr_setipl(ci->ci_cpl); - ppc_intr_enable(s); + /* + * 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_intr); + *p = ih; return (ih); } @@ -340,93 +301,195 @@ printf("macintr_establish, hI %d L %d %s", irq, level, ppc_intr_typename(type)); void macintr_disestablish(void *lcp, void *arg) { - struct cpu_info *ci = curcpu(); struct intrhand *ih = arg; int irq = ih->ih_irq; - int s; - struct intrq *iq; + struct intrhand **p, *q; if (!LEGAL_IRQ(irq)) panic("intr_disestablish: bogus irq"); /* * Remove the handler from the chain. + * This is O(n^2), too. */ - - iq = &macintr_handler[irq]; - s = ppc_intr_disable(); - - TAILQ_REMOVE(&iq->iq_list, ih, ih_list); - macintr_calc_mask(); - - macintr_setipl(ci->ci_cpl); - ppc_intr_enable(s); + 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); - if (TAILQ_EMPTY(&iq->iq_list)) - iq->iq_ist = IST_NONE; + intr_calculatemasks(); + + if (m_intrhand[irq] == NULL) + m_intrtype[irq] = IST_NONE; } + +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 + } +} /* * 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. */ -void -macintr_calc_mask() +static void +intr_calculatemasks() { - int irq; - struct intrhand *ih; - int i; + int irq, level; + struct intrhand *q; - for (i = IPL_NONE; i < IPL_NUM; i++) { - macintr_pri_share[i] = i; + /* 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; + } + + /* 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; } + /* + * 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++) { - 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; + 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; } + imen_m = ~irqs; + enable_irq(~imen_m); + } +} +static void +enable_irq(int x) +{ + int state0, state1, v; + int irq; - iq->iq_ipl = maxipl; + x &= HWIRQ_MASK; /* XXX Higher bits are software interrupts. */ - if (maxipl == IPL_NONE) { - minipl = IPL_NONE; /* Interrupt not enabled */ - } else { - for (i = minipl; i <= maxipl; i++) - macintr_pri_share[i] = i; - } + 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); - /* 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)); + 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 (m_virq_inited == 0) { + m_virq_max = 0; + for (i = 0; i < ICU_LEN; i++) { + m_virq[i] = 0; } + 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 - for (i = 0; i < IPL_NUM; i++) - printf("imask[%d] %x %x\n", i, macintr_ienable_l[i], - macintr_ienable_h[i]); +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; } /* @@ -436,136 +499,143 @@ 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 */ - irq = macintr_read_irq(); - while (irq != 255) { - iq = &macintr_handler[irq]; - macintr_setipl(iq->iq_ipl); + int_state = read_irq(); + if (int_state == 0) + goto out; + +start: + irq = 31 - cntlzw(int_state); + + o_imen = imen_m; + r_imen = 1 << irq; - TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { - ppc_intr_enable(1); + 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) { if ((*ih->ih_fun)(ih->ih_arg)) ih->ih_count.ec_count++; - (void)ppc_intr_disable(); + ih = ih->ih_next; } - macintr_eoi(irq); - macintr_setipl(pcpl); uvmexp.intrs++; - - irq = macintr_read_irq(); } + int_state &= ~r_imen; + if (int_state) + goto start; - ppc_intr_enable(1); +out: splx(pcpl); /* Process pendings. */ } void -macintr_do_pending_int() +mac_intr_do_pending_int() { struct cpu_info *ci = curcpu(); - int pcpl = ci->ci_cpl; /* XXX */ - int s, s2; - s = ppc_intr_disable(); - if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { - ppc_intr_enable(s); + struct intrhand *ih; + int irq; + int pcpl; + int hwpend; + int s; + + if (ci->ci_iactive) return; + + ci->ci_iactive = 1; + pcpl = splhigh(); /* Turn off all */ + 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; + } } - atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); + + /*out32rb(INT_ENABLE_REG, ~imen_m);*/ do { - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && (pcpl < IPL_SOFTTTY)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); - s2 = ci->ci_cpl; - ci->ci_cpl = IPL_SOFTTTY; - ppc_intr_enable(1); - KERNEL_LOCK(); - softtty(); - KERNEL_UNLOCK(); - ppc_intr_disable(); - ci->ci_cpl = pcpl; - continue; + if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) { + ci->ci_ipending &= ~SINT_CLOCK; + softclock(); } - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && (pcpl < IPL_SOFTNET)) { + if((ci->ci_ipending & SINT_NET) & ~pcpl) { extern int netisr; int pisr; - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); + ci->ci_ipending &= ~SINT_NET; 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 & 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; + if((ci->ci_ipending & SINT_TTY) & ~pcpl) { + ci->ci_ipending &= ~SINT_TTY; + softtty(); } - } while (ci->ci_ipending & ppc_smask[pcpl]); - macintr_setipl(pcpl); - atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); + } 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; } -void -macintr_eoi(int irq) +static int +read_irq() { - u_int32_t state0, state1; + int rv = 0; + int state0, state1, p; + int state0save, state1save; - if (irq < 32) { - state0 = 1 << irq; + state0 = in32rb(INT_STATE_REG0); + if (state0) out32rb(INT_CLEAR_REG0, state0); - } else { - if (heathrow_FCR) { /* has heathrow? */ - state1 = 1 << (irq - 32); - out32rb(INT_CLEAR_REG1, state1); - } + state0save = state0; + while (state0) { + p = 31 - cntlzw(state0); + rv |= 1 << m_virq[p]; + state0 &= ~(1 << p); } -} - -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; - 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 (state1) + out32rb(INT_CLEAR_REG1, state1); + state1save = state1; + while (state1) { + p = 31 - cntlzw(state1); + rv |= 1 << m_virq[p + 32]; + state1 &= ~(1 << p); } - return 255; +#if 0 +printf("mac_intr int_stat 0:%x 1:%x\n", state0save, state1save); +#endif + + /* 1 << 0 is invalid. */ + return rv & ~1; } diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c index 98d092496f5..bedd55017fd 100644 --- a/sys/arch/macppc/dev/openpic.c +++ b/sys/arch/macppc/dev/openpic.c @@ -1,7 +1,6 @@ -/* $OpenBSD: openpic.c,v 1.51 2008/11/04 14:28:24 drahn Exp $ */ +/* $OpenBSD: openpic.c,v 1.52 2008/11/21 17:35:52 deraadt 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. @@ -57,19 +56,23 @@ #include <dev/ofw/openfirm.h> #define ICU_LEN 128 -int openpic_numirq = ICU_LEN; #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) -int openpic_pri_share[IPL_NUM]; - -struct intrq openpic_handler[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; +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); -ppc_splraise_t openpic_splraise; -ppc_spllower_t openpic_spllower; -ppc_splx_t openpic_splx; +#define HWIRQ_MAX 27 +#define HWIRQ_MASK 0x0fffffff /* IRQ vector used for inter-processor interrupts. */ #define IPI_VECTOR_NOP 64 @@ -80,30 +83,17 @@ 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; -void openpic_enable_irq(int, int); -void openpic_disable_irq(int); -void openpic_init(void); -void openpic_set_priority(int); +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); - -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); +static __inline int openpic_read_irq(int); +static __inline void openpic_eoi(int); struct openpic_softc { struct device sc_dev; @@ -111,9 +101,9 @@ struct openpic_softc { int openpic_match(struct device *parent, void *cf, void *aux); void openpic_attach(struct device *, struct device *, void *); -void openpic_do_pending_int(int pcpl); +void openpic_do_pending_int(void); void openpic_collect_preconf_intr(void); -void openpic_ext_intr(void); +void ext_intr_openpic(void); struct cfattach openpic_ca = { sizeof(struct openpic_softc), @@ -125,42 +115,6 @@ struct cfdriver openpic_cd = { NULL, "openpic", DV_DULL }; -u_int -openpic_read(int reg) -{ - char *addr = (void *)(openpic_base + reg); - - asm volatile("eieio"); - if (openpic_big_endian) - return in32(addr); - else - return in32rb(addr); -} - -void -openpic_write(int reg, u_int val) -{ - char *addr = (void *)(openpic_base + reg); - - if (openpic_big_endian) - out32(addr, val); - else - out32rb(addr, val); - asm volatile("eieio"); -} - -static inline int -openpic_read_irq(int cpu) -{ - return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK; -} - -static inline void -openpic_eoi(int cpu) -{ - openpic_write(OPENPIC_EOI(cpu), 0); -} - int openpic_match(struct device *parent, void *cf, void *aux) { @@ -188,10 +142,22 @@ 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; @@ -202,16 +168,12 @@ openpic_attach(struct device *parent, struct device *self, void *aux) openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr + ca->ca_reg[0], 0x40000); - /* 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" ); + printf(": version 0x%x %s endian", openpic_read(OPENPIC_VENDOR_ID), + openpic_big_endian ? "big" : "little" ); 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; @@ -219,73 +181,22 @@ 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); - ppc_smask_init(); - +#if 1 openpic_collect_preconf_intr(); - - evcount_attach(&openpic_spurious, "spurious", - (void *)&openpic_spurious_irq, &evcount_intr); +#endif #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() { @@ -304,6 +215,13 @@ openpic_collect_preconf_intr() } } +static int +fakeintr(void *arg) +{ + + return 0; +} + /* * Register an interrupt handler. */ @@ -311,52 +229,74 @@ void * openpic_intr_establish(void *lcv, int irq, int type, int level, int (*ih_fun)(void *), void *ih_arg, char *name) { - struct intrhand *ih; - struct intrq *iq; - int s; + 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 /* 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 (iq->iq_ist) { + switch (o_intrtype[irq]) { case IST_NONE: - iq->iq_ist = type; + o_intrtype[irq] = type; break; case IST_EDGE: case IST_LEVEL: - if (type == iq->iq_ist) + if (type == o_intrtype[irq]) break; case IST_PULSE: if (type != IST_NONE) panic("intr_establish: can't share %s with %s", - ppc_intr_typename(iq->iq_ist), - ppc_intr_typename(type)); + intr_typename(o_intrtype[irq]), + intr_typename(type)); break; } - 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); + /* + * 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) + ; /* - * Append handler to end of list + * 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. */ - s = ppc_intr_disable(); + fakehand.ih_level = level; + *p = &fakehand; - TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); openpic_calc_mask(); - ppc_intr_enable(s); + /* + * 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; return (ih); } @@ -369,27 +309,51 @@ openpic_intr_disestablish(void *lcp, void *arg) { struct intrhand *ih = arg; int irq = ih->ih_irq; - struct intrq *iq = &openpic_handler[irq]; - int s; + struct intrhand **p, *q; if (!LEGAL_IRQ(irq)) panic("intr_disestablish: bogus irq"); /* * Remove the handler from the chain. + * This is O(n^2), too. */ - s = ppc_intr_disable(); + 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); - TAILQ_REMOVE(&iq->iq_list, ih, ih_list); openpic_calc_mask(); - ppc_intr_enable(s); + if (o_intrhand[irq] == NULL) + o_intrtype[irq] = IST_NONE; +} - evcount_detach(&ih->ih_count); - free((void *)ih, M_DEVBUF); - if (TAILQ_EMPTY(&iq->iq_list)) - iq->iq_ist = IST_NONE; +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 + } } /* @@ -402,131 +366,268 @@ openpic_intr_disestablish(void *lcp, void *arg) void openpic_calc_mask() { - struct cpu_info *ci = curcpu(); int irq; struct intrhand *ih; int i; /* disable all openpic interrupts */ - openpic_set_priority(15); + openpic_set_priority(0, 15); - for (i = IPL_NONE; i < IPL_NUM; i++) { - openpic_pri_share[i] = i; - } + 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 (irq = 0; irq < openpic_numirq; irq++) { - int maxipl = IPL_NONE; - int minipl = IPL_HIGH; - struct intrq *iq = &openpic_handler[irq]; + o_intrmaxlvl[irq] = max; - 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; + /* 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) ); } - if (maxipl == IPL_NONE) { - minipl = IPL_NONE; /* Interrupt not enabled */ + if (max == IPL_NONE) + min = IPL_NONE; /* Interrupt not enabled */ - openpic_disable_irq(irq); - } else { - for (i = minipl; i <= maxipl; i++) { - openpic_pri_share[i] = maxipl; - } - openpic_enable_irq(irq, maxipl); + 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]); } - - iq->iq_ipl = maxipl; } /* restore interrupts */ - openpic_set_priority(ci->ci_cpl); + openpic_set_priority(0, 0); + + for (i = IPL_NONE; i <= IPL_HIGH; i++) { + if (i > IPL_NONE) + imask[i] |= SINT_MASK; + } + 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; +} + +void openpic_do_pending_softint(int pcpl); + void -openpic_do_pending_int(int pcpl) +openpic_do_pending_int() { struct cpu_info *ci = curcpu(); + struct intrhand *ih; + int irq; + int pcpl; + int hwpend; + int pri, pripending; int s; - int loopcount = 0; - s = ppc_intr_disable(); - if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { - /* soft interrupts are being processed, just set ipl/return */ - openpic_setipl(pcpl); - ppc_intr_enable(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); + + ppc_intr_enable(s); +} + +void +openpic_do_pending_softint(int pcpl) +{ + struct cpu_info *ci = curcpu(); + + if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) + return; atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); do { - 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); + 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(); - softtty(); + softclock(); KERNEL_UNLOCK(); ppc_intr_disable(); continue; } - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && - (pcpl < IPL_SOFTNET)) { + if((ci->ci_ipending & SINT_NET) & ~pcpl) { extern int netisr; int pisr; - - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); - openpic_setipl(IPL_SOFTNET); - ppc_intr_enable(s); - KERNEL_LOCK(); + + 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(); } - 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); - openpic_setipl(IPL_SOFTCLOCK); - ppc_intr_enable(s); + if((ci->ci_ipending & SINT_TTY) & ~pcpl) { + ci->ci_ipending &= ~SINT_TTY; + ci->ci_cpl = SINT_TTY; + ppc_intr_enable(1); KERNEL_LOCK(); - softclock(); + softtty(); KERNEL_UNLOCK(); ppc_intr_disable(); continue; } - break; - } while (ci->ci_ipending & ppc_smask[pcpl]); - openpic_setipl(pcpl); /* Don't use splx... we are here already! */ + } while ((ci->ci_ipending & SINT_MASK) & ~pcpl); + ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); - ppc_intr_enable(s); +} + +u_int +openpic_read(int reg) +{ + char *addr = (void *)(openpic_base + reg); + + if (openpic_big_endian) + return in32(addr); + else + return in32rb(addr); +} + +void +openpic_write(int reg, u_int val) +{ + char *addr = (void *)(openpic_base + reg); + + if (openpic_big_endian) + out32(addr, val); + else + out32rb(addr, val); +} + +void +openpic_enable_irq_mask(int irq_mask) +{ + int irq; + for ( irq = 0; irq <= o_virq_max; irq++) { + if (irq_mask & (1 << irq)) + openpic_enable_irq(o_hwirq[irq]); + else + openpic_disable_irq(o_hwirq[irq]); + } } void -openpic_enable_irq(int irq, int pri) +openpic_set_enable_irq(int irq, int type) { u_int x; - struct intrq *iq = &openpic_handler[irq]; - x = irq; - if (iq->iq_ist == IST_LEVEL) + 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 |= OPENPIC_SENSE_LEVEL; else x |= OPENPIC_SENSE_EDGE; - x |= OPENPIC_POLARITY_POSITIVE; - x |= pri << OPENPIC_PRIORITY_SHIFT; openpic_write(OPENPIC_SRC_VECTOR(irq), x); } @@ -541,13 +642,31 @@ openpic_disable_irq(int irq) } void -openpic_set_priority(int pri) +openpic_set_priority(int cpu, int pri) { - struct cpu_info *ci = curcpu(); - openpic_write(OPENPIC_CPU_PRIORITY(ci->ci_cpuid), 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)); } #ifdef MULTIPROCESSOR + void openpic_send_ipi(struct cpu_info *ci, int id) { @@ -562,82 +681,80 @@ openpic_send_ipi(struct cpu_info *ci, int id) panic("invalid ipi send to cpu %d %d\n", ci->ci_cpuid, id); } + openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid); } #endif void -openpic_ext_intr() +ext_intr_openpic() { struct cpu_info *ci = curcpu(); - int irq; - int pcpl; + int irq, realirq; + int r_imen; + int pcpl, ocpl; struct intrhand *ih; - struct intrq *iq; - int irqloop = 0; - static int irqnest = 0; - int spurious; pcpl = ci->ci_cpl; - irq = openpic_read_irq(ci->ci_cpuid); - irqnest++; + realirq = openpic_read_irq(ci->ci_cpuid); - while (irq != 255) { - irqloop++; - if (irqloop > 20 || irqnest > 3) { - printf("irqloop %d irqnest %d\n", irqloop, irqnest); - } + while (realirq != 255) { #ifdef MULTIPROCESSOR - if (irq == IPI_VECTOR_NOP) { + if (realirq == IPI_VECTOR_NOP) { ipi_nop[ci->ci_cpuid].ec_count++; openpic_eoi(ci->ci_cpuid); - irq = openpic_read_irq(ci->ci_cpuid); + realirq = openpic_read_irq(ci->ci_cpuid); continue; } - if (irq == IPI_VECTOR_DDB) { + if (realirq == IPI_VECTOR_DDB) { ipi_ddb[ci->ci_cpuid].ec_count++; openpic_eoi(ci->ci_cpuid); openpic_ipi_ddb(); - irq = openpic_read_irq(ci->ci_cpuid); + realirq = 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))); - splraise(iq->iq_ipl); - openpic_eoi(ci->ci_cpuid); + irq = o_virq[realirq]; - 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(); + /* XXX check range */ - (void)ppc_intr_disable(); - } - if (spurious) { - openpic_spurious.ec_count++; -#ifdef OPENPIC_NOISY - printf("spurious intr %d\n", irq); -#endif - } + r_imen = 1 << irq; + + if ((pcpl & r_imen) != 0) { + /* Masked! Mark this as pending. */ + ci->ci_ipending |= r_imen; + openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]); + openpic_eoi(ci->ci_cpuid); + } else { + openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]); + openpic_eoi(ci->ci_cpuid); + ocpl = splraise(imask[o_intrmaxlvl[realirq]]); + + ih = o_intrhand[irq]; + while (ih) { + ppc_intr_enable(1); + + KERNEL_LOCK(); + if ((*ih->ih_fun)(ih->ih_arg)) + ih->ih_count.ec_count++; + KERNEL_UNLOCK(); - uvmexp.intrs++; - openpic_setipl(pcpl); + (void)ppc_intr_disable(); + ih = ih->ih_next; + } + + uvmexp.intrs++; + __asm__ volatile("":::"memory"); /* don't reorder.... */ + ci->ci_cpl = ocpl; + __asm__ volatile("":::"memory"); /* don't reorder.... */ + openpic_enable_irq_mask(~pcpl); + } - irq = openpic_read_irq(ci->ci_cpuid); + realirq = openpic_read_irq(ci->ci_cpuid); } - irqnest--; ppc_intr_enable(1); splx(pcpl); /* Process pendings. */ @@ -646,29 +763,22 @@ openpic_ext_intr() 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 < openpic_numirq; irq++) + for (irq = 0; irq < 255; irq++) openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK); - - for (i = 0; i < openpic_numirq; i++) { - iq = &openpic_handler[i]; - TAILQ_INIT(&iq->iq_list); - } + openpic_set_priority(0, 15); /* we don't need 8259 pass through mode */ x = openpic_read(OPENPIC_CONFIG); x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; openpic_write(OPENPIC_CONFIG, x); - /* initialize all vectors to something sane */ + /* send all interrupts to cpu 0 */ + for (irq = 0; irq < ICU_LEN; irq++) + openpic_write(OPENPIC_IDEST(irq), 1 << 0); for (irq = 0; irq < ICU_LEN; irq++) { x = irq; x |= OPENPIC_IMASK; @@ -678,17 +788,6 @@ 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 */ @@ -702,7 +801,6 @@ 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, @@ -713,21 +811,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); } -#if 0 - openpic_write(OPENPIC_SPURIOUS_VECTOR, 255); -#endif - - install_extint(openpic_ext_intr); + for (irq = 0; irq < ICU_LEN; irq++) + openpic_disable_irq(irq); - openpic_set_priority(0); + install_extint(ext_intr_openpic); } - /* * programmer_button function to fix args to Debugger. * deal with any enables/disables, if necessary. @@ -744,11 +842,10 @@ openpic_prog_button (void *arg) return 1; } + void -openpic_ipi_ddb() +openpic_ipi_ddb(void) { -#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 ee424cb7224..c881dc54add 100644 --- a/sys/arch/macppc/include/intr.h +++ b/sys/arch/macppc/include/intr.h @@ -1,9 +1,9 @@ -/* $OpenBSD: intr.h,v 1.5 2008/09/18 03:56:25 drahn Exp $ */ +/* $OpenBSD: intr.h,v 1.6 2008/11/21 17:35:52 deraadt Exp $ */ #include <powerpc/intr.h> #ifndef _LOCORE void softtty(void); -void openpic_set_priority(int); +void openpic_set_priority(int, int); #endif diff --git a/sys/arch/macppc/macppc/clock.c b/sys/arch/macppc/macppc/clock.c index 32da2f7330f..8a7bfb72d8d 100644 --- a/sys/arch/macppc/macppc/clock.c +++ b/sys/arch/macppc/macppc/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.24 2008/09/23 20:45:26 miod Exp $ */ +/* $OpenBSD: clock.c,v 1.25 2008/11/21 17:35:52 deraadt 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 >= IPL_CLOCK) { + if (curcpu()->ci_cpl & SPL_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 d443aa4f15a..9cccd9302f6 100644 --- a/sys/arch/macppc/macppc/cpu.c +++ b/sys/arch/macppc/macppc/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.59 2008/10/15 23:23:49 deraadt Exp $ */ +/* $OpenBSD: cpu.c,v 1.60 2008/11/21 17:35:52 deraadt Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -789,7 +789,7 @@ cpu_hatch(void) ppc_intr_enable(intrstate); /* Enable inter-processor interrupts. */ - openpic_set_priority(14); + openpic_set_priority(curcpu()->ci_cpuid, 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 edd3bd8a851..50438c0f76e 100644 --- a/sys/arch/macppc/macppc/genassym.cf +++ b/sys/arch/macppc/macppc/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.18 2008/09/18 03:56:25 drahn Exp $ +# $OpenBSD: genassym.cf,v 1.19 2008/11/21 17:35:52 deraadt Exp $ # # Copyright (c) 1982, 1990 The Regents of the University of California. # All rights reserved. @@ -86,6 +86,7 @@ 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 d7a7dae07c6..927b4952496 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.101 2008/09/18 03:56:25 drahn Exp $ */ +/* $OpenBSD: machdep.c,v 1.102 2008/11/21 17:35:52 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -877,6 +877,8 @@ 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 73a400c003c..c7bd5410c40 100644 --- a/sys/arch/powerpc/include/intr.h +++ b/sys/arch/powerpc/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.37 2008/09/19 01:42:05 drahn Exp $ */ +/* $OpenBSD: intr.h,v 1.38 2008/11/21 17:35:52 deraadt Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. @@ -36,18 +36,14 @@ #define _POWERPC_INTR_H_ #define IPL_NONE 0 -#define IPL_SOFT 1 -#define IPL_SOFTCLOCK 2 -#define IPL_SOFTNET 3 -#define IPL_SOFTTTY 4 -#define IPL_BIO 5 +#define IPL_BIO 1 #define IPL_AUDIO IPL_BIO /* XXX - was defined this val in audio_if.h */ -#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 IPL_NET 2 +#define IPL_TTY 3 +#define IPL_VM 4 +#define IPL_CLOCK 5 +#define IPL_HIGH 6 +#define IPL_NUM 7 #define IST_NONE 0 #define IST_PULSE 1 @@ -59,9 +55,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); @@ -74,69 +70,48 @@ 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; - -#if 0 -/* does it make sense to call directly ?? */ -#define splraise(x) ppc_intr.raise(x) -#define spllower(x) ppc_intr.lower(x) -#define splx(x) ppc_intr.x(x) -#endif - -extern int ppc_smask[IPL_NUM]; - -void ppc_smask_init(void); -char *ppc_intr_typename(int type); void do_pending_int(void); +extern int imask[IPL_NUM]; + /* SPL asserts */ #define splassert(wantipl) /* nothing */ #define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p) -#if 0 #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) -#endif - -#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) + +#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) /* * Interrupt control struct used to control the ICU setup. */ struct intrhand { - TAILQ_ENTRY(intrhand) ih_list; + struct intrhand *ih_next; int (*ih_fun)(void *); void *ih_arg; struct evcount ih_count; @@ -144,34 +119,11 @@ 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 */ - -#define SI_NQUEUES 4 - -#define SI_QUEUENAMES { \ - "generic", \ - "clock", \ - "net", \ - "serial", \ -} - #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 ed5f5dd84fe..722477c74cd 100644 --- a/sys/arch/powerpc/powerpc/intr.c +++ b/sys/arch/powerpc/powerpc/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.3 2008/09/18 03:56:25 drahn Exp $ */ +/* $OpenBSD: intr.c,v 1.4 2008/11/21 17:35:52 deraadt Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. @@ -35,121 +35,45 @@ #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); -} - -int -ppc_dflt_splraise(int newcpl) -{ struct cpu_info *ci = curcpu(); int oldcpl; + __asm__ volatile("":::"memory"); /* reorder protect */ oldcpl = ci->ci_cpl; - if (newcpl < oldcpl) - newcpl = oldcpl; - ci->ci_cpl = newcpl; + ci->ci_cpl = oldcpl | newcpl; + __asm__ volatile("":::"memory"); return (oldcpl); } -/* - * functions with 'default' behavior to use before the real - * interrupt controller attaches - */ int -ppc_dflt_spllower(int newcpl) +spllower(int newcpl) { struct cpu_info *ci = curcpu(); int oldcpl; + __asm__ volatile("":::"memory"); /* reorder protect */ oldcpl = ci->ci_cpl; - - splx(newcpl); + ci->ci_cpl = newcpl; + if (ci->ci_ipending & ~newcpl) + do_pending_int(); + __asm__ volatile("":::"memory"); return (oldcpl); } void -ppc_dflt_splx(int newcpl) +splx(int newcpl) { struct cpu_info *ci = curcpu(); + __asm__ volatile("":::"memory"); /* reorder protect */ ci->ci_cpl = newcpl; - - if (ci->ci_ipending & ppc_smask[newcpl]) + if (ci->ci_ipending & ~newcpl) do_pending_int(); -} - -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"); - } + __asm__ volatile("":::"memory"); } diff --git a/sys/arch/powerpc/powerpc/mutex.S b/sys/arch/powerpc/powerpc/mutex.S index 5ec8f84462e..7de7c22c3a2 100644 --- a/sys/arch/powerpc/powerpc/mutex.S +++ b/sys/arch/powerpc/powerpc/mutex.S @@ -1,4 +1,4 @@ -/* $OpenBSD: mutex.S,v 1.4 2008/09/18 03:56:25 drahn Exp $ */ +/* $OpenBSD: mutex.S,v 1.5 2008/11/21 17:35:52 deraadt Exp $ */ /* * Copyright (c) 2007 Dale Rahn @@ -22,11 +22,7 @@ #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 @@ -36,44 +32,44 @@ ENTRY(mtx_init) blr -/* - * mtx_enter(struct mutex *mtx[%r3]) - */ ENTRY(mtx_enter) - stwu %r1,-16(%r1) # reserve stack + stwu %r1,-32(%r1) # reserve stack mflr %r0 - stw %r0,20(%r1) # save return address + stw %r0,36(%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 %r3,12(%r1) + 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 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 -.L_mutex_busy: - stw %r3,12(%r1) # save mtx during lcsplx - la %r4,12(%r1) + stw %r3,28(%r1) # save mtx during lcsplx + la %r4,28(%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,12(%r1) + lwz %r3,28(%r1) b .L_retry .L_mutex_free: stwcx. %r4,%r5,%r3 # old owner was 0 cond store - bne- .L_mutex_busy # branch if reserve cancelled + bne- .L_mutex_locked # branch if reserve cancelled stw %r7,MTX_OLDCPL(%r3) # save old ipl - lwz %r0,20(%r1) # load return address + lwz %r0,36(%r1) # load return address mtlr %r0 - addi %r1,%r1,16 # restore stack + addi %r1,%r1,32 # restore stack blr #ifdef DIAGNOSTIC @@ -95,10 +91,14 @@ ENTRY(mtx_leave) beq- .L_mutex_notlocked #endif li %r4,0 - lwz % r5,MTX_OLDCPL(%r3) + 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 |