-/* $OpenBSD: agintc.c,v 1.45 2022/12/21 22:30:42 kettenis Exp $ */
+/* $OpenBSD: agintc.c,v 1.46 2022/12/21 23:18:09 patrick Exp $ */
/*
* Copyright (c) 2007, 2009, 2011, 2017 Dale Rahn <drahn@dalerahn.com>
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
void agintc_splx(int);
int agintc_splraise(int);
void agintc_setipl(int);
+void agintc_enable_wakeup(void);
+void agintc_disable_wakeup(void);
void agintc_calc_mask(void);
void agintc_calc_irq(struct agintc_softc *sc, int irq);
void *agintc_intr_establish(int, int, int, struct cpu_info *,
void *agintc_intr_establish_mbi(void *, uint64_t *, uint64_t *,
int , struct cpu_info *, int (*)(void *), void *, char *);
void agintc_intr_disestablish(void *);
+void agintc_intr_set_wakeup(void *);
void agintc_irq_handler(void *);
uint32_t agintc_iack(void);
void agintc_eoi(uint32_t);
/* insert self as interrupt handler */
arm_set_intr_handler(agintc_splraise, agintc_spllower, agintc_splx,
- agintc_setipl, agintc_irq_handler, NULL, NULL, NULL);
+ agintc_setipl, agintc_irq_handler, NULL,
+ agintc_enable_wakeup, agintc_disable_wakeup);
/* enable interrupts */
ctrl = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, GICD_CTLR);
sc->sc_ic.ic_barrier = agintc_intr_barrier;
if (sc->sc_mbi_nranges > 0)
sc->sc_ic.ic_establish_msi = agintc_intr_establish_mbi;
+ sc->sc_ic.ic_set_wakeup = agintc_intr_set_wakeup;
arm_intr_register_fdt(&sc->sc_ic);
intr_restore(psw);
intr_restore(psw);
}
+void
+agintc_enable_wakeup(void)
+{
+ struct agintc_softc *sc = agintc_sc;
+ struct intrhand *ih;
+ uint8_t *prop;
+ int irq, wakeup;
+
+ for (irq = 0; irq < sc->sc_nintr; irq++) {
+ /* No handler? Disabled already. */
+ if (TAILQ_EMPTY(&sc->sc_handler[irq].iq_list))
+ continue;
+ /* Unless we're WAKEUP, disable. */
+ wakeup = 0;
+ TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
+ if (ih->ih_flags & IPL_WAKEUP) {
+ wakeup = 1;
+ break;
+ }
+ }
+ if (!wakeup)
+ agintc_intr_disable(sc, irq);
+ }
+
+ for (irq = 0; irq < sc->sc_nlpi; irq++) {
+ ih = sc->sc_lpi_handler[irq];
+ if (ih == NULL || (ih->ih_flags & IPL_WAKEUP))
+ continue;
+ prop = AGINTC_DMA_KVA(sc->sc_prop);
+ prop[irq] &= ~GICR_PROP_ENABLE;
+ /* Make globally visible. */
+ cpu_dcache_wb_range((vaddr_t)&prop[irq],
+ sizeof(*prop));
+ __asm volatile("dsb sy");
+ }
+}
+
+void
+agintc_disable_wakeup(void)
+{
+ struct agintc_softc *sc = agintc_sc;
+ struct intrhand *ih;
+ uint8_t *prop;
+ int irq, wakeup;
+
+ for (irq = 0; irq < sc->sc_nintr; irq++) {
+ /* No handler? Keep disabled. */
+ if (TAILQ_EMPTY(&sc->sc_handler[irq].iq_list))
+ continue;
+ /* WAKEUPs are already enabled. */
+ wakeup = 0;
+ TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
+ if (ih->ih_flags & IPL_WAKEUP) {
+ wakeup = 1;
+ break;
+ }
+ }
+ if (!wakeup)
+ agintc_intr_enable(sc, irq);
+ }
+
+ for (irq = 0; irq < sc->sc_nlpi; irq++) {
+ ih = sc->sc_lpi_handler[irq];
+ if (ih == NULL || (ih->ih_flags & IPL_WAKEUP))
+ continue;
+ prop = AGINTC_DMA_KVA(sc->sc_prop);
+ prop[irq] |= GICR_PROP_ENABLE;
+ /* Make globally visible. */
+ cpu_dcache_wb_range((vaddr_t)&prop[irq],
+ sizeof(*prop));
+ __asm volatile("dsb sy");
+ }
+}
+
void
agintc_intr_enable(struct agintc_softc *sc, int irq)
{
free(ih, M_DEVBUF, 0);
}
+void
+agintc_intr_set_wakeup(void *cookie)
+{
+ struct intrhand *ih = cookie;
+
+ ih->ih_flags |= IPL_WAKEUP;
+}
+
void *
agintc_intr_establish_mbi(void *self, uint64_t *addr, uint64_t *data,
int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name)