Linux ACPI
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: linux-arm-kernel@lists.infradead.org, linux-acpi@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
Cc: "Lorenzo Pieralisi" <lpieralisi@kernel.org>,
	"Hanjun Guo" <guohanjun@huawei.com>,
	"Sudeep Holla" <sudeep.holla@kernel.org>,
	"Catalin Marinas" <catalin.marinas@arm.com>,
	"Will Deacon" <will@kernel.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	"Mark Rutland" <mark.rutland@arm.com>,
	"Daniel Lezcano" <daniel.lezcano@kernel.org>,
	"Thomas Gleixner" <tglx@kernel.org>,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Chen-Yu Tsai" <wens@kernel.org>,
	"Jernej Skrabec" <jernej.skrabec@gmail.com>,
	"Samuel Holland" <samuel@sholland.org>,
	"Neil Armstrong" <neil.armstrong@linaro.org>,
	"Kevin Hilman" <khilman@baylibre.com>,
	"Jerome Brunet" <jbrunet@baylibre.com>,
	"Martin Blumenstingl" <martin.blumenstingl@googlemail.com>,
	"Ge Gordon" <gordon.ge@bst.ai>,
	"BST Linux Kernel Upstream Group" <bst-upstream@bstai.top>,
	"Jesper Nilsson" <jesper.nilsson@axis.com>,
	"Lars Persson" <lars.persson@axis.com>,
	"Alim Akhtar" <alim.akhtar@samsung.com>,
	"Ivaylo Ivanov" <ivo.ivanov.ivanov1@gmail.com>,
	"Frank Li" <Frank.Li@nxp.com>,
	"Sascha Hauer" <s.hauer@pengutronix.de>,
	"Pengutronix Kernel Team" <kernel@pengutronix.de>,
	"Fabio Estevam" <festevam@gmail.com>,
	"Dinh Nguyen" <dinguyen@kernel.org>,
	"Matthias Brugger" <matthias.bgg@gmail.com>,
	"AngeloGioacchino Del Regno"
	<angelogioacchino.delregno@collabora.com>,
	"Thierry Reding" <thierry.reding@kernel.org>,
	"Jonathan Hunter" <jonathanh@nvidia.com>,
	"Bjorn Andersson" <andersson@kernel.org>,
	"Konrad Dybcio" <konradybcio@kernel.org>,
	"Andreas Färber" <afaerber@suse.de>,
	"Heiko Stuebner" <heiko@sntech.de>,
	"Shawn Lin" <shawn.lin@rock-chips.com>,
	"Orson Zhai" <orsonzhai@gmail.com>,
	"Baolin Wang" <baolin.wang@linux.alibaba.com>,
	"Michal Simek" <michal.simek@amd.com>
Subject: [PATCH 02/16] clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE
Date: Thu,  7 May 2026 13:55:30 +0100	[thread overview]
Message-ID: <20260507125544.2903406-3-maz@kernel.org> (raw)
In-Reply-To: <20260507125544.2903406-1-maz@kernel.org>

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@kernel.org>
---
 drivers/clocksource/arm_arch_timer.c | 44 ++++++++++++++++------------
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 90aeff44a2764..eaf276a9b9d28 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -688,6 +688,7 @@ static void __arch_timer_setup(struct clock_event_device *clk)
 	clk->irq = arch_timer_ppi[arch_timer_uses_ppi];
 	switch (arch_timer_uses_ppi) {
 	case ARCH_TIMER_VIRT_PPI:
+	case ARCH_TIMER_HYP_VIRT_PPI:
 		clk->set_state_shutdown = arch_timer_shutdown_virt;
 		clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
 		sne = erratum_handler(set_next_event_virt);
@@ -879,7 +880,7 @@ static void __init arch_timer_banner(void)
 	pr_info("cp15 timer running at %lu.%02luMHz (%s).\n",
 		(unsigned long)arch_timer_rate / 1000000,
 		(unsigned long)(arch_timer_rate / 10000) % 100,
-		(arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys");
+		arch_timer_ppi_names[arch_timer_uses_ppi]);
 }
 
 u32 arch_timer_get_rate(void)
@@ -1023,6 +1024,7 @@ static int __init arch_timer_register(void)
 	ppi = arch_timer_ppi[arch_timer_uses_ppi];
 	switch (arch_timer_uses_ppi) {
 	case ARCH_TIMER_VIRT_PPI:
+	case ARCH_TIMER_HYP_VIRT_PPI:
 		err = request_percpu_irq(ppi, arch_timer_handler_virt,
 					 "arch_timer", arch_timer_evt);
 		break;
@@ -1090,25 +1092,34 @@ static int __init arch_timer_common_init(void)
 /**
  * arch_timer_select_ppi() - Select suitable PPI for the current system.
  *
- * If HYP mode is available, we know that the physical timer
- * has been configured to be accessible from PL1. Use it, so
- * that a guest can use the virtual timer instead.
+ * On AArch32, if HYP mode is available, we know that the physical
+ * timer has been configured to be accessible from PL1. Use it, so
+ * that a guest can use the virtual timer instead (though KVM host
+ * support has long been removed).
  *
- * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
- * accesses to CNTP_*_EL1 registers are silently redirected to
- * their CNTHP_*_EL2 counterparts, and use a different PPI
- * number.
+ * On ARMv8.1 with FEAT_VHE, the kernel runs in EL2. Accesses to
+ * CNTV_*_EL1 registers are silently redirected to their CNTHV_*_EL2
+ * counterparts, and the timer uses a different PPI number. Similar
+ * thing happen when using the EL2 physical timer. Note that a bunch
+ * of DTs out there omit the virtual EL2 timer, so fallback gracefully
+ * on the physical timer.
+ *
+ * Without VHE, if no interrupt provided for virtual timer, we'll have
+ * to stick to the physical timer. It'd better be accessible...
  *
- * If no interrupt provided for virtual timer, we'll have to
- * stick to the physical timer. It'd better be accessible...
  * For arm64 we never use the secure interrupt.
  *
  * Return: a suitable PPI type for the current system.
  */
 static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
 {
-	if (is_kernel_in_hyp_mode())
+	if (is_kernel_in_hyp_mode()) {
+		if (arch_timer_ppi[ARCH_TIMER_HYP_VIRT_PPI])
+			return ARCH_TIMER_HYP_VIRT_PPI;
+
+		pr_warn_once("VHE without EL2 virtual timer interrupt, broken firmware\n");
 		return ARCH_TIMER_HYP_PPI;
+	}
 
 	if (!is_hyp_mode_available() && arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
 		return ARCH_TIMER_VIRT_PPI;
@@ -1200,14 +1211,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 	if (ret)
 		return ret;
 
-	arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
-		acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI);
-
-	arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
-		acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI);
-
-	arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
-		acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI);
+	/* The GTDT parser can't be bothered with the secure timer */
+	for (int i = ARCH_TIMER_PHYS_NONSECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
+		arch_timer_ppi[i] = acpi_gtdt_map_ppi(i);
 
 	arch_timer_populate_kvm_info();
 
-- 
2.47.3


  parent reply	other threads:[~2026-05-07 12:55 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-07 12:55 [PATCH 00/16] arm64: Use EL2 virtual timer when running VHE Marc Zyngier
2026-05-07 12:55 ` [PATCH 01/16] ACPI: GTDT: Parse information related to the EL2 virtual timer Marc Zyngier
2026-05-07 12:55 ` Marc Zyngier [this message]
2026-05-08 14:15   ` [PATCH 02/16] clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE Marc Zyngier
2026-05-07 12:55 ` [PATCH 03/16] dt-bindings: timer: arm,arch_timer: Fix requirements for interrupt description Marc Zyngier
2026-05-07 12:55 ` [PATCH 04/16] arm64: dts: allwinner: Add EL2 virtual timer interrupt Marc Zyngier
2026-05-07 12:55 ` [PATCH 05/16] arm64: dts: amlogic: " Marc Zyngier
2026-05-07 15:44   ` Neil Armstrong
2026-05-07 12:55 ` [PATCH 06/16] arm64: dts: bst: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 07/16] arm64: dts: exynos: " Marc Zyngier
2026-05-12  7:47   ` Jesper Nilsson
2026-05-07 12:55 ` [PATCH 08/16] arm64: dts: freescale: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 09/16] arm64: dts: intel: " Marc Zyngier
2026-05-11 19:00   ` Dinh Nguyen
2026-05-07 12:55 ` [PATCH 10/16] arm64: dts: mediatek: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 11/16] arm64: dts: nvidia: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 12/16] arm64: dts: qcom: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 13/16] arm64: dts: realtek: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 14/16] arm64: dts: rockchip: " Marc Zyngier
2026-05-07 15:33   ` Heiko Stuebner
2026-05-07 15:57     ` Marc Zyngier
2026-05-07 12:55 ` [PATCH 15/16] arm64: dts: sprd: " Marc Zyngier
2026-05-07 12:55 ` [PATCH 16/16] arm64: dts: xilinx: " Marc Zyngier
2026-05-11  9:19   ` Michal Simek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260507125544.2903406-3-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=Frank.Li@nxp.com \
    --cc=afaerber@suse.de \
    --cc=alim.akhtar@samsung.com \
    --cc=andersson@kernel.org \
    --cc=angelogioacchino.delregno@collabora.com \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=bst-upstream@bstai.top \
    --cc=catalin.marinas@arm.com \
    --cc=conor+dt@kernel.org \
    --cc=daniel.lezcano@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dinguyen@kernel.org \
    --cc=festevam@gmail.com \
    --cc=gordon.ge@bst.ai \
    --cc=guohanjun@huawei.com \
    --cc=heiko@sntech.de \
    --cc=ivo.ivanov.ivanov1@gmail.com \
    --cc=jbrunet@baylibre.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=jesper.nilsson@axis.com \
    --cc=jonathanh@nvidia.com \
    --cc=kernel@pengutronix.de \
    --cc=khilman@baylibre.com \
    --cc=konradybcio@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=lars.persson@axis.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lpieralisi@kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=martin.blumenstingl@googlemail.com \
    --cc=matthias.bgg@gmail.com \
    --cc=michal.simek@amd.com \
    --cc=neil.armstrong@linaro.org \
    --cc=orsonzhai@gmail.com \
    --cc=rafael@kernel.org \
    --cc=robh@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=samuel@sholland.org \
    --cc=shawn.lin@rock-chips.com \
    --cc=sudeep.holla@kernel.org \
    --cc=tglx@kernel.org \
    --cc=thierry.reding@kernel.org \
    --cc=wens@kernel.org \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox