Commit f246ec34 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Peter Zijlstra
Browse files

x86/apic: Enable TSC coupled programming mode



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: default avatarThomas Gleixner <tglx@kernel.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163430.076565985@kernel.org
parent 89f951a1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -11,4 +11,12 @@ static __always_inline u64 arch_inlined_clocksource_read(struct clocksource *cs)
	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
+6 −6
Original line number Diff line number Diff line
@@ -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);
}
+2 −1
Original line number Diff line number Diff line
@@ -1203,7 +1203,8 @@ static struct clocksource clocksource_tsc = {
				  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,