aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2013-03-26 21:18:34 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2013-04-19 07:53:14 -0400
commit0453b435df0d69dd0d8c42eb9b3015aaf0d8a032 (patch)
treea941e04d55e74cc40285834a37175a5be41c12db /kernel
parent65d798f0f9339ae2c4ebe9480e3260b33382a584 (diff)
nohz: Force boot CPU outside full dynticks range
The timekeeping job must be able to run early on boot because there may be some pre-SMP (and thus pre-initcalls ) components that rely on it. The IO-APIC is one such users as it tests the timer health by watching jiffies progression. Given that it happens before we know the initial online set, we can't rely on it to select a timekeeper. We need one before SMP time otherwise we simply crash on boot. To fix this and keep things simple for now, force the boot CPU outside of the full dynticks range in any case and do this early on kernel parameter parsing time. We might want a trickier solution later, expecially for aSMP architectures that need to assign housekeeping tasks to arbitrary low power CPUs. But it's still first pass KISS time for now. Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Chris Metcalf <cmetcalf@tilera.com> Cc: Christoph Lameter <cl@linux.com> Cc: Geoff Levand <geoff@infradead.org> Cc: Gilad Ben Yossef <gilad@benyossef.com> Cc: Hakan Akkan <hakanakkan@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Kevin Hilman <khilman@linaro.org> Cc: Li Zhong <zhong@linux.vnet.ibm.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/tick-sched.c54
1 files changed, 15 insertions, 39 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 369b5769fc97..2bac5ea2c9af 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -158,11 +158,21 @@ int tick_nohz_full_cpu(int cpu)
158/* Parse the boot-time nohz CPU list from the kernel parameters. */ 158/* Parse the boot-time nohz CPU list from the kernel parameters. */
159static int __init tick_nohz_full_setup(char *str) 159static int __init tick_nohz_full_setup(char *str)
160{ 160{
161 int cpu;
162
161 alloc_bootmem_cpumask_var(&nohz_full_mask); 163 alloc_bootmem_cpumask_var(&nohz_full_mask);
162 if (cpulist_parse(str, nohz_full_mask) < 0) 164 if (cpulist_parse(str, nohz_full_mask) < 0) {
163 pr_warning("NOHZ: Incorrect nohz_full cpumask\n"); 165 pr_warning("NOHZ: Incorrect nohz_full cpumask\n");
164 else 166 return 1;
165 have_nohz_full_mask = true; 167 }
168
169 cpu = smp_processor_id();
170 if (cpumask_test_cpu(cpu, nohz_full_mask)) {
171 pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu);
172 cpumask_clear_cpu(cpu, nohz_full_mask);
173 }
174 have_nohz_full_mask = true;
175
166 return 1; 176 return 1;
167} 177}
168__setup("nohz_full=", tick_nohz_full_setup); 178__setup("nohz_full=", tick_nohz_full_setup);
@@ -195,42 +205,8 @@ static char __initdata nohz_full_buf[NR_CPUS + 1];
195 205
196static int __init init_tick_nohz_full(void) 206static int __init init_tick_nohz_full(void)
197{ 207{
198 cpumask_var_t online_nohz; 208 if (have_nohz_full_mask)
199 int cpu; 209 cpu_notifier(tick_nohz_cpu_down_callback, 0);
200
201 if (!have_nohz_full_mask)
202 return 0;
203
204 cpu_notifier(tick_nohz_cpu_down_callback, 0);
205
206 if (!zalloc_cpumask_var(&online_nohz, GFP_KERNEL)) {
207 pr_warning("NO_HZ: Not enough memory to check full nohz mask\n");
208 return -ENOMEM;
209 }
210
211 /*
212 * CPUs can probably not be concurrently offlined on initcall time.
213 * But we are paranoid, aren't we?
214 */
215 get_online_cpus();
216
217 /* Ensure we keep a CPU outside the dynticks range for timekeeping */
218 cpumask_and(online_nohz, cpu_online_mask, nohz_full_mask);
219 if (cpumask_equal(online_nohz, cpu_online_mask)) {
220 pr_warning("NO_HZ: Must keep at least one online CPU "
221 "out of nohz_full range\n");
222 /*
223 * We know the current CPU doesn't have its tick stopped.
224 * Let's use it for the timekeeping duty.
225 */
226 preempt_disable();
227 cpu = smp_processor_id();
228 pr_warning("NO_HZ: Clearing %d from nohz_full range\n", cpu);
229 cpumask_clear_cpu(cpu, nohz_full_mask);
230 preempt_enable();
231 }
232 put_online_cpus();
233 free_cpumask_var(online_nohz);
234 210
235 cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask); 211 cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask);
236 pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf); 212 pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf);