Implement support for multiple dies. This should make OpenBSD work on the
authorkettenis <kettenis@openbsd.org>
Thu, 31 Mar 2022 18:47:04 +0000 (18:47 +0000)
committerkettenis <kettenis@openbsd.org>
Thu, 31 Mar 2022 18:47:04 +0000 (18:47 +0000)
M1 Ultra.

ok patrick@

sys/arch/arm64/dev/aplintc.c

index 7769942..814a74f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: aplintc.c,v 1.8 2022/03/12 11:28:55 kettenis Exp $    */
+/*     $OpenBSD: aplintc.c,v 1.9 2022/03/31 18:47:04 kettenis Exp $    */
 /*
  * Copyright (c) 2021 Mark Kettenis
  *
 #define CNTV_CTL_ISTATUS       (1 << 2)
 
 #define AIC_INFO               0x0004
+#define  AIC_INFO_NDIE(val)    (((val) >> 24) & 0xf)
 #define  AIC_INFO_NIRQ(val)    ((val) & 0xffff)
 #define AIC_WHOAMI             0x2000
 #define AIC_EVENT              0x2004
-#define  AIC_EVENT_TYPE(val)   ((val) >> 16)
+#define  AIC_EVENT_DIE(val)    (((val) >> 24) & 0xff)
+#define  AIC_EVENT_TYPE(val)   (((val) >> 16) & 0xff)
 #define  AIC_EVENT_TYPE_NONE   0
 #define  AIC_EVENT_TYPE_IRQ    1
 #define  AIC_EVENT_TYPE_IPI    4
 
 #define AIC2_CONFIG            0x0014
 #define  AIC2_CONFIG_ENABLE    (1 << 0)
-#define AIC2_SW_SET(irq)       (0x6000 + (((irq) >> 5) << 2))
-#define AIC2_SW_CLR(irq)       (0x6200 + (((irq) >> 5) << 2))
-#define AIC2_MASK_SET(irq)     (0x6400 + (((irq) >> 5) << 2))
-#define AIC2_MASK_CLR(irq)     (0x6600 + (((irq) >> 5) << 2))
+#define AIC2_SW_SET(die, irq)  (0x6000 + (die) * 0x4a00 + (((irq) >> 5) << 2))
+#define AIC2_SW_CLR(die, irq)  (0x6200 + (die) * 0x4a00 + (((irq) >> 5) << 2))
+#define AIC2_MASK_SET(die, irq)        (0x6400 + (die) * 0x4a00 + (((irq) >> 5) << 2))
+#define AIC2_MASK_CLR(die, irq)        (0x6600 + (die) * 0x4a00 + (((irq) >> 5) << 2))
 #define AIC2_EVENT             0xc000
 
 #define AIC_MAXCPUS            32
+#define AIC_MAXDIES            4
 
 #define HREAD4(sc, reg)                                                        \
        (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
@@ -93,6 +96,7 @@ struct intrhand {
        void            *ih_arg;
        int             ih_ipl;
        int             ih_flags;
+       int             ih_die;
        int             ih_irq;
        struct evcount  ih_count;
        const char      *ih_name;
@@ -111,8 +115,9 @@ struct aplintc_softc {
 
        struct intrhand         *sc_fiq_handler;
        int                     sc_fiq_pending[AIC_MAXCPUS];
-       struct intrhand         **sc_irq_handler;
+       struct intrhand         **sc_irq_handler[AIC_MAXDIES];
        int                     sc_nirq;
+       int                     sc_ndie;
        TAILQ_HEAD(, intrhand)  sc_irq_list[NIPL];
 
        uint32_t                sc_cpuremap[AIC_MAXCPUS];
@@ -164,7 +169,7 @@ aplintc_attach(struct device *parent, struct device *self, void *aux)
        struct aplintc_softc *sc = (struct aplintc_softc *)self;
        struct fdt_attach_args *faa = aux;
        uint32_t info;
-       int ipl;
+       int die, ipl;
 
        if (faa->fa_nreg < 1) {
                printf(": no registers\n");
@@ -207,12 +212,15 @@ aplintc_attach(struct device *parent, struct device *self, void *aux)
 
        info = HREAD4(sc, AIC_INFO);
        sc->sc_nirq = AIC_INFO_NIRQ(info);
-       sc->sc_irq_handler = mallocarray(sc->sc_nirq,
-           sizeof(*sc->sc_irq_handler), M_DEVBUF, M_WAITOK | M_ZERO);
+       sc->sc_ndie = AIC_INFO_NDIE(info) + 1;
+       for (die = 0; die < sc->sc_ndie; die++) {
+               sc->sc_irq_handler[die] = mallocarray(sc->sc_nirq,
+                   sizeof(struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO);
+       }
        for (ipl = 0; ipl < NIPL; ipl++)
                TAILQ_INIT(&sc->sc_irq_list[ipl]);
 
-       printf(" nirq %d\n", sc->sc_nirq);
+       printf(" nirq %d ndie %d\n", sc->sc_nirq, sc->sc_ndie);
 
        arm_init_smask();
 
@@ -262,6 +270,42 @@ aplintc_cpuinit(void)
        }
 }
 
+static inline void
+aplintc_sw_clr(struct aplintc_softc *sc, int die, int irq)
+{
+       if (sc->sc_version == 1)
+               HWRITE4(sc, AIC_SW_CLR(irq), AIC_SW_BIT(irq));
+       else
+               HWRITE4(sc, AIC2_SW_CLR(die, irq), AIC_SW_BIT(irq));
+}
+
+static inline void
+aplintc_sw_set(struct aplintc_softc *sc, int die, int irq)
+{
+       if (sc->sc_version == 1)
+               HWRITE4(sc, AIC_SW_SET(irq), AIC_SW_BIT(irq));
+       else
+               HWRITE4(sc, AIC2_SW_SET(die, irq), AIC_SW_BIT(irq));
+}
+
+static inline void
+aplintc_mask_clr(struct aplintc_softc *sc, int die, int irq)
+{
+       if (sc->sc_version == 1)
+               HWRITE4(sc, AIC_MASK_CLR(irq), AIC_MASK_BIT(irq));
+       else
+               HWRITE4(sc, AIC2_MASK_CLR(die, irq), AIC_MASK_BIT(irq));
+}
+
+static inline void
+aplintc_mask_set(struct aplintc_softc *sc, int die, int irq)
+{
+       if (sc->sc_version == 1)
+               HWRITE4(sc, AIC_MASK_SET(irq), AIC_MASK_BIT(irq));
+       else
+               HWRITE4(sc, AIC2_MASK_SET(die, irq), AIC_MASK_BIT(irq));
+}
+
 void
 aplintc_run_handler(struct intrhand *ih, void *frame, int s)
 {
@@ -302,10 +346,11 @@ aplintc_irq_handler(void *frame)
        struct cpu_info *ci = curcpu();
        struct intrhand *ih;
        uint32_t event;
-       uint32_t irq, type;
+       uint32_t die, irq, type;
        int s;
 
        event = bus_space_read_4(sc->sc_iot, sc->sc_event_ioh, 0);
+       die = AIC_EVENT_DIE(event);
        irq = AIC_EVENT_IRQ(event);
        type = AIC_EVENT_TYPE(event);
 
@@ -317,18 +362,16 @@ aplintc_irq_handler(void *frame)
                return;
        }
 
+       if (die >= sc->sc_ndie)
+               panic("%s: unexpected die %d", __func__, die);
        if (irq >= sc->sc_nirq)
                panic("%s: unexpected irq %d", __func__, irq);
 
-       if (sc->sc_irq_handler[irq] == NULL)
+       if (sc->sc_irq_handler[die][irq] == NULL)
                return;
 
-       if (sc->sc_version == 1)
-               HWRITE4(sc, AIC_SW_CLR(irq), AIC_SW_BIT(irq));
-       else
-               HWRITE4(sc, AIC2_SW_CLR(irq), AIC_SW_BIT(irq));
-
-       ih = sc->sc_irq_handler[irq];
+       aplintc_sw_clr(sc, die, irq);
+       ih = sc->sc_irq_handler[die][irq];
 
        if (ci->ci_cpl >= ih->ih_ipl) {
                /* Queue interrupt as pending. */
@@ -340,10 +383,7 @@ aplintc_irq_handler(void *frame)
                intr_disable();
                aplintc_splx(s);
 
-               if (sc->sc_version == 1)
-                       HWRITE4(sc, AIC_MASK_CLR(irq), AIC_MASK_BIT(irq));
-               else
-                       HWRITE4(sc, AIC2_MASK_CLR(irq), AIC_MASK_BIT(irq));
+               aplintc_mask_clr(sc, die, irq);
        }
 }
 
@@ -437,17 +477,8 @@ aplintc_splx(int new)
                                TAILQ_REMOVE(&sc->sc_irq_list[ipl],
                                    ih, ih_list);
 
-                               if (sc->sc_version == 1) {
-                                       HWRITE4(sc, AIC_SW_SET(ih->ih_irq),
-                                           AIC_SW_BIT(ih->ih_irq));
-                                       HWRITE4(sc, AIC_MASK_CLR(ih->ih_irq),
-                                           AIC_MASK_BIT(ih->ih_irq));
-                               } else {
-                                       HWRITE4(sc, AIC2_SW_SET(ih->ih_irq),
-                                           AIC_SW_BIT(ih->ih_irq));
-                                       HWRITE4(sc, AIC2_MASK_CLR(ih->ih_irq),
-                                           AIC_MASK_BIT(ih->ih_irq));
-                               }
+                               aplintc_sw_set(sc, ih->ih_die, ih->ih_irq);
+                               aplintc_mask_clr(sc, ih->ih_die, ih->ih_irq);
                        }
                }
        }
@@ -474,15 +505,22 @@ aplintc_intr_establish(void *cookie, int *cell, int level,
        struct aplintc_softc *sc = cookie;
        struct intrhand *ih;
        uint32_t type = cell[0];
-       uint32_t irq;
+       uint32_t die, irq;
 
-       if (sc->sc_version == 1)
+       if (sc->sc_version == 1) {
+               die = 0;
                irq = cell[1];
-       else
+       } else {
+               die = cell[1];
                irq = cell[2];
+       }
 
        if (type == 0) {
                KASSERT(level != (IPL_CLOCK | IPL_MPSAFE));
+               if (die >= sc->sc_ndie) {
+                       panic("%s: bogus die number %d",
+                           sc->sc_dev.dv_xname, die);
+               }
                if (irq >= sc->sc_nirq) {
                        panic("%s: bogus irq number %d",
                            sc->sc_dev.dv_xname, irq);
@@ -502,6 +540,7 @@ aplintc_intr_establish(void *cookie, int *cell, int level,
        ih->ih_arg = arg;
        ih->ih_ipl = level & IPL_IRQMASK;
        ih->ih_flags = level & IPL_FLAGMASK;
+       ih->ih_die = die;
        ih->ih_irq = irq;
        ih->ih_name = name;
        ih->ih_ci = ci;
@@ -510,13 +549,10 @@ aplintc_intr_establish(void *cookie, int *cell, int level,
                evcount_attach(&ih->ih_count, name, &ih->ih_irq);
 
        if (type == 0) {
-               sc->sc_irq_handler[irq] = ih;
-               if (sc->sc_version == 1) {
+               sc->sc_irq_handler[die][irq] = ih;
+               if (sc->sc_version == 1)
                        HWRITE4(sc, AIC_TARGET_CPU(irq), 1);
-                       HWRITE4(sc, AIC_MASK_CLR(irq), AIC_MASK_BIT(irq));
-               } else {
-                       HWRITE4(sc, AIC2_MASK_CLR(irq), AIC_MASK_BIT(irq));
-               }
+               aplintc_mask_clr(sc, die, irq);
        } else
                sc->sc_fiq_handler = ih;
 
@@ -535,13 +571,8 @@ aplintc_intr_disestablish(void *cookie)
 
        daif = intr_disable();
 
-       if (sc->sc_version == 1) {
-               HWRITE4(sc, AIC_SW_CLR(ih->ih_irq), AIC_SW_BIT(ih->ih_irq));
-               HWRITE4(sc, AIC_MASK_SET(ih->ih_irq), AIC_MASK_BIT(ih->ih_irq));
-       } else {
-               HWRITE4(sc, AIC2_SW_CLR(ih->ih_irq), AIC_SW_BIT(ih->ih_irq));
-               HWRITE4(sc, AIC2_MASK_SET(ih->ih_irq), AIC_MASK_BIT(ih->ih_irq));
-       }
+       aplintc_sw_clr(sc, ih->ih_die, ih->ih_irq);
+       aplintc_mask_set(sc, ih->ih_die, ih->ih_irq);
 
        /* Remove ourselves from the list of pending IRQs. */
        TAILQ_FOREACH(tmp, &sc->sc_irq_list[ih->ih_ipl], ih_list) {
@@ -552,7 +583,7 @@ aplintc_intr_disestablish(void *cookie)
                }
        }
 
-       sc->sc_irq_handler[ih->ih_irq] = NULL;
+       sc->sc_irq_handler[ih->ih_die][ih->ih_irq] = NULL;
        if (ih->ih_name)
                evcount_detach(&ih->ih_count);