From d0056b06edc3f565a6fc3eebefdef84caf43c69d Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 31 Mar 2022 18:47:04 +0000 Subject: [PATCH] Implement support for multiple dies. This should make OpenBSD work on the M1 Ultra. ok patrick@ --- sys/arch/arm64/dev/aplintc.c | 133 +++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 51 deletions(-) diff --git a/sys/arch/arm64/dev/aplintc.c b/sys/arch/arm64/dev/aplintc.c index 7769942fcf1..814a74f1d5d 100644 --- a/sys/arch/arm64/dev/aplintc.c +++ b/sys/arch/arm64/dev/aplintc.c @@ -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 * @@ -44,10 +44,12 @@ #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 @@ -70,13 +72,14 @@ #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); -- 2.20.1