From nobody Sat Jun 13 23:44:24 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0548D298CA3; Sat, 13 Jun 2026 14:33:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781361195; cv=none; b=txN87RQ+IqGMloe3pfbYDi9dpMDyerMdFnaM1kiK+aDDAr8aLpN4Uim82Hbf9vlMCooloZ1Zd0JoRFzApHvbb4Z6piYlOI2U2LQUwqQ0WI0y3UGSl2B3GEUp/a2c9IPRc2UBHZgcjkcEgdd3UH8a8XIQUCjXz7jO9t86eYWpxnI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781361195; c=relaxed/simple; bh=df9VCxvPpjONPGW9oDIv6jlV4ncDaaT5iR0YDvnBd4A=; h=Date:From:To:Subject:Cc:In-Reply-To:References:MIME-Version: Message-ID:Content-Type; b=W/ACqExJKsxpAWKmzPwg+JeRAfQ5jDuBmC2YZ8B+bzmGYuIch13OojNvvKowPOVnsVJwXTXE6SS3dGKZEKJIY54scmiwrWoBlDN1J1zHvJwgltmrtwbkBPo3BGuiSARYsNhc06HMhMVSW1ihPz3n4worfznZZQ0asgfDLHtAqnA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=bHMvsn15; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=6/ed3sur; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="bHMvsn15"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="6/ed3sur" Date: Sat, 13 Jun 2026 14:33:09 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1781361191; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rTQ1rCItYt5dg2H3EH/SswyIx7U1OmuCfk9vsCf8zyw=; b=bHMvsn15hoQHmAzv8CWR91NB8/8w31k3Q5QUB+BSEbSrJ555WLJsY2KzsLjypX4cMZyixf PS+ntbOmywjKS6nyKgY7k6dg/2XryLd+xXuVaAGeSzwLeotVOsGJ/U1rq9anLWnecoUYmy zr45ITbgn5yK4/6C3PWdkwCWsTCxOJJGD6vIpK3lsD2IMbV81/JoxSM5WbHD6YXpYAT4j2 AnNKAaMrdyM7rj8ZUtqDRgJyAJzdlb4P+S7V6B1nlYTOEelXDSF0HXn44AS4XgFsTSS16V FwioeUglJ0bs03xvrRUGhkULSy2HvnltbXQke5OfBU6W86a60ITeQtw6aBsAuw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1781361191; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rTQ1rCItYt5dg2H3EH/SswyIx7U1OmuCfk9vsCf8zyw=; b=6/ed3surdc3wwzuuwcWVyAT5MEJGa2i8ycsEyN618GQsNBBzo01D464BRHyplgGCrQexEk yQiQGCnN4de18uDA== From: "tip-bot2 for Marc Zyngier" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: timers/clocksource] clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE Cc: Marc Zyngier , Daniel Lezcano , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20260523140242.586031-4-maz@kernel.org> References: <20260523140242.586031-4-maz@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <178136118991.1650852.3294850548787332246.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Precedence: bulk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The following commit has been merged into the timers/clocksource branch of = tip: Commit-ID: d87773de9efe1df6fe2ba379926f9df92f1a5913 Gitweb: https://git.kernel.org/tip/d87773de9efe1df6fe2ba379926f9df92= f1a5913 Author: Marc Zyngier AuthorDate: Sat, 23 May 2026 15:02:28 +01:00 Committer: Daniel Lezcano CommitterDate: Wed, 03 Jun 2026 09:53:21 +02:00 clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when runni= ng VHE 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 Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20260523140242.586031-4-maz@kernel.org --- drivers/clocksource/arm_arch_timer.c | 55 ++++++++++++++++----------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm= _arch_timer.c index 90aeff4..4adf756 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_devic= e *clk) clk->irq =3D 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 =3D arch_timer_shutdown_virt; clk->set_state_oneshot_stopped =3D arch_timer_shutdown_virt; sne =3D 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 =3D=3D ARCH_TIMER_VIRT_PPI) ? "virt" : "phys"); + arch_timer_ppi_names[arch_timer_uses_ppi]); } =20 u32 arch_timer_get_rate(void) @@ -912,7 +913,8 @@ static void __init arch_counter_register(void) int width; =20 if ((IS_ENABLED(CONFIG_ARM64) && !is_hyp_mode_available()) || - arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI) { + arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI || + arch_timer_uses_ppi =3D=3D ARCH_TIMER_HYP_VIRT_PPI) { if (arch_timer_counter_has_wa()) { rd =3D arch_counter_get_cntvct_stable; scr =3D raw_counter_get_cntvct_stable; @@ -1023,6 +1025,7 @@ static int __init arch_timer_register(void) ppi =3D arch_timer_ppi[arch_timer_uses_ppi]; switch (arch_timer_uses_ppi) { case ARCH_TIMER_VIRT_PPI: + case ARCH_TIMER_HYP_VIRT_PPI: err =3D request_percpu_irq(ppi, arch_timer_handler_virt, "arch_timer", arch_timer_evt); break; @@ -1090,25 +1093,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(FW_BUG "VHE-capable CPU without EL2 virtual timer interrupt= \n"); return ARCH_TIMER_HYP_PPI; + } =20 if (!is_hyp_mode_available() && arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) return ARCH_TIMER_VIRT_PPI; @@ -1200,14 +1212,9 @@ static int __init arch_timer_acpi_init(struct acpi_t= able_header *table) if (ret) return ret; =20 - arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =3D - acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI); - - arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =3D - acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI); - - arch_timer_ppi[ARCH_TIMER_HYP_PPI] =3D - acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI); + /* The GTDT parser can't be bothered with the secure timer */ + for (int i =3D ARCH_TIMER_PHYS_NONSECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PP= I; i++) + arch_timer_ppi[i] =3D acpi_gtdt_map_ppi(i); =20 arch_timer_populate_kvm_info(); =20 @@ -1253,10 +1260,14 @@ int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct= timespec64 *ts, if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)) return -EOPNOTSUPP; =20 - if (arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI) + switch (arch_timer_uses_ppi) { + case ARCH_TIMER_VIRT_PPI: + case ARCH_TIMER_HYP_VIRT_PPI: ptp_counter =3D KVM_PTP_VIRT_COUNTER; - else + break; + default: ptp_counter =3D KVM_PTP_PHYS_COUNTER; + } =20 arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, ptp_counter, &hvc_res);