[PATCH v3 03/17] clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE

Marc Zyngier maz at kernel.org
Tue Jun 9 03:21:54 PDT 2026


On Tue, 09 Jun 2026 11:03:21 +0100,
Marek Szyprowski <m.szyprowski at samsung.com> wrote:
> 
> Dear All,
> 
> On 23.05.2026 16:02, Marc Zyngier wrote:
> > When running with at EL2 with VHE enabled, the architecture provides
> > two EL2 timer/counters, dubbed physical and virtual. Apart from their
> > names, they are strictly identical.
> >
> > However, they don't get virtualised the same way, specially when
> > it comes to adding arbitrary offsets to the timers. When running as
> > a guest, the host CNTVOFF_EL2 does apply to the guest's view of
> > CNTHV*_El2. This is not true for CNTPOFF_EL2 and CNTHP*_EL2, as
> > the architecture is broken past the first level of virtualisation
> > (it lacks some essential mechanisms to be usable, despite what
> > the ARM ARM pretends).
> >
> > This means that when running as a L2 guest hypervisor, using the
> > physical timer results in traps to L0, which are then forwarded to
> > L1 in order to emulate the offset, leading to even worse performance
> > due to massive trap amplification (the combination of register and
> > ERET trapping is absolutely lethal).
> >
> > Switch the arch timer code to using the virtual timer when running
> > in VHE by default, only using the physical timer if the interrupt
> > is not correctly described in the firmware tables (which seems
> > to be an unfortunately common case). This comes as no impact on
> > bare-metal, and slightly improves the situation in the virtualised
> > case.
> >
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> This patch landed recently in linux-next as commit d87773de9efe
> ("clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when
> running VHE"). In my tests I found that it breaks booting of RaspberryPi5
> board. Reverting it on top of linux-next fixes the issue. Here is a boot
> log:

Huh.

[...]

> arch_timer: cp15 timer running at 54.00MHz (hyp-virt).
> clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0xc743ce346, max_idle_ns: 440795203123 ns
> sched_clock: 56 bits at 54MHz, resolution 18ns, wraps every 4398046511102ns

The interrupt appears to be advertised in the DT, but doesn't seem to
fire. That's obviously not going to end well. My suspicion is that
either the interrupt isn't wired (that'd be hilariously abd), or is
left as Group-0 by the firmware (copy-paste from RPi4).

Can you try the following hack and let me know if the kernel shouts at
you?

Thanks,

	M.

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ec70c84e9f91d..d05791e6cc0db 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -213,6 +213,7 @@ static void gic_eoimode1_mask_irq(struct irq_data *d)
 static void gic_unmask_irq(struct irq_data *d)
 {
 	gic_poke_irq(d, GIC_DIST_ENABLE_SET);
+	WARN_ON(!gic_peek_irq(d, GIC_DIST_ENABLE_SET));
 }
 
 static void gic_eoi_irq(struct irq_data *d)

-- 
Without deviation from the norm, progress is not possible.



More information about the linux-arm-kernel mailing list