aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/process.c')
-rw-r--r--arch/x86_64/kernel/process.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 33feab9c75691..171931ea7eaae 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -62,7 +62,7 @@ EXPORT_SYMBOL(boot_option_idle_override);
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
-static cpumask_t cpu_idle_map;
+static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
void disable_hlt(void)
{
@@ -125,20 +125,31 @@ static void poll_idle (void)
}
}
-
void cpu_idle_wait(void)
{
- int cpu;
- cpumask_t map;
+ unsigned int cpu, this_cpu = get_cpu();
+ cpumask_t map;
+
+ set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
+ put_cpu();
+
+ cpus_clear(map);
+ for_each_online_cpu(cpu) {
+ per_cpu(cpu_idle_state, cpu) = 1;
+ cpu_set(cpu, map);
+ }
- for_each_online_cpu(cpu)
- cpu_set(cpu, cpu_idle_map);
+ __get_cpu_var(cpu_idle_state) = 0;
- wmb();
- do {
- ssleep(1);
- cpus_and(map, cpu_idle_map, cpu_online_map);
- } while (!cpus_empty(map));
+ wmb();
+ do {
+ ssleep(1);
+ for_each_online_cpu(cpu) {
+ if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
+ cpu_clear(cpu, map);
+ }
+ cpus_and(map, map, cpu_online_map);
+ } while (!cpus_empty(map));
}
EXPORT_SYMBOL_GPL(cpu_idle_wait);
@@ -150,21 +161,21 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
*/
void cpu_idle (void)
{
- int cpu = smp_processor_id();
-
/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
void (*idle)(void);
- if (cpu_isset(cpu, cpu_idle_map))
- cpu_clear(cpu, cpu_idle_map);
+ if (__get_cpu_var(cpu_idle_state))
+ __get_cpu_var(cpu_idle_state) = 0;
+
rmb();
idle = pm_idle;
if (!idle)
idle = default_idle;
idle();
}
+
schedule();
}
}