diff options
Diffstat (limited to 'arch/x86_64/kernel/process.c')
-rw-r--r-- | arch/x86_64/kernel/process.c | 41 |
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(); } } |