diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cpu.c | 2 | ||||
-rw-r--r-- | kernel/sched/core.c | 2 | ||||
-rw-r--r-- | kernel/smpboot.c | 84 | ||||
-rw-r--r-- | kernel/smpboot.h | 10 |
4 files changed, 96 insertions, 2 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index e58b99ada3d8..05c46bae5e55 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 4603b9d8f30a..6a63cde23d03 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 6dae6a3d2d59..ed1576981801 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 | ||
14 | struct create_idle { | ||
15 | struct work_struct work; | ||
16 | struct task_struct *idle; | ||
17 | struct completion done; | ||
18 | unsigned int cpu; | ||
19 | }; | ||
20 | |||
21 | static 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 | |||
29 | static 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 | */ | ||
47 | static DEFINE_PER_CPU(struct task_struct *, idle_threads); | ||
48 | |||
49 | static 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 | |||
59 | struct task_struct * __cpuinit idle_thread_get(unsigned int cpu) | ||
60 | { | ||
61 | return per_cpu(idle_threads, cpu); | ||
62 | } | ||
63 | |||
64 | void __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 | */ | ||
75 | static 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 | ||
87 | static 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 | */ |
11 | int __cpuinit smpboot_prepare(unsigned int cpu) | 93 | int __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 d88e77165086..7943bbbab917 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 | ||
4 | struct task_struct; | ||
5 | |||
4 | int smpboot_prepare(unsigned int cpu); | 6 | int smpboot_prepare(unsigned int cpu); |
5 | 7 | ||
8 | #ifdef CONFIG_GENERIC_SMP_IDLE_THREAD | ||
9 | struct task_struct *idle_thread_get(unsigned int cpu); | ||
10 | void idle_thread_set_boot_cpu(void); | ||
11 | #else | ||
12 | static inline struct task_struct *idle_thread_get(unsigned int cpu) { return NULL; } | ||
13 | static inline void idle_thread_set_boot_cpu(void) { } | ||
14 | #endif | ||
15 | |||
6 | #endif | 16 | #endif |