forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
smp: Provide generic idle thread allocation
All SMP architectures have magic to fork the idle task and to store it for reusage when cpu hotplug is enabled. Provide a generic infrastructure for it. Create/reinit the idle thread for the cpu which is brought up in the generic code and hand the thread pointer to the architecture code via __cpu_up(). Note, that fork_idle() is called via a workqueue, because this guarantees that the idle thread does not get a reference to a user space VM. This can happen when the boot process did not bring up all possible cpus and a later cpu_up() is initiated via the sysfs interface. In that case fork_idle() would be called in the context of the user space task and take a reference on the user space VM. Signed-off-by: Thomas Gleixner <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Rusty Russell <[email protected]> Cc: Paul E. McKenney <[email protected]> Cc: Srivatsa S. Bhat <[email protected]> Cc: Matt Turner <[email protected]> Cc: Russell King <[email protected]> Cc: Mike Frysinger <[email protected]> Cc: Jesper Nilsson <[email protected]> Cc: Richard Kuo <[email protected]> Cc: Tony Luck <[email protected]> Cc: Hirokazu Takata <[email protected]> Cc: Ralf Baechle <[email protected]> Cc: David Howells <[email protected]> Cc: James E.J. Bottomley <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Martin Schwidefsky <[email protected]> Cc: Paul Mundt <[email protected]> Cc: David S. Miller <[email protected]> Cc: Chris Metcalf <[email protected]> Cc: Richard Weinberger <[email protected]> Cc: [email protected] Acked-by: Venkatesh Pallipadi <[email protected]> Link: http://lkml.kernel.org/r/[email protected]
- Loading branch information
Showing
5 changed files
with
99 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,96 @@ | ||
/* | ||
* Common SMP CPU bringup/teardown functions | ||
*/ | ||
#include <linux/err.h> | ||
#include <linux/smp.h> | ||
#include <linux/init.h> | ||
#include <linux/sched.h> | ||
#include <linux/percpu.h> | ||
#include <linux/workqueue.h> | ||
|
||
#include "smpboot.h" | ||
|
||
#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD | ||
struct create_idle { | ||
struct work_struct work; | ||
struct task_struct *idle; | ||
struct completion done; | ||
unsigned int cpu; | ||
}; | ||
|
||
static void __cpuinit do_fork_idle(struct work_struct *work) | ||
{ | ||
struct create_idle *c = container_of(work, struct create_idle, work); | ||
|
||
c->idle = fork_idle(c->cpu); | ||
complete(&c->done); | ||
} | ||
|
||
static struct task_struct * __cpuinit idle_thread_create(unsigned int cpu) | ||
{ | ||
struct create_idle c_idle = { | ||
.cpu = cpu, | ||
.done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), | ||
}; | ||
|
||
INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle); | ||
schedule_work(&c_idle.work); | ||
wait_for_completion(&c_idle.done); | ||
destroy_work_on_stack(&c_idle.work); | ||
return c_idle.idle; | ||
} | ||
|
||
/* | ||
* For the hotplug case we keep the task structs around and reuse | ||
* them. | ||
*/ | ||
static DEFINE_PER_CPU(struct task_struct *, idle_threads); | ||
|
||
static inline struct task_struct *get_idle_for_cpu(unsigned int cpu) | ||
{ | ||
struct task_struct *tsk = per_cpu(idle_threads, cpu); | ||
|
||
if (!tsk) | ||
return idle_thread_create(cpu); | ||
init_idle(tsk, cpu); | ||
return tsk; | ||
} | ||
|
||
struct task_struct * __cpuinit idle_thread_get(unsigned int cpu) | ||
{ | ||
return per_cpu(idle_threads, cpu); | ||
} | ||
|
||
void __init idle_thread_set_boot_cpu(void) | ||
{ | ||
per_cpu(idle_threads, smp_processor_id()) = current; | ||
} | ||
|
||
/** | ||
* idle_thread_init - Initialize the idle thread for a cpu | ||
* @cpu: The cpu for which the idle thread should be initialized | ||
* | ||
* Creates the thread if it does not exist. | ||
*/ | ||
static int __cpuinit idle_thread_init(unsigned int cpu) | ||
{ | ||
struct task_struct *idle = get_idle_for_cpu(cpu); | ||
|
||
if (IS_ERR(idle)) { | ||
printk(KERN_ERR "failed fork for CPU %u\n", cpu); | ||
return PTR_ERR(idle); | ||
} | ||
per_cpu(idle_threads, cpu) = idle; | ||
return 0; | ||
} | ||
#else | ||
static inline int idle_thread_init(unsigned int cpu) { return 0; } | ||
#endif | ||
|
||
/** | ||
* smpboot_prepare - generic smpboot preparation | ||
*/ | ||
int __cpuinit smpboot_prepare(unsigned int cpu) | ||
{ | ||
return 0; | ||
return idle_thread_init(cpu); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,16 @@ | ||
#ifndef SMPBOOT_H | ||
#define SMPBOOT_H | ||
|
||
struct task_struct; | ||
|
||
int smpboot_prepare(unsigned int cpu); | ||
|
||
#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD | ||
struct task_struct *idle_thread_get(unsigned int cpu); | ||
void idle_thread_set_boot_cpu(void); | ||
#else | ||
static inline struct task_struct *idle_thread_get(unsigned int cpu) { return NULL; } | ||
static inline void idle_thread_set_boot_cpu(void) { } | ||
#endif | ||
|
||
#endif |