Changes in interrupt controller infrastructure to support smp.

Add an API that allows a processor to direct an interrupt to multiple cores
enable support for ampintc to serice MPSAFE interrupts.

bcm does not yet have support enabled, but are updated to be compatible
for single processor support.

This is needed for local timer interrupt support.

diff --git a/sys/arch/arm64/arm64/intr.c b/sys/arch/arm64/arm64/intr.c
index 24efa304017..f41cc8fbda9 100644
--- a/sys/arch/arm64/arm64/intr.c
+++ b/sys/arch/arm64/arm64/intr.c
@@ -53,7 +53,8 @@ struct arm_intr_func arm_intr_func = {
        arm_dflt_splx,
        arm_dflt_setipl,
        arm_dflt_intr_establish,
-       arm_dflt_intr_disestablish
+       arm_dflt_intr_disestablish,
+       NULL
 };
 
 void (*arm_intr_dispatch)(void *) = arm_dflt_intr;
@@ -71,16 +72,26 @@ arm_dflt_intr(void *frame)
 }
 
 
-void *arm_intr_establish(int irqno, int level, int (*func)(void *),
+void *
+arm_intr_establish(int irqno, int level, int (*func)(void *),
     void *cookie, char *name)
 {
        return arm_intr_func.intr_establish(irqno, level, func, cookie, name);
 }
-void arm_intr_disestablish(void *cookie)
+
+void
+arm_intr_disestablish(void *cookie)
 {
        arm_intr_func.intr_disestablish(cookie);
 }
 
+void
+arm_intr_route_ih(void *cookie, int enable, int cpu_idx)
+{
+       if (arm_intr_func.route_ih)
+               arm_intr_func.route_ih(cookie, enable, cpu_idx);
+}
+
 /*
  * Find the interrupt parent by walking up the tree.
  */
@@ -224,11 +235,6 @@ arm_intr_register_fdt(struct interrupt_controller *ic)
        }
 }
 
-struct arm_intr_handle {
-       struct interrupt_controller *ih_ic;
-       void *ih_ih;
-};
-
 void *
 arm_intr_establish_fdt(int node, int level, int (*func)(void *),
     void *cookie, char *name)
@@ -457,7 +463,8 @@ void arm_set_intr_handler(int (*raise)(int), int 
(*lower)(int),
        void *(*intr_establish)(int irqno, int level, int (*func)(void *),
            void *cookie, char *name),
        void (*intr_disestablish)(void *cookie),
-       void (*intr_handle)(void *))
+       void (*intr_handle)(void *),
+       void (*route_ih)(void*, int, int))
 {
        arm_intr_func.raise             = raise;
        arm_intr_func.lower             = lower;
@@ -466,6 +473,7 @@ void arm_set_intr_handler(int (*raise)(int), int 
(*lower)(int),
        arm_intr_func.intr_establish    = intr_establish;
        arm_intr_func.intr_disestablish = intr_disestablish;
        arm_intr_dispatch               = intr_handle;
+       arm_intr_func.route_ih          = route_ih;
 }
 
 void
@@ -586,6 +594,15 @@ cpu_initclocks(void)
 }
 
 void
+cpu_startclock(void)
+{
+       if (arm_clock_func.mpstartclock == NULL)
+               panic("mpstartclock function not initialized yet");
+
+       arm_clock_func.mpstartclock();
+}
+
+void
 arm_dflt_delay(u_int usecs)
 {
        int j;
diff --git a/sys/arch/arm64/dev/agtimer.c b/sys/arch/arm64/dev/agtimer.c
index 278ad9a0e19..4517283adc7 100644
--- a/sys/arch/arm64/dev/agtimer.c
+++ b/sys/arch/arm64/dev/agtimer.c
@@ -65,6 +65,7 @@ struct agtimer_softc {
        u_int32_t               sc_ticks_per_intr;
        u_int32_t               sc_statvar;
        u_int32_t               sc_statmin;
+       void                    *sc_ih;
 
 #ifdef AMPTIMER_DEBUG
        struct evcount          sc_clk_count;
@@ -297,10 +298,10 @@ agtimer_cpu_initclocks()
        pc->pc_ticks_err_sum = 0;
 
        /* Setup secure and non-secure timer IRQs. */
-       arm_intr_establish_fdt_idx(sc->sc_node, 0, IPL_CLOCK,
-           agtimer_intr, NULL, "tick");
-       arm_intr_establish_fdt_idx(sc->sc_node, 1, IPL_CLOCK,
-           agtimer_intr, NULL, "tick");
+       // irq 0 is cntv, irq 1 is cntp, since this only supports
+       // cntp, only register the one interrupt.
+       sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 1,
+           IPL_CLOCK | IPL_MPSAFE, agtimer_intr, NULL, "tick");
 
        next = agtimer_readcnt64() + sc->sc_ticks_per_intr;
        pc->pc_nexttickevent = pc->pc_nextstatevent = next;
@@ -380,13 +381,14 @@ agtimer_startclock(void)
        nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr;
        pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
 
+       arm_intr_route_ih(sc->sc_ih, 1, cpu_number());
+
        reg = agtimer_get_ctrl();
        reg &= ~GTIMER_CNTP_CTL_IMASK;
        reg |= GTIMER_CNTP_CTL_ENABLE;
        agtimer_set_tval(sc->sc_ticks_per_second);
        agtimer_set_ctrl(reg);
 }
-
 void
 agtimer_init(void)
 {
diff --git a/sys/arch/arm64/dev/ampintc.c b/sys/arch/arm64/dev/ampintc.c
index aa15de5798b..58d92079ce8 100644
--- a/sys/arch/arm64/dev/ampintc.c
+++ b/sys/arch/arm64/dev/ampintc.c
@@ -141,6 +141,7 @@ struct intrhand {
        void *ih_arg;                   /* arg for handler */
        int ih_ipl;                     /* IPL_* */
        int ih_irq;                     /* IRQ number */
+       int ih_flags;                   /* flags: eg IPL_MPSAFE */
        struct evcount  ih_count;
        char *ih_name;
 };
@@ -150,6 +151,7 @@ struct intrq {
        int iq_irq;                     /* IRQ to mask while handling */
        int iq_levels;                  /* IPL_*'s this IRQ has */
        int iq_ist;                     /* share type */
+       int iq_route;                   /* cpu route mask */
 };
 
 
@@ -164,6 +166,7 @@ void                *ampintc_intr_establish(int, int, int 
(*)(void *), void *,
                    char *);
 void           *ampintc_intr_establish_ext(int, int, int (*)(void *), void *,
                    char *);
+void            ampintc_route_ih(void *, int, int);
 void           *ampintc_intr_establish_fdt(void *, int *, int,
                    int (*)(void *), void *, char *);
 void            ampintc_intr_disestablish(void *);
@@ -174,7 +177,7 @@ void                 ampintc_eoi(uint32_t);
 void            ampintc_set_priority(int, int);
 void            ampintc_intr_enable(int);
 void            ampintc_intr_disable(int);
-void            ampintc_route(int, int , int);
+void            ampintc_route(int, int);
 
 struct cfattach        ampintc_ca = {
        sizeof (struct ampintc_softc), ampintc_match, ampintc_attach
@@ -263,6 +266,7 @@ ampintc_attach(struct device *parent, struct device *self, 
void *aux)
            sizeof(*sc->sc_ampintc_handler), M_DEVBUF, M_ZERO | M_NOWAIT);
        for (i = 0; i < nintr; i++) {
                TAILQ_INIT(&sc->sc_ampintc_handler[i].iq_list);
+               sc->sc_ampintc_handler[i].iq_route = 0;
        }
 
        ampintc_setipl(IPL_HIGH);  /* XXX ??? */
@@ -271,7 +275,7 @@ ampintc_attach(struct device *parent, struct device *self, 
void *aux)
        /* insert self as interrupt handler */
        arm_set_intr_handler(ampintc_splraise, ampintc_spllower, ampintc_splx,
            ampintc_setipl, ampintc_intr_establish_ext,
-           ampintc_intr_disestablish, ampintc_irq_handler);
+           ampintc_intr_disestablish, ampintc_irq_handler, ampintc_route_ih);
 
        /* enable interrupts */
        bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
@@ -375,12 +379,12 @@ ampintc_calc_mask(void)
                if (min != IPL_NONE) {
                        ampintc_set_priority(irq, min);
                        ampintc_intr_enable(irq);
-                       ampintc_route(irq, IRQ_ENABLE, 0);
+                       sc->sc_ampintc_handler[irq].iq_route |= (1 << 0);
                } else {
                        ampintc_intr_disable(irq);
-                       ampintc_route(irq, IRQ_DISABLE, 0);
-
+                       sc->sc_ampintc_handler[irq].iq_route &= ~(1 << 0);
                }
+               ampintc_route(irq, sc->sc_ampintc_handler[irq].iq_route);
        }
        ampintc_setipl(ci->ci_cpl);
 }
@@ -448,17 +452,29 @@ ampintc_eoi(uint32_t eoi)
 }
 
 void
-ampintc_route(int irq, int enable, int cpu)
+ampintc_route_ih(void *vih, int enable, int cpuid)
 {
-       uint8_t  val;
+       struct arm_intr_handle *aih = vih;
+       struct intrhand         *ih = aih->ih_ih;
        struct ampintc_softc    *sc = ampintc;
 
-       val = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq));
-       if (enable == IRQ_ENABLE)
-               val |= (1 << cpu);
-       else
-               val &= ~(1 << cpu);
-       bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), val);
+       bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
+       bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(ih->ih_irq), 0);
+       ampintc_set_priority(ih->ih_irq, 
+           sc->sc_ampintc_handler[ih->ih_irq].iq_irq);
+       ampintc_intr_enable(ih->ih_irq);
+
+       /* should be value in MPIDR, is the same for early processors. */
+       sc->sc_ampintc_handler[ih->ih_irq].iq_route |= (1 << cpuid);
+       ampintc_route(ih->ih_irq, sc->sc_ampintc_handler[ih->ih_irq].iq_route);
+}
+
+void
+ampintc_route(int irq, int cpumask)
+{
+       struct ampintc_softc    *sc = ampintc;
+
+       bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), cpumask);
 }
 
 void
@@ -499,6 +515,16 @@ ampintc_irq_handler(void *frame)
        pri = sc->sc_ampintc_handler[irq].iq_irq;
        s = ampintc_splraise(pri);
        TAILQ_FOREACH(ih, &sc->sc_ampintc_handler[irq].iq_list, ih_list) {
+#ifdef MULTIPROCESSOR
+               int need_lock;
+
+               if (ih->ih_flags & IPL_MPSAFE)
+                       need_lock = 0;
+               else
+                       need_lock = s < IPL_SCHED;
+               if (need_lock)
+                               KERNEL_LOCK();
+#endif
                if (ih->ih_arg != 0)
                        arg = ih->ih_arg;
                else
@@ -507,9 +533,15 @@ ampintc_irq_handler(void *frame)
                if (ih->ih_func(arg))
                        ih->ih_count.ec_count++;
 
+#ifdef MULTIPROCESSOR
+               if (need_lock)
+                       KERNEL_UNLOCK();
+#endif
        }
        ampintc_eoi(iack_val);
 
+
+
        ampintc_splx(s);
 }
 
@@ -556,7 +588,8 @@ ampintc_intr_establish(int irqno, int level, int 
(*func)(void *),
        ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
        ih->ih_func = func;
        ih->ih_arg = arg;
-       ih->ih_ipl = level;
+       ih->ih_ipl = level &  IPL_IRQMASK;
+       ih->ih_flags = level & IPL_FLAGMASK;
        ih->ih_irq = irqno;
        ih->ih_name = name;
 
@@ -572,7 +605,7 @@ ampintc_intr_establish(int irqno, int level, int 
(*func)(void *),
            name);
 #endif
        ampintc_calc_mask();
-       
+
        restore_interrupts(psw);
        return (ih);
 }
@@ -594,6 +627,10 @@ ampintc_intr_disestablish(void *cookie)
        TAILQ_REMOVE(&sc->sc_ampintc_handler[ih->ih_irq].iq_list, ih, ih_list);
        if (ih->ih_name != NULL)
                evcount_detach(&ih->ih_count);
+
+       if (TAILQ_EMPTY(&sc->sc_ampintc_handler[ih->ih_irq].iq_list))
+               sc->sc_ampintc_handler[ih->ih_irq].iq_route = 0;
+
        free(ih, M_DEVBUF, sizeof(*ih));
 
        ampintc_calc_mask();
diff --git a/sys/arch/arm64/dev/bcm2836_intr.c 
b/sys/arch/arm64/dev/bcm2836_intr.c
index 16d6e1daa50..09fe633ee73 100644
--- a/sys/arch/arm64/dev/bcm2836_intr.c
+++ b/sys/arch/arm64/dev/bcm2836_intr.c
@@ -80,6 +80,7 @@ struct intrhand {
        void *ih_arg;                   /* arg for handler */
        int ih_ipl;                     /* IPL_* */
        int ih_irq;                     /* IRQ number */
+       int ih_flags;                   /* flags, eg MPSAFE */
        struct evcount ih_count;        /* interrupt counter */
        char *ih_name;                  /* device name */
 };
@@ -204,7 +205,7 @@ bcm_intc_attach(struct device *parent, struct device *self, 
void *aux)
        arm_set_intr_handler(bcm_intc_splraise, bcm_intc_spllower,
            bcm_intc_splx, bcm_intc_setipl,
            bcm_intc_intr_establish, bcm_intc_intr_disestablish,
-           bcm_intc_irq_handler);
+           bcm_intc_irq_handler, NULL);
 
        sc->sc_intc.ic_node = faa->fa_node;
        sc->sc_intc.ic_cookie = sc;
@@ -522,7 +523,8 @@ bcm_intc_intr_establish(int irqno, int level, int 
(*func)(void *),
        ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK);
        ih->ih_fun = func;
        ih->ih_arg = arg;
-       ih->ih_ipl = level;
+       ih->ih_ipl = level &  IPL_IRQMASK;
+       ih->ih_flags = level & IPL_FLAGMASK;
        ih->ih_irq = irqno;
        ih->ih_name = name;
 
diff --git a/sys/arch/arm64/include/intr.h b/sys/arch/arm64/include/intr.h
index 10cbe793a93..85c0335255c 100644
--- a/sys/arch/arm64/include/intr.h
+++ b/sys/arch/arm64/include/intr.h
@@ -60,7 +60,9 @@
 #define        NIPL            13      /* number of levels */
 
 /* Interrupt priority 'flags'. */
-#define        IPL_MPSAFE      0       /* no "mpsafe" interrupts */
+#define        IPL_IRQMASK     0x0f    /* priority only */
+#define        IPL_FLAGMASK    0xf00   /* flags only */
+#define        IPL_MPSAFE      0x100   /* no "mpsafe" interrupts */
 
 /* Interrupt sharing types. */
 #define        IST_NONE        0       /* none */
@@ -88,7 +90,8 @@ void   arm_set_intr_handler(int (*raise)(int), int 
(*lower)(int),
     void *(*intr_establish)(int irqno, int level, int (*func)(void *),
         void *cookie, char *name),
     void (*intr_disestablish)(void *cookie),
-    void (*intr_handle)(void *));
+    void (*intr_handle)(void *),
+    void (*route_ih)(void*, int, int));
 
 struct arm_intr_func {
        int (*raise)(int);
@@ -98,6 +101,7 @@ struct arm_intr_func {
        void *(*intr_establish)(int irqno, int level, int (*func)(void *),
            void *cookie, char *name);
        void (*intr_disestablish)(void *cookie);
+       void (*route_ih)(void *cookie, int enable, int cpuid);
 };
 
 extern struct arm_intr_func arm_intr_func;
@@ -131,6 +135,11 @@ extern uint32_t arm_smask[NIPL];
 
 #include <machine/softintr.h>
 
+struct arm_intr_handle {
+       struct interrupt_controller *ih_ic;
+       void *ih_ih;
+};
+
 void   *arm_intr_establish(int irqno, int level, int (*func)(void *),
     void *cookie, char *name);
 void    arm_intr_disestablish(void *cookie);
@@ -153,6 +162,7 @@ struct interrupt_controller {
 
 void    arm_intr_init_fdt(void);
 void    arm_intr_register_fdt(struct interrupt_controller *);
+void    arm_intr_route_ih(void *, int, int);
 void   *arm_intr_establish_fdt(int, int, int (*)(void *),
            void *, char *);
 void   *arm_intr_establish_fdt_idx(int, int, int, int (*)(void *),

Dale Rahn                               dr...@dalerahn.com

Reply via email to