From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 4A2393A8FE1 for ; Tue, 24 Feb 2026 16:36:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771951013; cv=none; b=UutGoy5rqZG2hDaE7aTzJ/6QNJVJH7OC8IpxxyjDSJo8ylxOPMNIIQ3LTF9cHaa29H1JKTgTu2Jr/RaxyWjWDqRuP9mMD4vFR9f3HLLRtfZ1D5/w46l0KPe9QEHJHuA2uYh9QlETDyDgZVMhGSHXEbS1U+wmqEKvphQpPaL3pb8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771951013; c=relaxed/simple; bh=T0PgGw45XKbEq/105Qxsyx83s7PyOv0Wxw6JUQ6IIp0=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=oQ1cHnqD5lcVDT+ozL5yKhyyidLmD44v4foj1SjVfucCfkHq1wbq764fwrJ88DSkVcEtmJi98lReJcLIiGf2DqEpzbOAI0QBrIliWNhvkZTzfpTxAt0iQhoPtP+tIkPRp8AI5Zbdwit0G8O6Lc9hecKM89OHylv4wPQC/vahPzw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RlG5jjMR; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RlG5jjMR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 463B6C19425; Tue, 24 Feb 2026 16:36:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1771951012; bh=T0PgGw45XKbEq/105Qxsyx83s7PyOv0Wxw6JUQ6IIp0=; h=Date:From:To:Cc:Subject:References:From; b=RlG5jjMRoO0mNQq5HQuGmUvHAaWzOMa40vhBt7kZQylP7hW28LiAzqYhdEZTRK256 kvY9o1lPoWytZTyjXpheub0OnvAJkxq5aEEodNO/Ggl0WpolP0CaNEIPRF4UCn/rtn MZSDybeTMP5VSJuUFk9K+aeoG8lmhXSiRY1SUYitMFKRTU5gueTNDIR1eXIT8dwVq4 qo8kAOkieUv1F7oFc2EkwLqLTPRwcfyCB2VtFGVW+muN+DZCe3sicJL+Vi8n772MUO MQ1ht+7dK9KdSgjeEMyRiOikJaODXE5CmmdGnby0riqPKo6TMJwvFZn0d1U9XoyFfR IQjEozCImAIsg== Date: Tue, 24 Feb 2026 17:36:49 +0100 Message-ID: <20260224163430.076565985@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: Anna-Maria Behnsen , John Stultz , Stephen Boyd , Daniel Lezcano , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , x86@kernel.org, Peter Zijlstra , Frederic Weisbecker , Eric Dumazet Subject: [patch 20/48] x86/apic: Enable TSC coupled programming mode References: <20260224163022.795809588@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 The TSC deadline timer is directly coupled to the TSC and setting the next deadline is tedious as the clockevents core code converts the CLOCK_MONOTONIC based absolute expiry time to a relative expiry by reading the current time from the TSC. It converts that delta to cycles and hands the result to lapic_next_deadline(), which then has read to the TSC and add the delta to program the timer. The core code now supports coupled clock event devices and can provide the expiry time in TSC cycles directly without reading the TSC at all. This obviouly works only when the TSC is the current clocksource, but that's the default for all modern CPUs which implement the TSC deadline timer. If the TSC is not the current clocksource (e.g. early boot) then the core code falls back to the relative set_next_event() callback as before. Signed-off-by: Thomas Gleixner Cc: x86@kernel.org --- arch/x86/Kconfig | 1 + arch/x86/include/asm/clock_inlined.h | 8 ++++++++ arch/x86/kernel/apic/apic.c | 12 ++++++------ arch/x86/kernel/tsc.c | 3 ++- 4 files changed, 17 insertions(+), 7 deletions(-) --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -164,6 +164,7 @@ config X86 select EDAC_SUPPORT select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) select GENERIC_CLOCKEVENTS_BROADCAST_IDLE if GENERIC_CLOCKEVENTS_BROADCAST + select GENERIC_CLOCKEVENTS_COUPLED_INLINE if X86_64 select GENERIC_CLOCKEVENTS_MIN_ADJUST select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE --- a/arch/x86/include/asm/clock_inlined.h +++ b/arch/x86/include/asm/clock_inlined.h @@ -11,4 +11,12 @@ static __always_inline u64 arch_inlined_ return (u64)rdtsc_ordered(); } +struct clock_event_device; + +static __always_inline void +arch_inlined_clockevent_set_next_coupled(u64 cycles, struct clock_event_device *evt) +{ + native_wrmsrq(MSR_IA32_TSC_DEADLINE, cycles); +} + #endif --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -591,14 +591,14 @@ static void setup_APIC_timer(void) if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { levt->name = "lapic-deadline"; - levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_DUMMY); + levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_DUMMY); + levt->features |= CLOCK_EVT_FEAT_CLOCKSOURCE_COUPLED; + levt->cs_id = CSID_X86_TSC; levt->set_next_event = lapic_next_deadline; - clockevents_config_and_register(levt, - tsc_khz * (1000 / TSC_DIVISOR), - 0xF, ~0UL); - } else + clockevents_config_and_register(levt, tsc_khz * (1000 / TSC_DIVISOR), 0xF, ~0UL); + } else { clockevents_register_device(levt); + } apic_update_vector(smp_processor_id(), LOCAL_TIMER_VECTOR, true); } --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -1203,7 +1203,8 @@ static struct clocksource clocksource_ts CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_CAN_INLINE_READ | CLOCK_SOURCE_MUST_VERIFY | - CLOCK_SOURCE_VERIFY_PERCPU, + CLOCK_SOURCE_VERIFY_PERCPU | + CLOCK_SOURCE_HAS_COUPLED_CLOCK_EVENT, .id = CSID_X86_TSC, .vdso_clock_mode = VDSO_CLOCKMODE_TSC, .enable = tsc_cs_enable,