So here is the diff that brings the changes I made to the armv7
version over to arm64.  I've now verified that it actually works.
Even better, I've verified that it fixes my Overdrive 1000!

It seems not all Overdrives are created equally.  The Overdrive 3000
has 8 cores, but the Overdrive 1000 has only 4 cores.  I believe the
actual silicon is the same, but that the Overdrive 1000 simply has 4
of the 8 cores disabled.  And it turns out that on my machine those
disabled cores are different than on jsg@'s machine.  The device tree
for his machine has 'cpu' nodes with the following 'reg' properties:

    reg: 00000000.00000000
    reg: 00000000.00000001
    reg: 00000000.00000100
    reg: 00000000.00000101

and boots from the first.  Mine has:

    reg: 00000000.00000100
    reg: 00000000.00000101
    reg: 00000000.00000200
    reg: 00000000.00000201

and also boots from the first.  But since the current ampintc(4) code
unconditionally routes the interrupts to the core with the all zero
'reg' property, interrupts don't work on mine.  Makes you wonder if
they have some production issues and sell chips with some
non-functional cores as 4-core versions.

Anyway, I'd like to commit this diff now.

ok?


Index: arch/arm64/dev/ampintc.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/dev/ampintc.c,v
retrieving revision 1.7
diff -u -p -r1.7 ampintc.c
--- arch/arm64/dev/ampintc.c    25 Feb 2017 17:04:19 -0000      1.7
+++ arch/arm64/dev/ampintc.c    8 Apr 2017 10:49:27 -0000
@@ -138,6 +138,7 @@ struct ampintc_softc {
        int                      sc_nintr;
        bus_space_tag_t          sc_iot;
        bus_space_handle_t       sc_d_ioh, sc_p_ioh;
+       uint8_t                  sc_cpu_mask[ICD_ICTR_CPU_M + 1];
        struct evcount           sc_spur;
        struct interrupt_controller sc_ic;
 };
@@ -184,7 +185,7 @@ void                 ampintc_set_priority(int, int);
 void            ampintc_intr_enable(int);
 void            ampintc_intr_disable(int);
 void            ampintc_intr_config(int, int);
-void            ampintc_route(int, int , int);
+void            ampintc_route(int, int, struct cpu_info *);
 
 struct cfattach        ampintc_ca = {
        sizeof (struct ampintc_softc), ampintc_match, ampintc_attach
@@ -220,7 +221,8 @@ ampintc_attach(struct device *parent, st
 {
        struct ampintc_softc *sc = (struct ampintc_softc *)self;
        struct fdt_attach_args *faa = aux;
-       int i, nintr;
+       int i, nintr, ncpu;
+       uint32_t ictr;
 
        ampintc = sc;
 
@@ -240,11 +242,16 @@ ampintc_attach(struct device *parent, st
 
        evcount_attach(&sc->sc_spur, "irq1023/spur", NULL);
 
-       nintr = 32 * (bus_space_read_4(sc->sc_iot, sc->sc_d_ioh,
-           ICD_ICTR) & ICD_ICTR_ITL_M);
+       ictr = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICTR);
+       nintr = 32 * ((ictr >> ICD_ICTR_ITL_SH) & ICD_ICTR_ITL_M);
        nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */
        sc->sc_nintr = nintr;
-       printf(" nirq %d", nintr);
+       ncpu = ((ictr >> ICD_ICTR_CPU_SH) & ICD_ICTR_CPU_M) + 1;
+       printf(" nirq %d, ncpu %d", nintr, ncpu);
+
+       KASSERT(curcpu()->ci_cpuid <= ICD_ICTR_CPU_M);
+       sc->sc_cpu_mask[curcpu()->ci_cpuid] =
+           bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(0));
 
        /* Disable all interrupts, clear all pending */
        for (i = 0; i < nintr/32; i++) {
@@ -403,11 +410,10 @@ ampintc_calc_mask(void)
                if (min != IPL_NONE) {
                        ampintc_set_priority(irq, min);
                        ampintc_intr_enable(irq);
-                       ampintc_route(irq, IRQ_ENABLE, 0);
+                       ampintc_route(irq, IRQ_ENABLE, ci);
                } else {
                        ampintc_intr_disable(irq);
-                       ampintc_route(irq, IRQ_DISABLE, 0);
-
+                       ampintc_route(irq, IRQ_DISABLE, ci);
                }
        }
        ampintc_setipl(ci->ci_cpl);
@@ -476,16 +482,19 @@ ampintc_eoi(uint32_t eoi)
 }
 
 void
-ampintc_route(int irq, int enable, int cpu)
+ampintc_route(int irq, int enable, struct cpu_info *ci)
 {
-       uint8_t  val;
        struct ampintc_softc    *sc = ampintc;
+       uint8_t                  mask, val;
+
+       KASSERT(ci->ci_cpuid <= ICD_ICTR_CPU_M);
+       mask = sc->sc_cpu_mask[ci->ci_cpuid];
 
        val = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq));
        if (enable == IRQ_ENABLE)
-               val |= (1 << cpu);
+               val |= mask;
        else
-               val &= ~(1 << cpu);
+               val &= ~mask;
        bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), val);
 }
 

Reply via email to