diff options
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r-- | arch/arm/kernel/process.c | 81 |
1 files changed, 16 insertions, 65 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 693b744fd572..f98c17ff1957 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -31,9 +31,9 @@ | |||
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> | 33 | #include <linux/cpuidle.h> |
34 | #include <linux/leds.h> | ||
34 | 35 | ||
35 | #include <asm/cacheflush.h> | 36 | #include <asm/cacheflush.h> |
36 | #include <asm/leds.h> | ||
37 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
38 | #include <asm/thread_notify.h> | 38 | #include <asm/thread_notify.h> |
39 | #include <asm/stacktrace.h> | 39 | #include <asm/stacktrace.h> |
@@ -189,7 +189,7 @@ void cpu_idle(void) | |||
189 | while (1) { | 189 | while (1) { |
190 | tick_nohz_idle_enter(); | 190 | tick_nohz_idle_enter(); |
191 | rcu_idle_enter(); | 191 | rcu_idle_enter(); |
192 | leds_event(led_idle_start); | 192 | ledtrig_cpu(CPU_LED_IDLE_START); |
193 | while (!need_resched()) { | 193 | while (!need_resched()) { |
194 | #ifdef CONFIG_HOTPLUG_CPU | 194 | #ifdef CONFIG_HOTPLUG_CPU |
195 | if (cpu_is_offline(smp_processor_id())) | 195 | if (cpu_is_offline(smp_processor_id())) |
@@ -220,7 +220,7 @@ void cpu_idle(void) | |||
220 | } else | 220 | } else |
221 | local_irq_enable(); | 221 | local_irq_enable(); |
222 | } | 222 | } |
223 | leds_event(led_idle_end); | 223 | ledtrig_cpu(CPU_LED_IDLE_END); |
224 | rcu_idle_exit(); | 224 | rcu_idle_exit(); |
225 | tick_nohz_idle_exit(); | 225 | tick_nohz_idle_exit(); |
226 | schedule_preempt_disabled(); | 226 | schedule_preempt_disabled(); |
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task) | |||
373 | } | 373 | } |
374 | 374 | ||
375 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 375 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
376 | asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); | ||
376 | 377 | ||
377 | int | 378 | int |
378 | copy_thread(unsigned long clone_flags, unsigned long stack_start, | 379 | copy_thread(unsigned long clone_flags, unsigned long stack_start, |
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
381 | struct thread_info *thread = task_thread_info(p); | 382 | struct thread_info *thread = task_thread_info(p); |
382 | struct pt_regs *childregs = task_pt_regs(p); | 383 | struct pt_regs *childregs = task_pt_regs(p); |
383 | 384 | ||
384 | *childregs = *regs; | ||
385 | childregs->ARM_r0 = 0; | ||
386 | childregs->ARM_sp = stack_start; | ||
387 | |||
388 | memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); | 385 | memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); |
386 | |||
387 | if (likely(regs)) { | ||
388 | *childregs = *regs; | ||
389 | childregs->ARM_r0 = 0; | ||
390 | childregs->ARM_sp = stack_start; | ||
391 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | ||
392 | } else { | ||
393 | thread->cpu_context.r4 = stk_sz; | ||
394 | thread->cpu_context.r5 = stack_start; | ||
395 | thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread; | ||
396 | childregs->ARM_cpsr = SVC_MODE; | ||
397 | } | ||
389 | thread->cpu_context.sp = (unsigned long)childregs; | 398 | thread->cpu_context.sp = (unsigned long)childregs; |
390 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | ||
391 | 399 | ||
392 | clear_ptrace_hw_breakpoint(p); | 400 | clear_ptrace_hw_breakpoint(p); |
393 | 401 | ||
@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) | |||
423 | } | 431 | } |
424 | EXPORT_SYMBOL(dump_fpu); | 432 | EXPORT_SYMBOL(dump_fpu); |
425 | 433 | ||
426 | /* | ||
427 | * Shuffle the argument into the correct register before calling the | ||
428 | * thread function. r4 is the thread argument, r5 is the pointer to | ||
429 | * the thread function, and r6 points to the exit function. | ||
430 | */ | ||
431 | extern void kernel_thread_helper(void); | ||
432 | asm( ".pushsection .text\n" | ||
433 | " .align\n" | ||
434 | " .type kernel_thread_helper, #function\n" | ||
435 | "kernel_thread_helper:\n" | ||
436 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
437 | " bl trace_hardirqs_on\n" | ||
438 | #endif | ||
439 | " msr cpsr_c, r7\n" | ||
440 | " mov r0, r4\n" | ||
441 | " mov lr, r6\n" | ||
442 | " mov pc, r5\n" | ||
443 | " .size kernel_thread_helper, . - kernel_thread_helper\n" | ||
444 | " .popsection"); | ||
445 | |||
446 | #ifdef CONFIG_ARM_UNWIND | ||
447 | extern void kernel_thread_exit(long code); | ||
448 | asm( ".pushsection .text\n" | ||
449 | " .align\n" | ||
450 | " .type kernel_thread_exit, #function\n" | ||
451 | "kernel_thread_exit:\n" | ||
452 | " .fnstart\n" | ||
453 | " .cantunwind\n" | ||
454 | " bl do_exit\n" | ||
455 | " nop\n" | ||
456 | " .fnend\n" | ||
457 | " .size kernel_thread_exit, . - kernel_thread_exit\n" | ||
458 | " .popsection"); | ||
459 | #else | ||
460 | #define kernel_thread_exit do_exit | ||
461 | #endif | ||
462 | |||
463 | /* | ||
464 | * Create a kernel thread. | ||
465 | */ | ||
466 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
467 | { | ||
468 | struct pt_regs regs; | ||
469 | |||
470 | memset(®s, 0, sizeof(regs)); | ||
471 | |||
472 | regs.ARM_r4 = (unsigned long)arg; | ||
473 | regs.ARM_r5 = (unsigned long)fn; | ||
474 | regs.ARM_r6 = (unsigned long)kernel_thread_exit; | ||
475 | regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE; | ||
476 | regs.ARM_pc = (unsigned long)kernel_thread_helper; | ||
477 | regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT; | ||
478 | |||
479 | return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
480 | } | ||
481 | EXPORT_SYMBOL(kernel_thread); | ||
482 | |||
483 | unsigned long get_wchan(struct task_struct *p) | 434 | unsigned long get_wchan(struct task_struct *p) |
484 | { | 435 | { |
485 | struct stackframe frame; | 436 | struct stackframe frame; |