diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2016-12-15 05:44:28 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-01-14 05:29:43 -0500 |
commit | 12907fbb1a691807bb0420a27126e15934cb7954 (patch) | |
tree | 14ba1797a6e24d566513b368c59b13948130dc40 | |
parent | cb42c9a3ebbbb23448c3f9a25417fae6309b1a92 (diff) |
sched/clock, clocksource: Add optional cs::mark_unstable() method
PeterZ reported that we'd fail to mark the TSC unstable when the
clocksource watchdog finds it unsuitable.
Allow a clocksource to run a custom action when its being marked
unstable and hook up the TSC unstable code.
Reported-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/tsc.c | 11 | ||||
-rw-r--r-- | include/linux/clocksource.h | 3 | ||||
-rw-r--r-- | kernel/time/clocksource.c | 4 |
3 files changed, 18 insertions, 0 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index be3a49ee0356..c8174c815d83 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -1106,6 +1106,16 @@ static u64 read_tsc(struct clocksource *cs) | |||
1106 | return (u64)rdtsc_ordered(); | 1106 | return (u64)rdtsc_ordered(); |
1107 | } | 1107 | } |
1108 | 1108 | ||
1109 | static void tsc_cs_mark_unstable(struct clocksource *cs) | ||
1110 | { | ||
1111 | if (tsc_unstable) | ||
1112 | return; | ||
1113 | tsc_unstable = 1; | ||
1114 | clear_sched_clock_stable(); | ||
1115 | disable_sched_clock_irqtime(); | ||
1116 | pr_info("Marking TSC unstable due to clocksource watchdog\n"); | ||
1117 | } | ||
1118 | |||
1109 | /* | 1119 | /* |
1110 | * .mask MUST be CLOCKSOURCE_MASK(64). See comment above read_tsc() | 1120 | * .mask MUST be CLOCKSOURCE_MASK(64). See comment above read_tsc() |
1111 | */ | 1121 | */ |
@@ -1118,6 +1128,7 @@ static struct clocksource clocksource_tsc = { | |||
1118 | CLOCK_SOURCE_MUST_VERIFY, | 1128 | CLOCK_SOURCE_MUST_VERIFY, |
1119 | .archdata = { .vclock_mode = VCLOCK_TSC }, | 1129 | .archdata = { .vclock_mode = VCLOCK_TSC }, |
1120 | .resume = tsc_resume, | 1130 | .resume = tsc_resume, |
1131 | .mark_unstable = tsc_cs_mark_unstable, | ||
1121 | }; | 1132 | }; |
1122 | 1133 | ||
1123 | void mark_tsc_unstable(char *reason) | 1134 | void mark_tsc_unstable(char *reason) |
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index e315d04a2fd9..cfc75848a35d 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
@@ -62,6 +62,8 @@ struct module; | |||
62 | * @archdata: arch-specific data | 62 | * @archdata: arch-specific data |
63 | * @suspend: suspend function for the clocksource, if necessary | 63 | * @suspend: suspend function for the clocksource, if necessary |
64 | * @resume: resume function for the clocksource, if necessary | 64 | * @resume: resume function for the clocksource, if necessary |
65 | * @mark_unstable: Optional function to inform the clocksource driver that | ||
66 | * the watchdog marked the clocksource unstable | ||
65 | * @owner: module reference, must be set by clocksource in modules | 67 | * @owner: module reference, must be set by clocksource in modules |
66 | * | 68 | * |
67 | * Note: This struct is not used in hotpathes of the timekeeping code | 69 | * Note: This struct is not used in hotpathes of the timekeeping code |
@@ -93,6 +95,7 @@ struct clocksource { | |||
93 | unsigned long flags; | 95 | unsigned long flags; |
94 | void (*suspend)(struct clocksource *cs); | 96 | void (*suspend)(struct clocksource *cs); |
95 | void (*resume)(struct clocksource *cs); | 97 | void (*resume)(struct clocksource *cs); |
98 | void (*mark_unstable)(struct clocksource *cs); | ||
96 | 99 | ||
97 | /* private: */ | 100 | /* private: */ |
98 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG | 101 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 665985b0a89a..93621ae718d3 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -141,6 +141,10 @@ static void __clocksource_unstable(struct clocksource *cs) | |||
141 | { | 141 | { |
142 | cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); | 142 | cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); |
143 | cs->flags |= CLOCK_SOURCE_UNSTABLE; | 143 | cs->flags |= CLOCK_SOURCE_UNSTABLE; |
144 | |||
145 | if (cs->mark_unstable) | ||
146 | cs->mark_unstable(cs); | ||
147 | |||
144 | if (finished_booting) | 148 | if (finished_booting) |
145 | schedule_work(&watchdog_work); | 149 | schedule_work(&watchdog_work); |
146 | } | 150 | } |