diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2006-06-21 08:31:52 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-06-22 05:24:18 -0400 |
commit | d6551e884cf66de072b81f8b6d23259462c40baf (patch) | |
tree | fd8af193bd045e4b16ce911d392d7ffd109d7284 /arch/arm/kernel | |
parent | 52ab3f3dc711eeccbfbcc5d4f5c5d9b9ff59650f (diff) |
[ARM] Add thread_notify infrastructure
Some machine classes need to allow VFP support to be built into the
kernel, but still allow the kernel to run even though VFP isn't
present. Unfortunately, the kernel hard-codes VFP instructions
into the thread switch, which prevents this being run-time selectable.
Solve this by introducing a notifier which things such as VFP can
hook into to be informed of events which affect the VFP subsystem
(eg, creation and destruction of threads, switches between threads.)
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 24 | ||||
-rw-r--r-- | arch/arm/kernel/iwmmxt.S | 2 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 24 |
3 files changed, 22 insertions, 28 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index ab8e600c18c8..86c92523a346 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/glue.h> | 20 | #include <asm/glue.h> |
21 | #include <asm/vfpmacros.h> | 21 | #include <asm/vfpmacros.h> |
22 | #include <asm/arch/entry-macro.S> | 22 | #include <asm/arch/entry-macro.S> |
23 | #include <asm/thread_notify.h> | ||
23 | 24 | ||
24 | #include "entry-header.S" | 25 | #include "entry-header.S" |
25 | 26 | ||
@@ -560,10 +561,8 @@ ENTRY(__switch_to) | |||
560 | add ip, r1, #TI_CPU_SAVE | 561 | add ip, r1, #TI_CPU_SAVE |
561 | ldr r3, [r2, #TI_TP_VALUE] | 562 | ldr r3, [r2, #TI_TP_VALUE] |
562 | stmia ip!, {r4 - sl, fp, sp, lr} @ Store most regs on stack | 563 | stmia ip!, {r4 - sl, fp, sp, lr} @ Store most regs on stack |
563 | #ifndef CONFIG_MMU | 564 | #ifdef CONFIG_MMU |
564 | add r2, r2, #TI_CPU_DOMAIN | 565 | ldr r6, [r2, #TI_CPU_DOMAIN] |
565 | #else | ||
566 | ldr r6, [r2, #TI_CPU_DOMAIN]! | ||
567 | #endif | 566 | #endif |
568 | #if __LINUX_ARM_ARCH__ >= 6 | 567 | #if __LINUX_ARM_ARCH__ >= 6 |
569 | #ifdef CONFIG_CPU_32v6K | 568 | #ifdef CONFIG_CPU_32v6K |
@@ -585,21 +584,20 @@ ENTRY(__switch_to) | |||
585 | #ifdef CONFIG_MMU | 584 | #ifdef CONFIG_MMU |
586 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register | 585 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register |
587 | #endif | 586 | #endif |
588 | #ifdef CONFIG_VFP | ||
589 | @ Always disable VFP so we can lazily save/restore the old | ||
590 | @ state. This occurs in the context of the previous thread. | ||
591 | VFPFMRX r4, FPEXC | ||
592 | bic r4, r4, #FPEXC_ENABLE | ||
593 | VFPFMXR FPEXC, r4 | ||
594 | #endif | ||
595 | #if defined(CONFIG_IWMMXT) | 587 | #if defined(CONFIG_IWMMXT) |
596 | bl iwmmxt_task_switch | 588 | bl iwmmxt_task_switch |
597 | #elif defined(CONFIG_CPU_XSCALE) | 589 | #elif defined(CONFIG_CPU_XSCALE) |
598 | add r4, r2, #40 @ cpu_context_save->extra | 590 | add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra |
599 | ldmib r4, {r4, r5} | 591 | ldmib r4, {r4, r5} |
600 | mar acc0, r4, r5 | 592 | mar acc0, r4, r5 |
601 | #endif | 593 | #endif |
602 | ldmib r2, {r4 - sl, fp, sp, pc} @ Load all regs saved previously | 594 | mov r5, r0 |
595 | add r4, r2, #TI_CPU_SAVE | ||
596 | ldr r0, =thread_notify_head | ||
597 | mov r1, #THREAD_NOTIFY_SWITCH | ||
598 | bl atomic_notifier_call_chain | ||
599 | mov r0, r5 | ||
600 | ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously | ||
603 | 601 | ||
604 | __INIT | 602 | __INIT |
605 | 603 | ||
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index 24c7b0477a09..af9e0ae952d5 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S | |||
@@ -285,7 +285,7 @@ ENTRY(iwmmxt_task_switch) | |||
285 | bne 1f @ yes: block them for next task | 285 | bne 1f @ yes: block them for next task |
286 | 286 | ||
287 | ldr r5, =concan_owner | 287 | ldr r5, =concan_owner |
288 | add r6, r2, #(TI_IWMMXT_STATE - TI_CPU_DOMAIN) @ get next task Concan save area | 288 | add r6, r2, #TI_IWMMXT_STATE @ get next task Concan save area |
289 | ldr r5, [r5] @ get current Concan owner | 289 | ldr r5, [r5] @ get current Concan owner |
290 | teq r5, r6 @ next task owns it? | 290 | teq r5, r6 @ next task owns it? |
291 | movne pc, lr @ no: leave Concan disabled | 291 | movne pc, lr @ no: leave Concan disabled |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 17c38dbf2f3c..e1c77ee885a7 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/leds.h> | 33 | #include <asm/leds.h> |
34 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
35 | #include <asm/system.h> | 35 | #include <asm/system.h> |
36 | #include <asm/thread_notify.h> | ||
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | #include <asm/mach/time.h> | 38 | #include <asm/mach/time.h> |
38 | 39 | ||
@@ -338,13 +339,9 @@ void exit_thread(void) | |||
338 | { | 339 | { |
339 | } | 340 | } |
340 | 341 | ||
341 | static void default_fp_init(union fp_state *fp) | 342 | ATOMIC_NOTIFIER_HEAD(thread_notify_head); |
342 | { | ||
343 | memset(fp, 0, sizeof(union fp_state)); | ||
344 | } | ||
345 | 343 | ||
346 | void (*fp_init)(union fp_state *) = default_fp_init; | 344 | EXPORT_SYMBOL_GPL(thread_notify_head); |
347 | EXPORT_SYMBOL(fp_init); | ||
348 | 345 | ||
349 | void flush_thread(void) | 346 | void flush_thread(void) |
350 | { | 347 | { |
@@ -353,22 +350,21 @@ void flush_thread(void) | |||
353 | 350 | ||
354 | memset(thread->used_cp, 0, sizeof(thread->used_cp)); | 351 | memset(thread->used_cp, 0, sizeof(thread->used_cp)); |
355 | memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); | 352 | memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); |
353 | memset(&thread->fpstate, 0, sizeof(union fp_state)); | ||
354 | |||
355 | thread_notify(THREAD_NOTIFY_FLUSH, thread); | ||
356 | #if defined(CONFIG_IWMMXT) | 356 | #if defined(CONFIG_IWMMXT) |
357 | iwmmxt_task_release(thread); | 357 | iwmmxt_task_release(thread); |
358 | #endif | 358 | #endif |
359 | fp_init(&thread->fpstate); | ||
360 | #if defined(CONFIG_VFP) | ||
361 | vfp_flush_thread(&thread->vfpstate); | ||
362 | #endif | ||
363 | } | 359 | } |
364 | 360 | ||
365 | void release_thread(struct task_struct *dead_task) | 361 | void release_thread(struct task_struct *dead_task) |
366 | { | 362 | { |
367 | #if defined(CONFIG_VFP) | 363 | struct thread_info *thread = task_thread_info(dead_task); |
368 | vfp_release_thread(&task_thread_info(dead_task)->vfpstate); | 364 | |
369 | #endif | 365 | thread_notify(THREAD_NOTIFY_RELEASE, thread); |
370 | #if defined(CONFIG_IWMMXT) | 366 | #if defined(CONFIG_IWMMXT) |
371 | iwmmxt_task_release(task_thread_info(dead_task)); | 367 | iwmmxt_task_release(thread); |
372 | #endif | 368 | #endif |
373 | } | 369 | } |
374 | 370 | ||