Skip to content

Commit aa83c45

Browse files
Peter ZijlstraKAGA-KOKO
authored andcommitted
x86/tsc: Introduce early tsc clocksource
Without TSC_KNOWN_FREQ the TSC clocksource is registered so late that the kernel first switches to the HPET. Using HPET on large CPU count machines is undesirable. Therefore register a tsc-early clocksource using the preliminary tsc_khz from quick calibration. Then when the final TSC calibration is done, it can switch to the tuned frequency. The only notably problem is that the real tsc clocksource must be marked with CLOCK_SOURCE_VALID_FOR_HRES, otherwise it will not be selected when unregistering tsc-early. tsc-early cannot be left registered, because then the clocksource code would fall back to it when we tsc clocksource is marked unstable later. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: [email protected] Cc: Len Brown <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 6d671e1 commit aa83c45

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

arch/x86/kernel/tsc.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,8 +1006,6 @@ static void __init detect_art(void)
10061006

10071007
/* clocksource code */
10081008

1009-
static struct clocksource clocksource_tsc;
1010-
10111009
static void tsc_resume(struct clocksource *cs)
10121010
{
10131011
tsc_verify_tsc_adjust(true);
@@ -1058,12 +1056,31 @@ static void tsc_cs_tick_stable(struct clocksource *cs)
10581056
/*
10591057
* .mask MUST be CLOCKSOURCE_MASK(64). See comment above read_tsc()
10601058
*/
1059+
static struct clocksource clocksource_tsc_early = {
1060+
.name = "tsc-early",
1061+
.rating = 299,
1062+
.read = read_tsc,
1063+
.mask = CLOCKSOURCE_MASK(64),
1064+
.flags = CLOCK_SOURCE_IS_CONTINUOUS |
1065+
CLOCK_SOURCE_MUST_VERIFY,
1066+
.archdata = { .vclock_mode = VCLOCK_TSC },
1067+
.resume = tsc_resume,
1068+
.mark_unstable = tsc_cs_mark_unstable,
1069+
.tick_stable = tsc_cs_tick_stable,
1070+
};
1071+
1072+
/*
1073+
* Must mark VALID_FOR_HRES early such that when we unregister tsc_early
1074+
* this one will immediately take over. We will only register if TSC has
1075+
* been found good.
1076+
*/
10611077
static struct clocksource clocksource_tsc = {
10621078
.name = "tsc",
10631079
.rating = 300,
10641080
.read = read_tsc,
10651081
.mask = CLOCKSOURCE_MASK(64),
10661082
.flags = CLOCK_SOURCE_IS_CONTINUOUS |
1083+
CLOCK_SOURCE_VALID_FOR_HRES |
10671084
CLOCK_SOURCE_MUST_VERIFY,
10681085
.archdata = { .vclock_mode = VCLOCK_TSC },
10691086
.resume = tsc_resume,
@@ -1187,8 +1204,8 @@ static void tsc_refine_calibration_work(struct work_struct *work)
11871204
int cpu;
11881205

11891206
/* Don't bother refining TSC on unstable systems */
1190-
if (check_tsc_unstable())
1191-
goto out;
1207+
if (tsc_unstable)
1208+
return;
11921209

11931210
/*
11941211
* Since the work is started early in boot, we may be
@@ -1240,9 +1257,13 @@ static void tsc_refine_calibration_work(struct work_struct *work)
12401257
set_cyc2ns_scale(tsc_khz, cpu, tsc_stop);
12411258

12421259
out:
1260+
if (tsc_unstable)
1261+
return;
1262+
12431263
if (boot_cpu_has(X86_FEATURE_ART))
12441264
art_related_clocksource = &clocksource_tsc;
12451265
clocksource_register_khz(&clocksource_tsc, tsc_khz);
1266+
clocksource_unregister(&clocksource_tsc_early);
12461267
}
12471268

12481269

@@ -1251,13 +1272,11 @@ static int __init init_tsc_clocksource(void)
12511272
if (!boot_cpu_has(X86_FEATURE_TSC) || tsc_disabled > 0 || !tsc_khz)
12521273
return 0;
12531274

1275+
if (check_tsc_unstable())
1276+
return 0;
1277+
12541278
if (tsc_clocksource_reliable)
12551279
clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
1256-
/* lower the rating if we already know its unstable: */
1257-
if (check_tsc_unstable()) {
1258-
clocksource_tsc.rating = 0;
1259-
clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
1260-
}
12611280

12621281
if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
12631282
clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
@@ -1270,6 +1289,7 @@ static int __init init_tsc_clocksource(void)
12701289
if (boot_cpu_has(X86_FEATURE_ART))
12711290
art_related_clocksource = &clocksource_tsc;
12721291
clocksource_register_khz(&clocksource_tsc, tsc_khz);
1292+
clocksource_unregister(&clocksource_tsc_early);
12731293
return 0;
12741294
}
12751295

@@ -1374,9 +1394,12 @@ void __init tsc_init(void)
13741394

13751395
check_system_tsc_reliable();
13761396

1377-
if (unsynchronized_tsc())
1397+
if (unsynchronized_tsc()) {
13781398
mark_tsc_unstable("TSCs unsynchronized");
1399+
return;
1400+
}
13791401

1402+
clocksource_register_khz(&clocksource_tsc_early, tsc_khz);
13801403
detect_art();
13811404
}
13821405

0 commit comments

Comments
 (0)