diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2011-08-29 20:21:45 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2011-08-29 20:21:45 +0000 |
commit | 1a9161e19576a182bd9ae248258881711c63d5ed (patch) | |
tree | 74d3ef47c413b75f1037e9ffb1400a5eca09165a /sys/arch/socppc | |
parent | 45eb37d7c1c3cec88a07d2930a46f4ef74354a3e (diff) |
Return of the long missing powerpc interrupt rewrite. Was working for
several weeks before release on macppc, socppc bugs just fixed.
Diffstat (limited to 'sys/arch/socppc')
-rw-r--r-- | sys/arch/socppc/dev/ipic.c | 180 | ||||
-rw-r--r-- | sys/arch/socppc/socppc/clock.c | 4 | ||||
-rw-r--r-- | sys/arch/socppc/socppc/machdep.c | 62 |
3 files changed, 130 insertions, 116 deletions
diff --git a/sys/arch/socppc/dev/ipic.c b/sys/arch/socppc/dev/ipic.c index 6e250257176..c7a07965969 100644 --- a/sys/arch/socppc/dev/ipic.c +++ b/sys/arch/socppc/dev/ipic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipic.c,v 1.14 2011/01/08 18:10:22 deraadt Exp $ */ +/* $OpenBSD: ipic.c,v 1.15 2011/08/29 20:21:44 drahn Exp $ */ /* * Copyright (c) 2008 Mark Kettenis @@ -65,8 +65,9 @@ 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_preinit_done; /* defaults to 0 - not initialized */ int ipic_match(struct device *, void *, void *); void ipic_attach(struct device *, struct device *, void *); @@ -79,15 +80,34 @@ struct cfdriver ipic_cd = { NULL, "ipic", DV_DULL }; +void ipic_preinit(void); uint32_t ipic_read(struct ipic_softc *, bus_addr_t); 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 intr_calculatemasks(void); void ext_intr(void); -void ipic_do_pending_int(void); + +ppc_splraise_t ipic_splraise; +ppc_spllower_t ipic_spllower; +ppc_splx_t ipic_splx; + +void ipic_setipl(int); + +void +ipic_preinit(void) +{ + int i; + struct intrq *iq; + + for (i = 0; i < IPIC_NVEC; i++) { + iq = &ipic_handler[i]; + TAILQ_INIT(&iq->iq_list); + } + ipic_preinit_done = 1; +} int ipic_match(struct device *parent, void *cfdata, void *aux) @@ -108,6 +128,7 @@ ipic_attach(struct device *parent, struct device *self, void *aux) struct ipic_softc *sc = (void *)self; struct obio_attach_args *oa = aux; int ivec; + struct intrq *iq; sc->sc_iot = oa->oa_iot; if (bus_space_map(sc->sc_iot, oa->oa_offset, 128, 0, &sc->sc_ioh)) { @@ -117,18 +138,23 @@ ipic_attach(struct device *parent, struct device *self, void *aux) ipic_sc = sc; + /* if ipic_preinit has not happened, do it here */ + if (ipic_preinit_done == 0) + ipic_preinit(); + /* * Deal with pre-established interrupts. */ for (ivec = 0; ivec < IPIC_NVEC; ivec++) { - if (ipic_intrhand[ivec]) { - int level = ipic_intrhand[ivec]->ih_level; + iq = &ipic_handler[ivec]; + if (!TAILQ_EMPTY(&iq->iq_list)) { + int level = TAILQ_FIRST(&iq->iq_list)->ih_level; uint32_t mask; 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(); + ipic_calc_masks(); /* Unmask the interrupt. */ mask = ipic_read(sc, IPIC_SIMSR_H); @@ -143,6 +169,11 @@ ipic_attach(struct device *parent, struct device *self, void *aux) } } + ppc_smask_init(); + ppc_intr_func.raise = ipic_splraise; + ppc_intr_func.lower = ipic_spllower; + ppc_intr_func.x = ipic_splx; + printf("\n"); } @@ -217,31 +248,9 @@ ipic_semsr(int ivec) } void -intr_calculatemasks(void) +ipic_calc_masks(void) { struct ipic_softc *sc = ipic_sc; - int level; - - for (level = IPL_NONE; level < IPL_NUM; level++) - cpu_imask[level] = SINT_ALLMASK | (1 << level); - - /* - * There are tty, network and disk drivers that use free() at interrupt - * time, so vm > (tty | net | bio). - * - * Enforce a hierarchy that gives slow devices a better chance at not - * dropping data. - */ - cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO]; - cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET]; - cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY]; - cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK; - - /* - * These are pseudo-levels. - */ - cpu_imask[IPL_NONE] = 0x00000000; - cpu_imask[IPL_HIGH] = 0xffffffff; sc->sc_simsr_h[IPL_NET] |= sc->sc_simsr_h[IPL_BIO]; sc->sc_simsr_h[IPL_TTY] |= sc->sc_simsr_h[IPL_NET]; @@ -267,36 +276,47 @@ 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; + + if (ipic_preinit_done == 0) + ipic_preinit(); ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) panic("%s: malloc failed", __func__); + iq = &ipic_handler[ivec]; if (ivec < 0 || ivec >= IPIC_NVEC) panic("%s: invalid vector %d", __func__, ivec); - for (p = &ipic_intrhand[ivec]; (q = *p) != NULL; p = &q->ih_next) - ; - if (sc) { sc->sc_simsr_h[level] |= ipic_simsr_h(ivec); sc->sc_simsr_l[level] |= ipic_simsr_l(ivec); sc->sc_semsr[level] |= ipic_semsr(ivec); - intr_calculatemasks(); } ih->ih_fun = ih_fun; ih->ih_arg = ih_arg; - ih->ih_next = NULL; ih->ih_level = level; ih->ih_irq = ivec; - evcount_attach(&ih->ih_count, name, NULL); - *p = ih; + evcount_attach(&ih->ih_count, name, &ih->ih_irq); + + /* + * Append handler to end of list + */ + s = ppc_intr_disable(); + + TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); + ipic_calc_masks(); + + ppc_intr_enable(s); + + /* Unmask the interrupt. */ if (sc) { - /* Unmask the interrupt. */ mask = ipic_read(sc, IPIC_SIMSR_H); mask |= ipic_simsr_h(ivec); ipic_write(sc, IPIC_SIMSR_H, mask); @@ -317,31 +337,22 @@ 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) { + panic("irq handler called at wrong level %d %d", + ih->ih_level, pcpl); + continue; } - ipic_write(sc, IPIC_SIMSR_H, sc->sc_simsr_h[ih->ih_level]); - ipic_write(sc, IPIC_SIMSR_L, sc->sc_simsr_l[ih->ih_level]); - ipic_write(sc, IPIC_SEMSR, sc->sc_semsr[ih->ih_level]); - ocpl = splraise(cpu_imask[ih->ih_level]); + ipic_splraise(ih->ih_level); ppc_intr_enable(1); KERNEL_LOCK(); @@ -350,40 +361,61 @@ ext_intr(void) KERNEL_UNLOCK(); ppc_intr_disable(); - ci->ci_cpl = ocpl; - ih = ih->ih_next; } - ipic_write(sc, IPIC_SIMSR_H, simsr_h); - ipic_write(sc, IPIC_SIMSR_L, simsr_l); - ipic_write(sc, IPIC_SEMSR, semsr); splx(pcpl); } -static __inline int -cntlzw(int x) +int +ipic_splraise(int newcpl) { - int a; + struct cpu_info *ci = curcpu(); + int ocpl = ci->ci_cpl; + + if (ocpl > newcpl) + newcpl = ocpl; + + ipic_setipl(newcpl); + + return (ocpl); +} - __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x)); +int +ipic_spllower(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int ocpl = ci->ci_cpl; + + ipic_splx(newcpl); + + return (ocpl); +} + +void +ipic_splx(int newcpl) +{ + struct cpu_info *ci = curcpu(); - return a; + ipic_setipl(newcpl); + if (ci->ci_ipending & ppc_smask[newcpl]) + do_pending_int(); } 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_ALLMASK; - level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCKMASK|SINT_ALLMASK))); - mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[level]; + s = ppc_intr_disable(); + ci->ci_cpl = ipl; + mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[ipl]; ipic_write(sc, IPIC_SIMSR_H, mask); - mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[level]; + mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[ipl]; ipic_write(sc, IPIC_SIMSR_L, mask); - mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[level]; + mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[ipl]; ipic_write(sc, IPIC_SEMSR, mask); + ppc_intr_enable(s); } diff --git a/sys/arch/socppc/socppc/clock.c b/sys/arch/socppc/socppc/clock.c index d063e72bfd1..159aed44769 100644 --- a/sys/arch/socppc/socppc/clock.c +++ b/sys/arch/socppc/socppc/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.8 2010/09/20 06:33:48 matthew Exp $ */ +/* $OpenBSD: clock.c,v 1.9 2011/08/29 20:21:44 drahn Exp $ */ /* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */ /* @@ -202,7 +202,7 @@ decr_intr(struct clockframe *frame) */ ppc_mtdec(nextevent - tb); - if (curcpu()->ci_cpl & SPL_CLOCKMASK) { + if (ci->ci_cpl >= IPL_CLOCK) { ci->ci_statspending += nstats; } else { KERNEL_LOCK(); diff --git a/sys/arch/socppc/socppc/machdep.c b/sys/arch/socppc/socppc/machdep.c index 665343b48af..27348935a7a 100644 --- a/sys/arch/socppc/socppc/machdep.c +++ b/sys/arch/socppc/socppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.32 2011/07/05 04:48:02 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.33 2011/08/29 20:21:44 drahn Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -1095,59 +1095,41 @@ boot(int howto) while(1) /* forever */; } -extern void ipic_do_pending_int(void); - void do_pending_int(void) { struct cpu_info *ci = curcpu(); - int pcpl, s; - - if (ci->ci_iactive) - return; - - ci->ci_iactive = 1; + int pcpl = ci->ci_cpl; /* XXX */ + int s; s = ppc_intr_disable(); - pcpl = ci->ci_cpl; - - ipic_do_pending_int(); + if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { + ppc_intr_enable(s); + return; + } + atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); do { - if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) { - ci->ci_ipending &= ~SINT_CLOCK; - ci->ci_cpl = SINT_CLOCK|SINT_NET|SINT_TTY; - ppc_intr_enable(1); - KERNEL_LOCK(); + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && + (pcpl < IPL_SOFTCLOCK)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); softintr_dispatch(SI_SOFTCLOCK); - KERNEL_UNLOCK(); - ppc_intr_disable(); - continue; - } - if((ci->ci_ipending & SINT_NET) & ~pcpl) { - ci->ci_ipending &= ~SINT_NET; - ci->ci_cpl = SINT_NET|SINT_TTY; - ppc_intr_enable(1); - KERNEL_LOCK(); + } + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && + (pcpl < IPL_SOFTNET)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); softintr_dispatch(SI_SOFTNET); - KERNEL_UNLOCK(); - ppc_intr_disable(); - continue; } - if((ci->ci_ipending & SINT_TTY) & ~pcpl) { - ci->ci_ipending &= ~SINT_TTY; - ci->ci_cpl = SINT_TTY; - ppc_intr_enable(1); - KERNEL_LOCK(); + if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && + (pcpl < IPL_SOFTTTY)) { + ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); softintr_dispatch(SI_SOFTTTY); - KERNEL_UNLOCK(); - ppc_intr_disable(); - continue; } - } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl); - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ - ci->ci_iactive = 0; + } while (ci->ci_ipending & ppc_smask[pcpl]); + splx(pcpl); ppc_intr_enable(s); + + atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); } /* |