aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/clock.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c
index 6bd6a6731b21..43c2bcc35761 100644
--- a/kernel/sched/clock.c
+++ b/kernel/sched/clock.c
@@ -77,35 +77,50 @@ __read_mostly int sched_clock_running;
77 77
78#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK 78#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
79static struct static_key __sched_clock_stable = STATIC_KEY_INIT; 79static struct static_key __sched_clock_stable = STATIC_KEY_INIT;
80static int __sched_clock_stable_early;
80 81
81int sched_clock_stable(void) 82int sched_clock_stable(void)
82{ 83{
83 if (static_key_false(&__sched_clock_stable)) 84 return static_key_false(&__sched_clock_stable);
84 return false;
85 return true;
86} 85}
87 86
88void set_sched_clock_stable(void) 87static void __set_sched_clock_stable(void)
89{ 88{
90 if (!sched_clock_stable()) 89 if (!sched_clock_stable())
91 static_key_slow_dec(&__sched_clock_stable); 90 static_key_slow_inc(&__sched_clock_stable);
91}
92
93void set_sched_clock_stable(void)
94{
95 __sched_clock_stable_early = 1;
96
97 smp_mb(); /* matches sched_clock_init() */
98
99 if (!sched_clock_running)
100 return;
101
102 __set_sched_clock_stable();
92} 103}
93 104
94static void __clear_sched_clock_stable(struct work_struct *work) 105static void __clear_sched_clock_stable(struct work_struct *work)
95{ 106{
96 /* XXX worry about clock continuity */ 107 /* XXX worry about clock continuity */
97 if (sched_clock_stable()) 108 if (sched_clock_stable())
98 static_key_slow_inc(&__sched_clock_stable); 109 static_key_slow_dec(&__sched_clock_stable);
99} 110}
100 111
101static DECLARE_WORK(sched_clock_work, __clear_sched_clock_stable); 112static DECLARE_WORK(sched_clock_work, __clear_sched_clock_stable);
102 113
103void clear_sched_clock_stable(void) 114void clear_sched_clock_stable(void)
104{ 115{
105 if (keventd_up()) 116 __sched_clock_stable_early = 0;
106 schedule_work(&sched_clock_work); 117
107 else 118 smp_mb(); /* matches sched_clock_init() */
108 __clear_sched_clock_stable(&sched_clock_work); 119
120 if (!sched_clock_running)
121 return;
122
123 schedule_work(&sched_clock_work);
109} 124}
110 125
111struct sched_clock_data { 126struct sched_clock_data {
@@ -140,6 +155,20 @@ void sched_clock_init(void)
140 } 155 }
141 156
142 sched_clock_running = 1; 157 sched_clock_running = 1;
158
159 /*
160 * Ensure that it is impossible to not do a static_key update.
161 *
162 * Either {set,clear}_sched_clock_stable() must see sched_clock_running
163 * and do the update, or we must see their __sched_clock_stable_early
164 * and do the update, or both.
165 */
166 smp_mb(); /* matches {set,clear}_sched_clock_stable() */
167
168 if (__sched_clock_stable_early)
169 __set_sched_clock_stable();
170 else
171 __clear_sched_clock_stable(NULL);
143} 172}
144 173
145/* 174/*
@@ -340,7 +369,7 @@ EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
340 */ 369 */
341u64 cpu_clock(int cpu) 370u64 cpu_clock(int cpu)
342{ 371{
343 if (static_key_false(&__sched_clock_stable)) 372 if (!sched_clock_stable())
344 return sched_clock_cpu(cpu); 373 return sched_clock_cpu(cpu);
345 374
346 return sched_clock(); 375 return sched_clock();
@@ -355,7 +384,7 @@ u64 cpu_clock(int cpu)
355 */ 384 */
356u64 local_clock(void) 385u64 local_clock(void)
357{ 386{
358 if (static_key_false(&__sched_clock_stable)) 387 if (!sched_clock_stable())
359 return sched_clock_cpu(raw_smp_processor_id()); 388 return sched_clock_cpu(raw_smp_processor_id());
360 389
361 return sched_clock(); 390 return sched_clock();