aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/Kconfig3
-rw-r--r--kernel/cpu.c2
-rw-r--r--kernel/sched/core.c2
-rw-r--r--kernel/smpboot.c84
-rw-r--r--kernel/smpboot.h10
5 files changed, 99 insertions, 2 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index 684eb5af439..4f0d0f7c831 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -145,6 +145,9 @@ config HAVE_DMA_ATTRS
145config USE_GENERIC_SMP_HELPERS 145config USE_GENERIC_SMP_HELPERS
146 bool 146 bool
147 147
148config GENERIC_SMP_IDLE_THREAD
149 bool
150
148config HAVE_REGS_AND_STACK_ACCESS_API 151config HAVE_REGS_AND_STACK_ACCESS_API
149 bool 152 bool
150 help 153 help
diff --git a/kernel/cpu.c b/kernel/cpu.c
index e58b99ada3d..05c46bae5e5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -316,7 +316,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
316 } 316 }
317 317
318 /* Arch-specific enabling code. */ 318 /* Arch-specific enabling code. */
319 ret = __cpu_up(cpu, NULL); 319 ret = __cpu_up(cpu, idle_thread_get(cpu));
320 if (ret != 0) 320 if (ret != 0)
321 goto out_notify; 321 goto out_notify;
322 BUG_ON(!cpu_online(cpu)); 322 BUG_ON(!cpu_online(cpu));
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4603b9d8f30..6a63cde23d0 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -83,6 +83,7 @@
83 83
84#include "sched.h" 84#include "sched.h"
85#include "../workqueue_sched.h" 85#include "../workqueue_sched.h"
86#include "../smpboot.h"
86 87
87#define CREATE_TRACE_POINTS 88#define CREATE_TRACE_POINTS
88#include <trace/events/sched.h> 89#include <trace/events/sched.h>
@@ -7049,6 +7050,7 @@ void __init sched_init(void)
7049 /* May be allocated at isolcpus cmdline parse time */ 7050 /* May be allocated at isolcpus cmdline parse time */
7050 if (cpu_isolated_map == NULL) 7051 if (cpu_isolated_map == NULL)
7051 zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT); 7052 zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
7053 idle_thread_set_boot_cpu();
7052#endif 7054#endif
7053 init_sched_fair_class(); 7055 init_sched_fair_class();
7054 7056
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index 6dae6a3d2d5..ed157698180 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -1,14 +1,96 @@
1/* 1/*
2 * Common SMP CPU bringup/teardown functions 2 * Common SMP CPU bringup/teardown functions
3 */ 3 */
4#include <linux/err.h>
5#include <linux/smp.h>
4#include <linux/init.h> 6#include <linux/init.h>
7#include <linux/sched.h>
8#include <linux/percpu.h>
9#include <linux/workqueue.h>
5 10
6#include "smpboot.h" 11#include "smpboot.h"
7 12
13#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
14struct create_idle {
15 struct work_struct work;
16 struct task_struct *idle;
17 struct completion done;
18 unsigned int cpu;
19};
20
21static void __cpuinit do_fork_idle(struct work_struct *work)
22{
23 struct create_idle *c = container_of(work, struct create_idle, work);
24
25 c->idle = fork_idle(c->cpu);
26 complete(&c->done);
27}
28
29static struct task_struct * __cpuinit idle_thread_create(unsigned int cpu)
30{
31 struct create_idle c_idle = {
32 .cpu = cpu,
33 .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
34 };
35
36 INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
37 schedule_work(&c_idle.work);
38 wait_for_completion(&c_idle.done);
39 destroy_work_on_stack(&c_idle.work);
40 return c_idle.idle;
41}
42
43/*
44 * For the hotplug case we keep the task structs around and reuse
45 * them.
46 */
47static DEFINE_PER_CPU(struct task_struct *, idle_threads);
48
49static inline struct task_struct *get_idle_for_cpu(unsigned int cpu)
50{
51 struct task_struct *tsk = per_cpu(idle_threads, cpu);
52
53 if (!tsk)
54 return idle_thread_create(cpu);
55 init_idle(tsk, cpu);
56 return tsk;
57}
58
59struct task_struct * __cpuinit idle_thread_get(unsigned int cpu)
60{
61 return per_cpu(idle_threads, cpu);
62}
63
64void __init idle_thread_set_boot_cpu(void)
65{
66 per_cpu(idle_threads, smp_processor_id()) = current;
67}
68
69/**
70 * idle_thread_init - Initialize the idle thread for a cpu
71 * @cpu: The cpu for which the idle thread should be initialized
72 *
73 * Creates the thread if it does not exist.
74 */
75static int __cpuinit idle_thread_init(unsigned int cpu)
76{
77 struct task_struct *idle = get_idle_for_cpu(cpu);
78
79 if (IS_ERR(idle)) {
80 printk(KERN_ERR "failed fork for CPU %u\n", cpu);
81 return PTR_ERR(idle);
82 }
83 per_cpu(idle_threads, cpu) = idle;
84 return 0;
85}
86#else
87static inline int idle_thread_init(unsigned int cpu) { return 0; }
88#endif
89
8/** 90/**
9 * smpboot_prepare - generic smpboot preparation 91 * smpboot_prepare - generic smpboot preparation
10 */ 92 */
11int __cpuinit smpboot_prepare(unsigned int cpu) 93int __cpuinit smpboot_prepare(unsigned int cpu)
12{ 94{
13 return 0; 95 return idle_thread_init(cpu);
14} 96}
diff --git a/kernel/smpboot.h b/kernel/smpboot.h
index d88e7716508..7943bbbab91 100644
--- a/kernel/smpboot.h
+++ b/kernel/smpboot.h
@@ -1,6 +1,16 @@
1#ifndef SMPBOOT_H 1#ifndef SMPBOOT_H
2#define SMPBOOT_H 2#define SMPBOOT_H
3 3
4struct task_struct;
5
4int smpboot_prepare(unsigned int cpu); 6int smpboot_prepare(unsigned int cpu);
5 7
8#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
9struct task_struct *idle_thread_get(unsigned int cpu);
10void idle_thread_set_boot_cpu(void);
11#else
12static inline struct task_struct *idle_thread_get(unsigned int cpu) { return NULL; }
13static inline void idle_thread_set_boot_cpu(void) { }
14#endif
15
6#endif 16#endif