-/* $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)))
void *ih_arg;
int ih_ipl;
int ih_flags;
+ int ih_die;
int ih_irq;
struct evcount ih_count;
const char *ih_name;
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];
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");
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();
}
}
+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)
{
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);
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. */
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);
}
}
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);
}
}
}
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);
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;
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;
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) {
}
}
- 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);