diff options
-rw-r--r-- | arch/arm/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 4 | ||||
-rw-r--r-- | arch/arm/kernel/iwmmxt-notifier.c | 64 | ||||
-rw-r--r-- | arch/arm/kernel/iwmmxt.S | 27 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 6 | ||||
-rw-r--r-- | include/asm-arm/thread_info.h | 1 |
6 files changed, 79 insertions, 25 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 7cffbaef064b..f0c0cdb1c183 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -25,7 +25,7 @@ obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | |||
25 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 25 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
26 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 | 26 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 |
27 | 27 | ||
28 | obj-$(CONFIG_IWMMXT) += iwmmxt.o | 28 | obj-$(CONFIG_IWMMXT) += iwmmxt.o iwmmxt-notifier.o |
29 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt | 29 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt |
30 | 30 | ||
31 | ifneq ($(CONFIG_ARCH_EBSA110),y) | 31 | ifneq ($(CONFIG_ARCH_EBSA110),y) |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 6423a38839b8..0e8aeaf9ff1d 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -590,9 +590,7 @@ ENTRY(__switch_to) | |||
590 | #ifdef CONFIG_MMU | 590 | #ifdef CONFIG_MMU |
591 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register | 591 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register |
592 | #endif | 592 | #endif |
593 | #if defined(CONFIG_IWMMXT) | 593 | #if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT) |
594 | bl iwmmxt_task_switch | ||
595 | #elif defined(CONFIG_CPU_XSCALE) | ||
596 | add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra | 594 | add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra |
597 | ldmib r4, {r4, r5} | 595 | ldmib r4, {r4, r5} |
598 | mar acc0, r4, r5 | 596 | mar acc0, r4, r5 |
diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c new file mode 100644 index 000000000000..44a86c33796e --- /dev/null +++ b/arch/arm/kernel/iwmmxt-notifier.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/iwmmxt-notifier.c | ||
3 | * | ||
4 | * XScale iWMMXt (Concan) context switching and handling | ||
5 | * | ||
6 | * Initial code: | ||
7 | * Copyright (c) 2003, Intel Corporation | ||
8 | * | ||
9 | * Full lazy switching support, optimizations and more, by Nicolas Pitre | ||
10 | * Copyright (c) 2003-2004, MontaVista Software, Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/signal.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <asm/thread_notify.h> | ||
25 | #include <asm/io.h> | ||
26 | |||
27 | static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t) | ||
28 | { | ||
29 | struct thread_info *thread = t; | ||
30 | |||
31 | switch (cmd) { | ||
32 | case THREAD_NOTIFY_FLUSH: | ||
33 | /* | ||
34 | * flush_thread() zeroes thread->fpstate, so no need | ||
35 | * to do anything here. | ||
36 | * | ||
37 | * FALLTHROUGH: Ensure we don't try to overwrite our newly | ||
38 | * initialised state information on the first fault. | ||
39 | */ | ||
40 | |||
41 | case THREAD_NOTIFY_RELEASE: | ||
42 | iwmmxt_task_release(thread); | ||
43 | break; | ||
44 | |||
45 | case THREAD_NOTIFY_SWITCH: | ||
46 | iwmmxt_task_switch(thread); | ||
47 | break; | ||
48 | } | ||
49 | |||
50 | return NOTIFY_DONE; | ||
51 | } | ||
52 | |||
53 | static struct notifier_block iwmmxt_notifier_block = { | ||
54 | .notifier_call = iwmmxt_do, | ||
55 | }; | ||
56 | |||
57 | static int __init iwmmxt_init(void) | ||
58 | { | ||
59 | thread_register_notifier(&iwmmxt_notifier_block); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | late_initcall(iwmmxt_init); | ||
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index a3bae95e536c..b63b528f22a6 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S | |||
@@ -271,30 +271,27 @@ ENTRY(iwmmxt_task_restore) | |||
271 | /* | 271 | /* |
272 | * Concan handling on task switch | 272 | * Concan handling on task switch |
273 | * | 273 | * |
274 | * r0 = previous task_struct pointer (must be preserved) | 274 | * r0 = next thread_info pointer |
275 | * r1 = previous thread_info pointer | ||
276 | * r2 = next thread_info pointer (must be preserved) | ||
277 | * | 275 | * |
278 | * Called only from __switch_to with task preemption disabled. | 276 | * Called only from the iwmmxt notifier with task preemption disabled. |
279 | * No need to care about preserving r4 and above. | ||
280 | */ | 277 | */ |
281 | ENTRY(iwmmxt_task_switch) | 278 | ENTRY(iwmmxt_task_switch) |
282 | 279 | ||
283 | mrc p15, 0, r4, c15, c1, 0 | 280 | mrc p15, 0, r1, c15, c1, 0 |
284 | tst r4, #0x3 @ CP0 and CP1 accessible? | 281 | tst r1, #0x3 @ CP0 and CP1 accessible? |
285 | bne 1f @ yes: block them for next task | 282 | bne 1f @ yes: block them for next task |
286 | 283 | ||
287 | ldr r5, =concan_owner | 284 | ldr r2, =concan_owner |
288 | add r6, r2, #TI_IWMMXT_STATE @ get next task Concan save area | 285 | add r3, r0, #TI_IWMMXT_STATE @ get next task Concan save area |
289 | ldr r5, [r5] @ get current Concan owner | 286 | ldr r2, [r2] @ get current Concan owner |
290 | teq r5, r6 @ next task owns it? | 287 | teq r2, r3 @ next task owns it? |
291 | movne pc, lr @ no: leave Concan disabled | 288 | movne pc, lr @ no: leave Concan disabled |
292 | 289 | ||
293 | 1: eor r4, r4, #3 @ flip Concan access | 290 | 1: eor r1, r1, #3 @ flip Concan access |
294 | mcr p15, 0, r4, c15, c1, 0 | 291 | mcr p15, 0, r1, c15, c1, 0 |
295 | 292 | ||
296 | mrc p15, 0, r4, c2, c0, 0 | 293 | mrc p15, 0, r1, c2, c0, 0 |
297 | sub pc, lr, r4, lsr #32 @ cpwait and return | 294 | sub pc, lr, r1, lsr #32 @ cpwait and return |
298 | 295 | ||
299 | /* | 296 | /* |
300 | * Remove Concan ownership of given task | 297 | * Remove Concan ownership of given task |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index e1c77ee885a7..b5773a2549ee 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -353,9 +353,6 @@ void flush_thread(void) | |||
353 | memset(&thread->fpstate, 0, sizeof(union fp_state)); | 353 | memset(&thread->fpstate, 0, sizeof(union fp_state)); |
354 | 354 | ||
355 | thread_notify(THREAD_NOTIFY_FLUSH, thread); | 355 | thread_notify(THREAD_NOTIFY_FLUSH, thread); |
356 | #if defined(CONFIG_IWMMXT) | ||
357 | iwmmxt_task_release(thread); | ||
358 | #endif | ||
359 | } | 356 | } |
360 | 357 | ||
361 | void release_thread(struct task_struct *dead_task) | 358 | void release_thread(struct task_struct *dead_task) |
@@ -363,9 +360,6 @@ void release_thread(struct task_struct *dead_task) | |||
363 | struct thread_info *thread = task_thread_info(dead_task); | 360 | struct thread_info *thread = task_thread_info(dead_task); |
364 | 361 | ||
365 | thread_notify(THREAD_NOTIFY_RELEASE, thread); | 362 | thread_notify(THREAD_NOTIFY_RELEASE, thread); |
366 | #if defined(CONFIG_IWMMXT) | ||
367 | iwmmxt_task_release(thread); | ||
368 | #endif | ||
369 | } | 363 | } |
370 | 364 | ||
371 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 365 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h index c46b5c84275f..c52e0bf75353 100644 --- a/include/asm-arm/thread_info.h +++ b/include/asm-arm/thread_info.h | |||
@@ -111,6 +111,7 @@ extern void iwmmxt_task_disable(struct thread_info *); | |||
111 | extern void iwmmxt_task_copy(struct thread_info *, void *); | 111 | extern void iwmmxt_task_copy(struct thread_info *, void *); |
112 | extern void iwmmxt_task_restore(struct thread_info *, void *); | 112 | extern void iwmmxt_task_restore(struct thread_info *, void *); |
113 | extern void iwmmxt_task_release(struct thread_info *); | 113 | extern void iwmmxt_task_release(struct thread_info *); |
114 | extern void iwmmxt_task_switch(struct thread_info *); | ||
114 | 115 | ||
115 | #endif | 116 | #endif |
116 | 117 | ||