clocksource: Limit the number of watchdogged clocksources
When TSC is deemed trustworthy, the clocksource watchdog will verify
other clocksources against it. @@@ Why limit it? Needed from Waiman.
Maybe overhead and disturbance of additional checks? @@@
Therefore, supply a new tsc_watchdogged kernel boot parameter that
limits the number of clocksources that will be verified against TSC.
This parameter defaults to INT_MAX. A value of zero prevents any
verification.
Link: https://lore.kernel.org/all/a82092f5-abc8-584f-b2ba-f06c82ffbe7d@redhat.com/
Reported-by: Waiman Long <longman@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Feng Tang <feng.tang@intel.com>
Cc: Waiman Long <longman@redhat.com
Cc: <x86@kernel.org>
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68c597e..0e304e4 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6345,6 +6345,12 @@
with CPUID.16h support and partial CPUID.15h support.
Format: <unsigned int>
+ tsc_watchdogged= [X86]
+ Specify the limit on the number of clocksources
+ that will be verified against TSC in cases where
+ the TSC is deemed trustworthy. Defaults to
+ INT_MAX. Specify zero to avoid verification.
+
tsx= [X86] Control Transactional Synchronization
Extensions (TSX) feature in Intel processors that
support TSX control.
diff --git a/arch/x86/include/asm/time.h b/arch/x86/include/asm/time.h
index a53961c..0fa15c4 100644
--- a/arch/x86/include/asm/time.h
+++ b/arch/x86/include/asm/time.h
@@ -8,7 +8,7 @@
extern void hpet_time_init(void);
extern void time_init(void);
extern bool pit_timer_init(void);
-extern bool tsc_clocksource_watchdog_disabled(void);
+extern void tsc_clocksource_watchdog_disabled(struct clocksource *csp);
extern struct clock_event_device *global_clock_event;
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index c8eb1ac..cf28b0a 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -1091,8 +1091,7 @@ int __init hpet_enable(void)
if (!hpet_counting())
goto out_nohpet;
- if (tsc_clocksource_watchdog_disabled())
- clocksource_hpet.flags |= CLOCK_SOURCE_MUST_VERIFY;
+ tsc_clocksource_watchdog_disabled(&clocksource_hpet);
clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq);
if (id & HPET_ID_LEGSUP) {
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 924e877..6a1def7 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -53,6 +53,9 @@ static u32 art_to_tsc_denominator;
static u64 art_to_tsc_offset;
struct clocksource *art_related_clocksource;
+static int max_tsc_watchdogged = INT_MAX;
+static atomic_t cur_tsc_watchdogged;
+
struct cyc2ns {
struct cyc2ns_data data[2]; /* 0 + 2*16 = 32 */
seqcount_latch_t seq; /* 32 + 4 = 36 */
@@ -308,6 +311,14 @@ static int __init tsc_setup(char *str)
__setup("tsc=", tsc_setup);
+static int __init tsc_watchdogged_setup(char *str)
+{
+ max_tsc_watchdogged = simple_strtol(str, NULL, 0);
+ return 1;
+}
+
+__setup("tsc_watchdogged=", tsc_watchdogged_setup);
+
#define MAX_RETRIES 5
#define TSC_DEFAULT_THRESHOLD 0x20000
@@ -1186,9 +1197,18 @@ static void __init tsc_disable_clocksource_watchdog(void)
clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
}
-bool tsc_clocksource_watchdog_disabled(void)
+/*
+ * If the TSC is judged trustworthy and the limit on the number of
+ * to-be-watchdogged clocksources has not been exceeded, place the specified
+ * clocksource into must-verify state.
+ */
+void tsc_clocksource_watchdog_disabled(struct clocksource *csp)
{
- return !(clocksource_tsc.flags & CLOCK_SOURCE_MUST_VERIFY);
+ if (clocksource_tsc.flags & CLOCK_SOURCE_MUST_VERIFY ||
+ atomic_inc_return(&cur_tsc_watchdogged) > max_tsc_watchdogged)
+ return;
+ pr_info("clocksource: '%s' will be checked by clocksource watchdog.\n", csp->name);
+ csp->flags |= CLOCK_SOURCE_MUST_VERIFY;
}
static void __init check_system_tsc_reliable(void)
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 82338773..8562f59 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -211,8 +211,7 @@ static int __init init_acpi_pm_clocksource(void)
return -ENODEV;
}
- if (tsc_clocksource_watchdog_disabled())
- clocksource_acpi_pm.flags |= CLOCK_SOURCE_MUST_VERIFY;
+ tsc_clocksource_watchdog_disabled(&clocksource_acpi_pm);
return clocksource_register_hz(&clocksource_acpi_pm, PMTMR_TICKS_PER_SEC);
}