Index | Thread | Search

From:
Marc Zyngier <maz@kernel.org>
Subject:
[PATCH 3/4] Pick the correct timer interrupt for the running EL
To:
tech@openbsd.org
Cc:
kettenis@openbsd.org
Date:
Sun, 12 Apr 2026 11:18:23 +0100

Download raw body.

Thread
When running at EL2, the kernel is using the virtual EL2 timer,
and therefore uses a different interrupt from the one driven by
the virtual EL0 timer which gets used when running at EL1.

Pick the correct interrupt depending on the EL the kernel runs at.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 sys/arch/arm64/dev/agtimer.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/sys/arch/arm64/dev/agtimer.c b/sys/arch/arm64/dev/agtimer.c
index d5700a13f..1f008662d 100644
--- a/sys/arch/arm64/dev/agtimer.c
+++ b/sys/arch/arm64/dev/agtimer.c
@@ -286,10 +286,38 @@ agtimer_set_clockrate(int32_t new_frequency)
 	    sc->sc_ticks_per_second / 1000);
 }
 
+static int
+agtimer_get_intr_idx(int node)
+{
+	const char *intr_name;
+	int intr_idx;
+	uint32_t el;
+
+	__asm volatile("mrs %x0, CurrentEL" : "=r" (el));
+	el >>= 2;
+
+	/* Pick the currect PPI depending on the running EL */
+	switch (el) {
+	case 1:
+		intr_name = "virt";
+		break;
+	case 2:
+		intr_name = "hyp-virt";
+		break;
+	}
+
+	intr_idx = OF_getindex(node, intr_name, "interrupt-names");
+	if (intr_idx >= 0)
+		return intr_idx;
+
+	return (el == 2) ? 4 : 2;
+}
+
 void
 agtimer_cpu_initclocks(void)
 {
 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
+	int ppi_idx;
 
 	stathz = hz;
 	profhz = stathz * 10;
@@ -299,8 +327,10 @@ agtimer_cpu_initclocks(void)
 		agtimer_set_clockrate(agtimer_frequency);
 	}
 
+	ppi_idx = agtimer_get_intr_idx(sc->sc_node);
+
 	/* configure virtual timer interrupt */
-	sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2,
+	sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, ppi_idx,
 	    IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick");
 }
 
-- 
2.51.0