diff options
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r-- | arch/arm/kernel/process.c | 133 |
1 files changed, 126 insertions, 7 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 5e1e5419722..3a2da7788cc 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -30,9 +30,10 @@ | |||
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/random.h> | 31 | #include <linux/random.h> |
32 | #include <linux/hw_breakpoint.h> | 32 | #include <linux/hw_breakpoint.h> |
33 | #include <linux/cpuidle.h> | ||
34 | #include <linux/console.h> | ||
33 | 35 | ||
34 | #include <asm/cacheflush.h> | 36 | #include <asm/cacheflush.h> |
35 | #include <asm/leds.h> | ||
36 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
37 | #include <asm/system.h> | 38 | #include <asm/system.h> |
38 | #include <asm/thread_notify.h> | 39 | #include <asm/thread_notify.h> |
@@ -62,6 +63,18 @@ static volatile int hlt_counter; | |||
62 | 63 | ||
63 | #include <mach/system.h> | 64 | #include <mach/system.h> |
64 | 65 | ||
66 | #ifdef CONFIG_SMP | ||
67 | void arch_trigger_all_cpu_backtrace(void) | ||
68 | { | ||
69 | smp_send_all_cpu_backtrace(); | ||
70 | } | ||
71 | #else | ||
72 | void arch_trigger_all_cpu_backtrace(void) | ||
73 | { | ||
74 | dump_stack(); | ||
75 | } | ||
76 | #endif | ||
77 | |||
65 | void disable_hlt(void) | 78 | void disable_hlt(void) |
66 | { | 79 | { |
67 | hlt_counter++; | 80 | hlt_counter++; |
@@ -91,12 +104,33 @@ static int __init hlt_setup(char *__unused) | |||
91 | __setup("nohlt", nohlt_setup); | 104 | __setup("nohlt", nohlt_setup); |
92 | __setup("hlt", hlt_setup); | 105 | __setup("hlt", hlt_setup); |
93 | 106 | ||
94 | void arm_machine_restart(char mode, const char *cmd) | 107 | #ifdef CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART |
108 | void arm_machine_flush_console(void) | ||
95 | { | 109 | { |
96 | /* Disable interrupts first */ | 110 | printk("\n"); |
111 | pr_emerg("Restarting %s\n", linux_banner); | ||
112 | if (console_trylock()) { | ||
113 | console_unlock(); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | mdelay(50); | ||
118 | |||
97 | local_irq_disable(); | 119 | local_irq_disable(); |
98 | local_fiq_disable(); | 120 | if (!console_trylock()) |
121 | pr_emerg("arm_restart: Console was locked! Busting\n"); | ||
122 | else | ||
123 | pr_emerg("arm_restart: Console was locked!\n"); | ||
124 | console_unlock(); | ||
125 | } | ||
126 | #else | ||
127 | void arm_machine_flush_console(void) | ||
128 | { | ||
129 | } | ||
130 | #endif | ||
99 | 131 | ||
132 | void arm_machine_restart(char mode, const char *cmd) | ||
133 | { | ||
100 | /* | 134 | /* |
101 | * Tell the mm system that we are going to reboot - | 135 | * Tell the mm system that we are going to reboot - |
102 | * we may need it to insert some 1:1 mappings so that | 136 | * we may need it to insert some 1:1 mappings so that |
@@ -182,8 +216,8 @@ void cpu_idle(void) | |||
182 | 216 | ||
183 | /* endless idle loop with no priority at all */ | 217 | /* endless idle loop with no priority at all */ |
184 | while (1) { | 218 | while (1) { |
219 | idle_notifier_call_chain(IDLE_START); | ||
185 | tick_nohz_stop_sched_tick(1); | 220 | tick_nohz_stop_sched_tick(1); |
186 | leds_event(led_idle_start); | ||
187 | while (!need_resched()) { | 221 | while (!need_resched()) { |
188 | #ifdef CONFIG_HOTPLUG_CPU | 222 | #ifdef CONFIG_HOTPLUG_CPU |
189 | if (cpu_is_offline(smp_processor_id())) | 223 | if (cpu_is_offline(smp_processor_id())) |
@@ -191,12 +225,16 @@ void cpu_idle(void) | |||
191 | #endif | 225 | #endif |
192 | 226 | ||
193 | local_irq_disable(); | 227 | local_irq_disable(); |
228 | #ifdef CONFIG_PL310_ERRATA_769419 | ||
229 | wmb(); | ||
230 | #endif | ||
194 | if (hlt_counter) { | 231 | if (hlt_counter) { |
195 | local_irq_enable(); | 232 | local_irq_enable(); |
196 | cpu_relax(); | 233 | cpu_relax(); |
197 | } else { | 234 | } else { |
198 | stop_critical_timings(); | 235 | stop_critical_timings(); |
199 | pm_idle(); | 236 | if (cpuidle_idle_call()) |
237 | pm_idle(); | ||
200 | start_critical_timings(); | 238 | start_critical_timings(); |
201 | /* | 239 | /* |
202 | * This will eventually be removed - pm_idle | 240 | * This will eventually be removed - pm_idle |
@@ -207,8 +245,8 @@ void cpu_idle(void) | |||
207 | local_irq_enable(); | 245 | local_irq_enable(); |
208 | } | 246 | } |
209 | } | 247 | } |
210 | leds_event(led_idle_end); | ||
211 | tick_nohz_restart_sched_tick(); | 248 | tick_nohz_restart_sched_tick(); |
249 | idle_notifier_call_chain(IDLE_END); | ||
212 | preempt_enable_no_resched(); | 250 | preempt_enable_no_resched(); |
213 | schedule(); | 251 | schedule(); |
214 | preempt_disable(); | 252 | preempt_disable(); |
@@ -247,10 +285,89 @@ void machine_power_off(void) | |||
247 | 285 | ||
248 | void machine_restart(char *cmd) | 286 | void machine_restart(char *cmd) |
249 | { | 287 | { |
288 | /* Flush the console to make sure all the relevant messages make it | ||
289 | * out to the console drivers */ | ||
290 | arm_machine_flush_console(); | ||
291 | |||
292 | /* Disable interrupts first */ | ||
293 | local_irq_disable(); | ||
294 | local_fiq_disable(); | ||
295 | |||
250 | machine_shutdown(); | 296 | machine_shutdown(); |
251 | arm_pm_restart(reboot_mode, cmd); | 297 | arm_pm_restart(reboot_mode, cmd); |
252 | } | 298 | } |
253 | 299 | ||
300 | /* | ||
301 | * dump a block of kernel memory from around the given address | ||
302 | */ | ||
303 | static void show_data(unsigned long addr, int nbytes, const char *name) | ||
304 | { | ||
305 | int i, j; | ||
306 | int nlines; | ||
307 | u32 *p; | ||
308 | |||
309 | /* | ||
310 | * don't attempt to dump non-kernel addresses or | ||
311 | * values that are probably just small negative numbers | ||
312 | */ | ||
313 | if (addr < PAGE_OFFSET || addr > -256UL) | ||
314 | return; | ||
315 | |||
316 | printk("\n%s: %#lx:\n", name, addr); | ||
317 | |||
318 | /* | ||
319 | * round address down to a 32 bit boundary | ||
320 | * and always dump a multiple of 32 bytes | ||
321 | */ | ||
322 | p = (u32 *)(addr & ~(sizeof(u32) - 1)); | ||
323 | nbytes += (addr & (sizeof(u32) - 1)); | ||
324 | nlines = (nbytes + 31) / 32; | ||
325 | |||
326 | |||
327 | for (i = 0; i < nlines; i++) { | ||
328 | /* | ||
329 | * just display low 16 bits of address to keep | ||
330 | * each line of the dump < 80 characters | ||
331 | */ | ||
332 | printk("%04lx ", (unsigned long)p & 0xffff); | ||
333 | for (j = 0; j < 8; j++) { | ||
334 | u32 data; | ||
335 | if (probe_kernel_address(p, data)) { | ||
336 | printk(" ********"); | ||
337 | } else { | ||
338 | printk(" %08x", data); | ||
339 | } | ||
340 | ++p; | ||
341 | } | ||
342 | printk("\n"); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | static void show_extra_register_data(struct pt_regs *regs, int nbytes) | ||
347 | { | ||
348 | mm_segment_t fs; | ||
349 | |||
350 | fs = get_fs(); | ||
351 | set_fs(KERNEL_DS); | ||
352 | show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC"); | ||
353 | show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR"); | ||
354 | show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); | ||
355 | show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); | ||
356 | show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); | ||
357 | show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); | ||
358 | show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); | ||
359 | show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); | ||
360 | show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); | ||
361 | show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); | ||
362 | show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); | ||
363 | show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); | ||
364 | show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); | ||
365 | show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); | ||
366 | show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); | ||
367 | show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); | ||
368 | set_fs(fs); | ||
369 | } | ||
370 | |||
254 | void __show_regs(struct pt_regs *regs) | 371 | void __show_regs(struct pt_regs *regs) |
255 | { | 372 | { |
256 | unsigned long flags; | 373 | unsigned long flags; |
@@ -310,6 +427,8 @@ void __show_regs(struct pt_regs *regs) | |||
310 | printk("Control: %08x%s\n", ctrl, buf); | 427 | printk("Control: %08x%s\n", ctrl, buf); |
311 | } | 428 | } |
312 | #endif | 429 | #endif |
430 | |||
431 | show_extra_register_data(regs, 128); | ||
313 | } | 432 | } |
314 | 433 | ||
315 | void show_regs(struct pt_regs * regs) | 434 | void show_regs(struct pt_regs * regs) |