Implement splassert(9) for powerpc.
authormpi <mpi@openbsd.org>
Sun, 4 Jan 2015 13:01:42 +0000 (13:01 +0000)
committermpi <mpi@openbsd.org>
Sun, 4 Jan 2015 13:01:42 +0000 (13:01 +0000)
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.

sys/arch/macppc/dev/macintr.c
sys/arch/macppc/dev/openpic.c
sys/arch/powerpc/include/cpu.h
sys/arch/powerpc/include/intr.h
sys/arch/powerpc/powerpc/intr.c
sys/arch/powerpc/powerpc/softintr.c
sys/arch/socppc/dev/ipic.c
sys/arch/socppc/socppc/machdep.c

index b0c6931..443e70a 100644 (file)
@@ -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 <drahn@openbsd.org>
@@ -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
index 1b55ffd..41ee103 100644 (file)
@@ -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 <drahn@openbsd.org>
@@ -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]--;
 }
 
index ecd5b9e..567f043 100644 (file)
@@ -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;
index ce2d414..448e729 100644 (file)
@@ -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)
 
index fa5535d..35b6291 100644 (file)
@@ -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
index f018a1b..6f5f92a 100644 (file)
@@ -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
index b7205e5..44b4d37 100644 (file)
@@ -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);
 }
index 2edb716..2f9d5fc 100644 (file)
@@ -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.