diff options
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r-- | arch/arm/kernel/process.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 1585423699ee..39196dff478c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -114,9 +114,6 @@ void arm_machine_restart(char mode, const char *cmd) | |||
114 | /* | 114 | /* |
115 | * Function pointers to optional machine specific functions | 115 | * Function pointers to optional machine specific functions |
116 | */ | 116 | */ |
117 | void (*pm_idle)(void); | ||
118 | EXPORT_SYMBOL(pm_idle); | ||
119 | |||
120 | void (*pm_power_off)(void); | 117 | void (*pm_power_off)(void); |
121 | EXPORT_SYMBOL(pm_power_off); | 118 | EXPORT_SYMBOL(pm_power_off); |
122 | 119 | ||
@@ -130,20 +127,19 @@ EXPORT_SYMBOL_GPL(arm_pm_restart); | |||
130 | */ | 127 | */ |
131 | static void default_idle(void) | 128 | static void default_idle(void) |
132 | { | 129 | { |
133 | if (hlt_counter) | 130 | if (!need_resched()) |
134 | cpu_relax(); | 131 | arch_idle(); |
135 | else { | 132 | local_irq_enable(); |
136 | local_irq_disable(); | ||
137 | if (!need_resched()) | ||
138 | arch_idle(); | ||
139 | local_irq_enable(); | ||
140 | } | ||
141 | } | 133 | } |
142 | 134 | ||
135 | void (*pm_idle)(void) = default_idle; | ||
136 | EXPORT_SYMBOL(pm_idle); | ||
137 | |||
143 | /* | 138 | /* |
144 | * The idle thread. We try to conserve power, while trying to keep | 139 | * The idle thread, has rather strange semantics for calling pm_idle, |
145 | * overall latency low. The architecture specific idle is passed | 140 | * but this is what x86 does and we need to do the same, so that |
146 | * a value to indicate the level of "idleness" of the system. | 141 | * things like cpuidle get called in the same way. The only difference |
142 | * is that we always respect 'hlt_counter' to prevent low power idle. | ||
147 | */ | 143 | */ |
148 | void cpu_idle(void) | 144 | void cpu_idle(void) |
149 | { | 145 | { |
@@ -151,21 +147,31 @@ void cpu_idle(void) | |||
151 | 147 | ||
152 | /* endless idle loop with no priority at all */ | 148 | /* endless idle loop with no priority at all */ |
153 | while (1) { | 149 | while (1) { |
154 | void (*idle)(void) = pm_idle; | 150 | tick_nohz_stop_sched_tick(1); |
155 | 151 | leds_event(led_idle_start); | |
152 | while (!need_resched()) { | ||
156 | #ifdef CONFIG_HOTPLUG_CPU | 153 | #ifdef CONFIG_HOTPLUG_CPU |
157 | if (cpu_is_offline(smp_processor_id())) { | 154 | if (cpu_is_offline(smp_processor_id())) |
158 | leds_event(led_idle_start); | 155 | cpu_die(); |
159 | cpu_die(); | ||
160 | } | ||
161 | #endif | 156 | #endif |
162 | 157 | ||
163 | if (!idle) | 158 | local_irq_disable(); |
164 | idle = default_idle; | 159 | if (hlt_counter) { |
165 | leds_event(led_idle_start); | 160 | local_irq_enable(); |
166 | tick_nohz_stop_sched_tick(1); | 161 | cpu_relax(); |
167 | while (!need_resched()) | 162 | } else { |
168 | idle(); | 163 | stop_critical_timings(); |
164 | pm_idle(); | ||
165 | start_critical_timings(); | ||
166 | /* | ||
167 | * This will eventually be removed - pm_idle | ||
168 | * functions should always return with IRQs | ||
169 | * enabled. | ||
170 | */ | ||
171 | WARN_ON(irqs_disabled()); | ||
172 | local_irq_enable(); | ||
173 | } | ||
174 | } | ||
169 | leds_event(led_idle_end); | 175 | leds_event(led_idle_end); |
170 | tick_nohz_restart_sched_tick(); | 176 | tick_nohz_restart_sched_tick(); |
171 | preempt_enable_no_resched(); | 177 | preempt_enable_no_resched(); |
@@ -352,6 +358,23 @@ asm( ".section .text\n" | |||
352 | " .size kernel_thread_helper, . - kernel_thread_helper\n" | 358 | " .size kernel_thread_helper, . - kernel_thread_helper\n" |
353 | " .previous"); | 359 | " .previous"); |
354 | 360 | ||
361 | #ifdef CONFIG_ARM_UNWIND | ||
362 | extern void kernel_thread_exit(long code); | ||
363 | asm( ".section .text\n" | ||
364 | " .align\n" | ||
365 | " .type kernel_thread_exit, #function\n" | ||
366 | "kernel_thread_exit:\n" | ||
367 | " .fnstart\n" | ||
368 | " .cantunwind\n" | ||
369 | " bl do_exit\n" | ||
370 | " nop\n" | ||
371 | " .fnend\n" | ||
372 | " .size kernel_thread_exit, . - kernel_thread_exit\n" | ||
373 | " .previous"); | ||
374 | #else | ||
375 | #define kernel_thread_exit do_exit | ||
376 | #endif | ||
377 | |||
355 | /* | 378 | /* |
356 | * Create a kernel thread. | 379 | * Create a kernel thread. |
357 | */ | 380 | */ |
@@ -363,7 +386,7 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | |||
363 | 386 | ||
364 | regs.ARM_r1 = (unsigned long)arg; | 387 | regs.ARM_r1 = (unsigned long)arg; |
365 | regs.ARM_r2 = (unsigned long)fn; | 388 | regs.ARM_r2 = (unsigned long)fn; |
366 | regs.ARM_r3 = (unsigned long)do_exit; | 389 | regs.ARM_r3 = (unsigned long)kernel_thread_exit; |
367 | regs.ARM_pc = (unsigned long)kernel_thread_helper; | 390 | regs.ARM_pc = (unsigned long)kernel_thread_helper; |
368 | regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE; | 391 | regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE; |
369 | 392 | ||