From: mpi Date: Sun, 4 Jan 2015 13:01:42 +0000 (+0000) Subject: Implement splassert(9) for powerpc. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=1c471f421f412895a8ccf0461fc716494b91bf1d;p=openbsd Implement splassert(9) for powerpc. This changes the logic to prevent a recursion when processing soft interrupts. Previously a per-CPU flag was set before re-enabling interrupts. Now the IPL level is raised to SOFTTTY which makes splsoftassert() happy, greatly inspired by mips64. As a side effect, the ppc_intr_{disable,enable}() dance is now done only once instead of twice per splx(9). While here, make use of dosoftint() instead of having 3 different functions for dispatching soft interrupts. Tested by deraadt@ on G4 smp and by myself G5 smp, G3, G4 and socppc. No objection from the usual (and over busy) suspects. --- diff --git a/sys/arch/macppc/dev/macintr.c b/sys/arch/macppc/dev/macintr.c index b0c69316db0..443e70a57f2 100644 --- a/sys/arch/macppc/dev/macintr.c +++ b/sys/arch/macppc/dev/macintr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macintr.c,v 1.49 2014/09/06 10:45:29 mpi Exp $ */ +/* $OpenBSD: macintr.c,v 1.50 2015/01/04 13:01:42 mpi Exp $ */ /*- * Copyright (c) 2008 Dale Rahn @@ -64,7 +64,6 @@ 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); extern u_int32_t *heathrow_FCR; @@ -83,7 +82,6 @@ struct macintr_softc { 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); @@ -125,7 +123,6 @@ macintr_match(struct device *parent, void *cf, void *aux) u_int8_t *interrupt_reg; typedef void (void_f) (void); -extern void_f *pending_int_f; int macintr_prog_button (void *arg); intr_establish_t macintr_establish; @@ -142,12 +139,16 @@ int macintr_splraise(int newcpl) { struct cpu_info *ci = curcpu(); - newcpl = macintr_pri_share[newcpl]; int ocpl = ci->ci_cpl; + int s; + + newcpl = macintr_pri_share[newcpl]; if (ocpl > newcpl) newcpl = ocpl; + s = ppc_intr_disable(); macintr_setipl(newcpl); + ppc_intr_enable(s); return ocpl; } @@ -167,10 +168,16 @@ void macintr_splx(int newcpl) { struct cpu_info *ci = curcpu(); - + int intr, s; + + intr = ppc_intr_disable(); macintr_setipl(newcpl); - if (ci->ci_ipending & ppc_smask[newcpl]) - macintr_do_pending_int(); + if ((newcpl < IPL_SOFTTTY && ci->ci_ipending & ppc_smask[newcpl])) { + s = splsofttty(); + dosoftint(newcpl); + macintr_setipl(s); /* no-overhead splx */ + } + ppc_intr_enable(intr); } void @@ -192,7 +199,6 @@ macintr_attach(struct device *parent, struct device *self, void *aux) ppc_smask_init(); install_extint(mac_ext_intr); - pending_int_f = macintr_do_pending_int; intr_establish_func = macintr_establish; intr_disestablish_func = macintr_disestablish; mac_intr_establish_func = macintr_establish; @@ -254,19 +260,18 @@ macintr_prog_button (void *arg) return 1; } +/* Must be called with interrupt disable. */ 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]]); out32rb(INT_ENABLE_REG0, macintr_ienable_l[macintr_pri_share[ipl]]); - ppc_intr_enable(s); } /* @@ -469,45 +474,7 @@ mac_ext_intr() irq = macintr_read_irq(); } - ppc_intr_enable(1); - splx(pcpl); /* Process pendings. */ -} - -void -macintr_do_pending_int() -{ - struct cpu_info *ci = curcpu(); - int pcpl = ci->ci_cpl; /* XXX */ - int s; - s = ppc_intr_disable(); - if (ci->ci_flags & CI_FLAGS_PROCESSING_SOFT) { - ppc_intr_enable(s); - return; - } - atomic_setbits_int(&ci->ci_flags, CI_FLAGS_PROCESSING_SOFT); - - do { - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && - (pcpl < IPL_SOFTCLOCK)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); - softintr_dispatch(SI_SOFTCLOCK); - } - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && - (pcpl < IPL_SOFTNET)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); - softintr_dispatch(SI_SOFTNET); - } - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && - (pcpl < IPL_SOFTTTY)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); - softintr_dispatch(SI_SOFTTTY); - } - - } while (ci->ci_ipending & ppc_smask[pcpl]); - macintr_setipl(pcpl); - ppc_intr_enable(s); - - atomic_clearbits_int(&ci->ci_flags, CI_FLAGS_PROCESSING_SOFT); + macintr_splx(pcpl); /* Process pendings. */ } void diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c index 1b55ffd0e15..41ee10334ca 100644 --- a/sys/arch/macppc/dev/openpic.c +++ b/sys/arch/macppc/dev/openpic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: openpic.c,v 1.75 2014/10/08 22:24:26 deraadt Exp $ */ +/* $OpenBSD: openpic.c,v 1.76 2015/01/04 13:01:42 mpi Exp $ */ /*- * Copyright (c) 2008 Dale Rahn @@ -108,8 +108,6 @@ 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_dis(int pcpl, int s); void openpic_collect_preconf_intr(void); void openpic_ext_intr(void); @@ -235,28 +233,30 @@ openpic_attach(struct device *parent, struct device *self, void *aux) printf("\n"); } +/* Must be called with interrupt disable. */ static inline void openpic_setipl(int newcpl) { struct cpu_info *ci = curcpu(); - int s; - /* XXX - try do to this without the disable */ - s = ppc_intr_disable(); + ci->ci_cpl = newcpl; openpic_set_priority(ci->ci_cpuid, newcpl); - ppc_intr_enable(s); } int openpic_splraise(int newcpl) { struct cpu_info *ci = curcpu(); - newcpl = openpic_pri_share[newcpl]; int ocpl = ci->ci_cpl; + int s; + + newcpl = openpic_pri_share[newcpl]; if (ocpl > newcpl) newcpl = ocpl; + s = ppc_intr_disable(); openpic_setipl(newcpl); + ppc_intr_enable(s); return ocpl; } @@ -275,7 +275,17 @@ openpic_spllower(int newcpl) void openpic_splx(int newcpl) { - openpic_do_pending_int(newcpl); + struct cpu_info *ci = curcpu(); + int intr, s; + + intr = ppc_intr_disable(); + openpic_setipl(newcpl); + if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) { + s = splsofttty(); + dosoftint(newcpl); + openpic_setipl(s); /* no-overhead splx */ + } + ppc_intr_enable(intr); } void @@ -441,71 +451,6 @@ openpic_calc_mask() openpic_set_priority(ci->ci_cpuid, ci->ci_cpl); } -void -openpic_do_pending_int(int pcpl) -{ - int s; - s = ppc_intr_disable(); - 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_int_dis(int pcpl, int s) -{ - struct cpu_info *ci = curcpu(); - - (void)ppc_intr_disable(); - if (ci->ci_flags & CI_FLAGS_PROCESSING_SOFT) { - /* soft interrupts are being processed, just set ipl/return */ - openpic_setipl(pcpl); - ppc_intr_enable(s); - return; - } - - atomic_setbits_int(&ci->ci_flags, CI_FLAGS_PROCESSING_SOFT); - - do { - if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && - (pcpl < IPL_SOFTCLOCK)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); - ppc_intr_enable(1); - KERNEL_LOCK(); - softintr_dispatch(SI_SOFTCLOCK); - KERNEL_UNLOCK(); - (void)ppc_intr_disable(); - } - if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && - (pcpl < IPL_SOFTNET)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); - ppc_intr_enable(1); - KERNEL_LOCK(); - softintr_dispatch(SI_SOFTNET); - KERNEL_UNLOCK(); - (void)ppc_intr_disable(); - } - if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && - (pcpl < IPL_SOFTTTY)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); - ppc_intr_enable(1); - KERNEL_LOCK(); - softintr_dispatch(SI_SOFTTTY); - KERNEL_UNLOCK(); - (void)ppc_intr_disable(); - } - } while (ci->ci_ipending & ppc_smask[pcpl]); - openpic_setipl(pcpl); /* Don't use splx... we are here already! */ - - atomic_clearbits_int(&ci->ci_flags, CI_FLAGS_PROCESSING_SOFT); - ppc_intr_enable(s); -} - void openpic_enable_irq(int irq, int pri) { @@ -618,7 +563,7 @@ openpic_ext_intr() openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid))); if (iq->iq_ipl > maxipl) maxipl = iq->iq_ipl; - splraise(iq->iq_ipl); + openpic_splraise(iq->iq_ipl); openpic_eoi(ci->ci_cpuid); spurious = 1; @@ -649,14 +594,7 @@ openpic_ext_intr() irq = openpic_read_irq(ci->ci_cpuid); } - /* - * sending 0 in to openpic_do_pending_int_dis will leave - * external interrupts disabled, but since we are about - * to return from interrupt leaving them disabled until then - * prevents additional recursion. - */ - openpic_do_pending_int_dis(pcpl, 0); - + openpic_splx(pcpl); /* Process pendings. */ openpic_irqnest[ci->ci_cpuid]--; } diff --git a/sys/arch/powerpc/include/cpu.h b/sys/arch/powerpc/include/cpu.h index ecd5b9e796b..567f0433b58 100644 --- a/sys/arch/powerpc/include/cpu.h +++ b/sys/arch/powerpc/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.58 2014/10/10 04:08:11 mpi Exp $ */ +/* $OpenBSD: cpu.h,v 1.59 2015/01/04 13:01:42 mpi Exp $ */ /* $NetBSD: cpu.h,v 1.1 1996/09/30 16:34:21 ws Exp $ */ /* @@ -57,7 +57,6 @@ struct cpu_info { volatile int ci_ipending; volatile int ci_flags; -#define CI_FLAGS_PROCESSING_SOFT 1 #define CI_FLAGS_SLEEPING 2 int ci_intrdepth; diff --git a/sys/arch/powerpc/include/intr.h b/sys/arch/powerpc/include/intr.h index ce2d4142d43..448e729bf30 100644 --- a/sys/arch/powerpc/include/intr.h +++ b/sys/arch/powerpc/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.49 2013/05/17 19:38:52 kettenis Exp $ */ +/* $OpenBSD: intr.h,v 1.50 2015/01/04 13:01:42 mpi Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. @@ -88,8 +88,24 @@ char *ppc_intr_typename(int type); void do_pending_int(void); /* SPL asserts */ -#define splassert(wantipl) /* nothing */ -#define splsoftassert(wantipl) /* nothing */ +#ifdef DIAGNOSTIC +/* + * Although this function is implemented in MI code, it must be in this MD + * header because we don't want this header to include MI includes. + */ +void splassert_fail(int, int, const char *); +extern int splassert_ctl; +void splassert_check(int, const char *); +#define splassert(__wantipl) do { \ + if (splassert_ctl > 0) { \ + splassert_check(__wantipl, __func__); \ + } \ +} while (0) +#define splsoftassert(wantipl) splassert(wantipl) +#else +#define splassert(wantipl) do { /* nada */ } while (0) +#define splsoftassert(wantipl) do { /* nada */ } while (0) +#endif #define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p) @@ -138,6 +154,7 @@ void *softintr_establish(int, void (*)(void *), void *); void softintr_init(void); void softintr_schedule(void *); +void dosoftint(int); #define set_sint(p) atomic_setbits_int(&curcpu()->ci_ipending, p) diff --git a/sys/arch/powerpc/powerpc/intr.c b/sys/arch/powerpc/powerpc/intr.c index fa5535d646c..35b62911893 100644 --- a/sys/arch/powerpc/powerpc/intr.c +++ b/sys/arch/powerpc/powerpc/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.7 2011/08/29 20:21:44 drahn Exp $ */ +/* $OpenBSD: intr.c,v 1.8 2015/01/04 13:01:42 mpi Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. @@ -121,7 +121,7 @@ ppc_dflt_splx(int newcpl) ci->ci_cpl = newcpl; if (ci->ci_ipending & ppc_smask[newcpl]) - do_pending_int(); + dosoftint(newcpl); } struct ppc_intr_func ppc_intr_func = @@ -147,3 +147,17 @@ ppc_intr_typename(int type) return ("unknown"); } } + +#ifdef DIAGNOSTIC +void +splassert_check(int wantipl, const char *func) +{ + struct cpu_info *ci = curcpu(); + + if (ci->ci_cpl < wantipl) + splassert_fail(wantipl, ci->ci_cpl, func); + + if (wantipl == IPL_NONE && ci->ci_intrdepth != -1) + splassert_fail(-1, ci->ci_intrdepth, func); +} +#endif diff --git a/sys/arch/powerpc/powerpc/softintr.c b/sys/arch/powerpc/powerpc/softintr.c index f018a1b120a..6f5f92acfc5 100644 --- a/sys/arch/powerpc/powerpc/softintr.c +++ b/sys/arch/powerpc/powerpc/softintr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softintr.c,v 1.6 2014/07/12 18:44:42 tedu Exp $ */ +/* $OpenBSD: softintr.c,v 1.7 2015/01/04 13:01:42 mpi Exp $ */ /* $NetBSD: softintr.c,v 1.2 2003/07/15 00:24:39 lukem Exp $ */ /* @@ -92,9 +92,7 @@ softintr_dispatch(int si) mtx_leave(&siq->siq_mtx); - KERNEL_LOCK(); (*sih->sih_func)(sih->sih_arg); - KERNEL_UNLOCK(); } } @@ -176,21 +174,25 @@ softintr_schedule(void *arg) mtx_leave(&siq->siq_mtx); } -#if 0 void -dosoftint(int xcpl) +dosoftint(int pcpl) { struct cpu_info *ci = curcpu(); int sir, q, mask; - while ((sir = (ci->ci_ipending & SINT_ALLMASK & ~xcpl)) != 0) { + ppc_intr_enable(1); + KERNEL_LOCK(); + + while ((sir = (ci->ci_ipending & ppc_smask[pcpl])) != 0) { atomic_clearbits_int(&ci->ci_ipending, sir); for (q = SI_NQUEUES - 1; q >= 0; q--) { - mask = SINTMASK(q); + mask = SI_TO_IRQBIT(q); if (sir & mask) softintr_dispatch(q); } } + + KERNEL_UNLOCK(); + (void)ppc_intr_disable(); } -#endif diff --git a/sys/arch/socppc/dev/ipic.c b/sys/arch/socppc/dev/ipic.c index b7205e5c490..44b4d37f305 100644 --- a/sys/arch/socppc/dev/ipic.c +++ b/sys/arch/socppc/dev/ipic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipic.c,v 1.16 2014/02/08 10:58:17 kettenis Exp $ */ +/* $OpenBSD: ipic.c,v 1.17 2015/01/04 13:01:42 mpi Exp $ */ /* * Copyright (c) 2008 Mark Kettenis @@ -298,11 +298,11 @@ intr_establish(int ivec, int type, int level, */ s = ppc_intr_disable(); TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); - ppc_intr_enable(s); /* Unmask the interrupt. */ if (sc) ipic_setipl(curcpu()->ci_cpl); + ppc_intr_enable(s); return (ih); } @@ -347,11 +347,14 @@ ipic_splraise(int newcpl) { struct cpu_info *ci = curcpu(); int ocpl = ci->ci_cpl; + int s; if (ocpl > newcpl) newcpl = ocpl; + s = ppc_intr_disable(); ipic_setipl(newcpl); + ppc_intr_enable(s); return (ocpl); } @@ -371,21 +374,26 @@ void ipic_splx(int newcpl) { struct cpu_info *ci = curcpu(); + int intr, s; + intr = ppc_intr_disable(); ipic_setipl(newcpl); - if (ci->ci_ipending & ppc_smask[newcpl]) - do_pending_int(); + if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) { + s = splsofttty(); + dosoftint(newcpl); + ipic_setipl(s); /* no-overhead splx */ + } + ppc_intr_enable(intr); } +/* Must be called with interrupt disable. */ void ipic_setipl(int ipl) { struct cpu_info *ci = curcpu(); struct ipic_softc *sc = ipic_sc; uint32_t mask; - int s; - 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); @@ -393,5 +401,4 @@ ipic_setipl(int ipl) ipic_write(sc, IPIC_SIMSR_L, mask); 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/machdep.c b/sys/arch/socppc/socppc/machdep.c index 2edb7167d7e..2f9d5fc3d1c 100644 --- a/sys/arch/socppc/socppc/machdep.c +++ b/sys/arch/socppc/socppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.60 2014/12/10 15:29:53 mikeb Exp $ */ +/* $OpenBSD: machdep.c,v 1.61 2015/01/04 13:01:42 mpi Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -1084,43 +1084,6 @@ haltsys: /* NOTREACHED */ } -void -do_pending_int(void) -{ - struct cpu_info *ci = curcpu(); - int pcpl = ci->ci_cpl; /* XXX */ - int s; - s = ppc_intr_disable(); - if (ci->ci_flags & CI_FLAGS_PROCESSING_SOFT) { - ppc_intr_enable(s); - return; - } - atomic_setbits_int(&ci->ci_flags, CI_FLAGS_PROCESSING_SOFT); - - do { - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && - (pcpl < IPL_SOFTCLOCK)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); - softintr_dispatch(SI_SOFTCLOCK); - } - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && - (pcpl < IPL_SOFTNET)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); - softintr_dispatch(SI_SOFTNET); - } - if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && - (pcpl < IPL_SOFTTTY)) { - ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); - softintr_dispatch(SI_SOFTTTY); - } - - } while (ci->ci_ipending & ppc_smask[pcpl]); - splx(pcpl); - ppc_intr_enable(s); - - atomic_clearbits_int(&ci->ci_flags, CI_FLAGS_PROCESSING_SOFT); -} - /* * Notify the current process (p) that it has a signal pending, * process as soon as possible.