Skip to content

Commit f9677e0

Browse files
christopher-s-halljohnstultz-work
authored andcommitted
x86/tsc: Always Running Timer (ART) correlated clocksource
On modern Intel systems TSC is derived from the new Always Running Timer (ART). ART can be captured simultaneous to the capture of audio and network device clocks, allowing a correlation between timebases to be constructed. Upon capture, the driver converts the captured ART value to the appropriate system clock using the correlated clocksource mechanism. On systems that support ART a new CPUID leaf (0x15) returns parameters “m” and “n” such that: TSC_value = (ART_value * m) / n + k [n >= 1] [k is an offset that can adjusted by a privileged agent. The IA32_TSC_ADJUST MSR is an example of an interface to adjust k. See 17.14.4 of the Intel SDM for more details] Cc: Prarit Bhargava <prarit@redhat.com> Cc: Richard Cochran <richardcochran@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: kevin.b.stanton@intel.com Cc: kevin.j.clarke@intel.com Cc: hpa@zytor.com Cc: jeffrey.t.kirsher@intel.com Cc: netdev@vger.kernel.org Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Christopher S. Hall <christopher.s.hall@intel.com> [jstultz: Tweaked to fix build issue, also reworked math for 64bit division on 32bit systems, as well as !CONFIG_CPU_FREQ build fixes] Signed-off-by: John Stultz <john.stultz@linaro.org>
1 parent 2c756fe commit f9677e0

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

arch/x86/include/asm/cpufeature.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */
8686
#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */
8787
#define X86_FEATURE_UP ( 3*32+ 9) /* smp kernel running on up */
88-
/* free, was #define X86_FEATURE_FXSAVE_LEAK ( 3*32+10) * "" FXSAVE leaks FOP/FIP/FOP */
88+
#define X86_FEATURE_ART (3*32+10) /* Platform has always running timer (ART) */
8989
#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */
9090
#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */
9191
#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */

arch/x86/include/asm/tsc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ static inline cycles_t get_cycles(void)
2929
return rdtsc();
3030
}
3131

32+
extern struct system_counterval_t convert_art_to_tsc(cycle_t art);
33+
3234
extern void tsc_init(void);
3335
extern void mark_tsc_unstable(char *reason);
3436
extern int unsynchronized_tsc(void);

arch/x86/kernel/tsc.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ static DEFINE_STATIC_KEY_FALSE(__use_tsc);
4343

4444
int tsc_clocksource_reliable;
4545

46+
static u32 art_to_tsc_numerator;
47+
static u32 art_to_tsc_denominator;
48+
static u64 art_to_tsc_offset;
49+
struct clocksource *art_related_clocksource;
50+
4651
/*
4752
* Use a ring-buffer like data structure, where a writer advances the head by
4853
* writing a new data entry and a reader advances the tail when it observes a
@@ -964,6 +969,37 @@ core_initcall(cpufreq_tsc);
964969

965970
#endif /* CONFIG_CPU_FREQ */
966971

972+
#define ART_CPUID_LEAF (0x15)
973+
#define ART_MIN_DENOMINATOR (1)
974+
975+
976+
/*
977+
* If ART is present detect the numerator:denominator to convert to TSC
978+
*/
979+
static void detect_art(void)
980+
{
981+
unsigned int unused[2];
982+
983+
if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
984+
return;
985+
986+
cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
987+
&art_to_tsc_numerator, unused, unused+1);
988+
989+
/* Don't enable ART in a VM, non-stop TSC required */
990+
if (boot_cpu_has(X86_FEATURE_HYPERVISOR) ||
991+
!boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
992+
art_to_tsc_denominator < ART_MIN_DENOMINATOR)
993+
return;
994+
995+
if (rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset))
996+
return;
997+
998+
/* Make this sticky over multiple CPU init calls */
999+
setup_force_cpu_cap(X86_FEATURE_ART);
1000+
}
1001+
1002+
9671003
/* clocksource code */
9681004

9691005
static struct clocksource clocksource_tsc;
@@ -1071,6 +1107,25 @@ int unsynchronized_tsc(void)
10711107
return 0;
10721108
}
10731109

1110+
/*
1111+
* Convert ART to TSC given numerator/denominator found in detect_art()
1112+
*/
1113+
struct system_counterval_t convert_art_to_tsc(cycle_t art)
1114+
{
1115+
u64 tmp, res, rem;
1116+
1117+
rem = do_div(art, art_to_tsc_denominator);
1118+
1119+
res = art * art_to_tsc_numerator;
1120+
tmp = rem * art_to_tsc_numerator;
1121+
1122+
do_div(tmp, art_to_tsc_denominator);
1123+
res += tmp + art_to_tsc_offset;
1124+
1125+
return (struct system_counterval_t) {.cs = art_related_clocksource,
1126+
.cycles = res};
1127+
}
1128+
EXPORT_SYMBOL(convert_art_to_tsc);
10741129

10751130
static void tsc_refine_calibration_work(struct work_struct *work);
10761131
static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
@@ -1142,6 +1197,8 @@ static void tsc_refine_calibration_work(struct work_struct *work)
11421197
(unsigned long)tsc_khz % 1000);
11431198

11441199
out:
1200+
if (boot_cpu_has(X86_FEATURE_ART))
1201+
art_related_clocksource = &clocksource_tsc;
11451202
clocksource_register_khz(&clocksource_tsc, tsc_khz);
11461203
}
11471204

@@ -1235,6 +1292,8 @@ void __init tsc_init(void)
12351292
mark_tsc_unstable("TSCs unsynchronized");
12361293

12371294
check_system_tsc_reliable();
1295+
1296+
detect_art();
12381297
}
12391298

12401299
#ifdef CONFIG_SMP

0 commit comments

Comments
 (0)