[RFC PATCH v5 16/16] x86/tsc: Switch to perf-based hardlockup detector if TSC become unstable

From: Ricardo Neri
Date: Tue May 04 2021 - 15:08:11 EST


The HPET-based hardlockup detector relies on the TSC to determine if an
observed NMI interrupt was originated by HPET timer. Hence, this detector
can no longer be used with an unstable TSC.

In such case, permanently stop the HPET-based hardlockup detector and
start the perf-based detector.

Add stub versions of hardlockup_detector_switch_to_perf() to be used when
the HPET hardlockup detector and/or when CONFIG_HPET_TIMER are not
selected.

Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
Cc: Ashok Raj <ashok.raj@xxxxxxxxx>
Cc: Andi Kleen <andi.kleen@xxxxxxxxx>
Cc: Tony Luck <tony.luck@xxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Stephane Eranian <eranian@xxxxxxxxxx>
Cc: "Ravi V. Shankar" <ravi.v.shankar@xxxxxxxxx>
Cc: x86@xxxxxxxxxx
Suggested-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@xxxxxxxxxxxxxxx>
---
Changes since v4:
* Added a stub version of hardlockup_detector_switch_to_perf() for
!CONFIG_HPET_TIMER. (lkp)
* Reconfigure the whole lockup detector instead of unconditionally
starting the perf-based hardlockup detector.

Changes since v3:
* None

Changes since v2:
* Introduced this patch.

Changes since v1:
* N/A
---
arch/x86/include/asm/hpet.h | 3 +++
arch/x86/kernel/tsc.c | 2 ++
arch/x86/kernel/watchdog_hld.c | 6 ++++++
3 files changed, 11 insertions(+)

diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 1ff7436c1ce6..df11c7d4af44 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -148,18 +148,21 @@ extern int hardlockup_detector_hpet_init(void);
extern void hardlockup_detector_hpet_stop(void);
extern void hardlockup_detector_hpet_enable(unsigned int cpu);
extern void hardlockup_detector_hpet_disable(unsigned int cpu);
+extern void hardlockup_detector_switch_to_perf(void);
#else
static inline int hardlockup_detector_hpet_init(void)
{ return -ENODEV; }
static inline void hardlockup_detector_hpet_stop(void) {}
static inline void hardlockup_detector_hpet_enable(unsigned int cpu) {}
static inline void hardlockup_detector_hpet_disable(unsigned int cpu) {}
+static inline void hardlockup_detector_switch_to_perf(void) {}
#endif /* CONFIG_X86_HARDLOCKUP_DETECTOR_HPET */

#else /* CONFIG_HPET_TIMER */

static inline int hpet_enable(void) { return 0; }
static inline int is_hpet_enabled(void) { return 0; }
+static inline void hardlockup_detector_switch_to_perf(void) {}
#define hpet_readl(a) 0
#define default_setup_hpet_msi NULL

diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 57ec01192180..86ac13a83884 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -1174,6 +1174,8 @@ void mark_tsc_unstable(char *reason)

clocksource_mark_unstable(&clocksource_tsc_early);
clocksource_mark_unstable(&clocksource_tsc);
+
+ hardlockup_detector_switch_to_perf();
}

EXPORT_SYMBOL_GPL(mark_tsc_unstable);
diff --git a/arch/x86/kernel/watchdog_hld.c b/arch/x86/kernel/watchdog_hld.c
index 8947a7644421..a4415ad4aa85 100644
--- a/arch/x86/kernel/watchdog_hld.c
+++ b/arch/x86/kernel/watchdog_hld.c
@@ -78,3 +78,9 @@ void watchdog_nmi_stop(void)
if (detector_type == X86_HARDLOCKUP_DETECTOR_HPET)
hardlockup_detector_hpet_stop();
}
+
+void hardlockup_detector_switch_to_perf(void)
+{
+ detector_type = X86_HARDLOCKUP_DETECTOR_PERF;
+ lockup_detector_reconfigure();
+}
--
2.17.1