aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2006-12-03 12:51:14 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-12-03 12:52:22 -0500
commitafe4b25e7d9260d85fccb2d13c9933a987bdfc8a (patch)
tree9b603e52ef91531089b45e5860e89d91d2e01565
parentf5236225a3858b505221a59233af1f1158be9139 (diff)
[ARM] 3881/4: xscale: clean up cp0/cp1 handling
XScale cores either have a DSP coprocessor (which contains a single 40 bit accumulator register), or an iWMMXt coprocessor (which contains eight 64 bit registers.) Because of the small amount of state in the DSP coprocessor, access to the DSP coprocessor (CP0) is always enabled, and DSP context switching is done unconditionally on every task switch. Access to the iWMMXt coprocessor (CP0/CP1) is enabled only when an iWMMXt instruction is first issued, and iWMMXt context switching is done lazily. CONFIG_IWMMXT is supposed to mean 'the cpu we will be running on will have iWMMXt support', but boards are supposed to select this config symbol by hand, and at least one pxa27x board doesn't get this right, so on that board, proc-xscale.S will incorrectly assume that we have a DSP coprocessor, enable CP0 on boot, and we will then only save the first iWMMXt register (wR0) on context switches, which is Bad. This patch redefines CONFIG_IWMMXT as 'the cpu we will be running on might have iWMMXt support, and we will enable iWMMXt context switching if it does.' This means that with this patch, running a CONFIG_IWMMXT=n kernel on an iWMMXt-capable CPU will no longer potentially corrupt iWMMXt state over context switches, and running a CONFIG_IWMMXT=y kernel on a non-iWMMXt capable CPU will still do DSP context save/restore. These changes should make iWMMXt work on PXA3xx, and as a side effect, enable proper acc0 save/restore on non-iWMMXt capable xsc3 cores such as IOP13xx and IXP23xx (which will not have CONFIG_CPU_XSCALE defined), as well as setting and using HWCAP_IWMMXT properly. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Acked-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/Kconfig8
-rw-r--r--arch/arm/kernel/Makefile4
-rw-r--r--arch/arm/kernel/entry-armv.S9
-rw-r--r--arch/arm/kernel/iwmmxt-notifier.c63
-rw-r--r--arch/arm/kernel/setup.c3
-rw-r--r--arch/arm/kernel/xscale-cp0.c179
-rw-r--r--arch/arm/mach-pxa/Kconfig8
-rw-r--r--arch/arm/mach-pxa/pm.c3
-rw-r--r--arch/arm/mm/proc-xscale.S9
-rw-r--r--include/asm-arm/elf.h48
10 files changed, 210 insertions, 124 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ce00c570459d..7be67ef4b84f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -374,6 +374,14 @@ config PLAT_IOP
374 374
375source arch/arm/mm/Kconfig 375source arch/arm/mm/Kconfig
376 376
377config IWMMXT
378 bool "Enable iWMMXt support"
379 depends CPU_XSCALE || CPU_XSC3
380 default y if PXA27x
381 help
382 Enable support for iWMMXt context switching at run time if
383 running on a CPU that supports it.
384
377# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER 385# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
378config XSCALE_PMU 386config XSCALE_PMU
379 bool 387 bool
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 1320a0efca73..ab06a86e85d5 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -24,7 +24,9 @@ obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
24obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o 24obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
25AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 25AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
26 26
27obj-$(CONFIG_IWMMXT) += iwmmxt.o iwmmxt-notifier.o 27obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o
28obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o
29obj-$(CONFIG_IWMMXT) += iwmmxt.o
28AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt 30AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
29 31
30ifneq ($(CONFIG_ARCH_EBSA110),y) 32ifneq ($(CONFIG_ARCH_EBSA110),y)
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index bd623b73445f..2db42b18f53f 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -589,10 +589,6 @@ ENTRY(__switch_to)
589 strex r5, r4, [ip] @ Clear exclusive monitor 589 strex r5, r4, [ip] @ Clear exclusive monitor
590#endif 590#endif
591#endif 591#endif
592#if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT)
593 mra r4, r5, acc0
594 stmia ip, {r4, r5}
595#endif
596#if defined(CONFIG_HAS_TLS_REG) 592#if defined(CONFIG_HAS_TLS_REG)
597 mcr p15, 0, r3, c13, c0, 3 @ set TLS register 593 mcr p15, 0, r3, c13, c0, 3 @ set TLS register
598#elif !defined(CONFIG_TLS_REG_EMUL) 594#elif !defined(CONFIG_TLS_REG_EMUL)
@@ -602,11 +598,6 @@ ENTRY(__switch_to)
602#ifdef CONFIG_MMU 598#ifdef CONFIG_MMU
603 mcr p15, 0, r6, c3, c0, 0 @ Set domain register 599 mcr p15, 0, r6, c3, c0, 0 @ Set domain register
604#endif 600#endif
605#if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT)
606 add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra
607 ldmib r4, {r4, r5}
608 mar acc0, r4, r5
609#endif
610 mov r5, r0 601 mov r5, r0
611 add r4, r2, #TI_CPU_SAVE 602 add r4, r2, #TI_CPU_SAVE
612 ldr r0, =thread_notify_head 603 ldr r0, =thread_notify_head
diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c
deleted file mode 100644
index 0d1a1db40062..000000000000
--- a/arch/arm/kernel/iwmmxt-notifier.c
+++ /dev/null
@@ -1,63 +0,0 @@
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/types.h>
19#include <linux/kernel.h>
20#include <linux/signal.h>
21#include <linux/sched.h>
22#include <linux/init.h>
23#include <asm/thread_notify.h>
24#include <asm/io.h>
25
26static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
27{
28 struct thread_info *thread = t;
29
30 switch (cmd) {
31 case THREAD_NOTIFY_FLUSH:
32 /*
33 * flush_thread() zeroes thread->fpstate, so no need
34 * to do anything here.
35 *
36 * FALLTHROUGH: Ensure we don't try to overwrite our newly
37 * initialised state information on the first fault.
38 */
39
40 case THREAD_NOTIFY_RELEASE:
41 iwmmxt_task_release(thread);
42 break;
43
44 case THREAD_NOTIFY_SWITCH:
45 iwmmxt_task_switch(thread);
46 break;
47 }
48
49 return NOTIFY_DONE;
50}
51
52static struct notifier_block iwmmxt_notifier_block = {
53 .notifier_call = iwmmxt_do,
54};
55
56static int __init iwmmxt_init(void)
57{
58 thread_register_notifier(&iwmmxt_notifier_block);
59
60 return 0;
61}
62
63late_initcall(iwmmxt_init);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 29efc9f82057..6f12d2686aaf 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -357,9 +357,6 @@ static void __init setup_processor(void)
357#ifndef CONFIG_VFP 357#ifndef CONFIG_VFP
358 elf_hwcap &= ~HWCAP_VFP; 358 elf_hwcap &= ~HWCAP_VFP;
359#endif 359#endif
360#ifndef CONFIG_IWMMXT
361 elf_hwcap &= ~HWCAP_IWMMXT;
362#endif
363 360
364 cpu_proc_init(); 361 cpu_proc_init();
365} 362}
diff --git a/arch/arm/kernel/xscale-cp0.c b/arch/arm/kernel/xscale-cp0.c
new file mode 100644
index 000000000000..180000bfdc8f
--- /dev/null
+++ b/arch/arm/kernel/xscale-cp0.c
@@ -0,0 +1,179 @@
1/*
2 * linux/arch/arm/kernel/xscale-cp0.c
3 *
4 * XScale DSP and iWMMXt coprocessor context switching and handling
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <linux/signal.h>
15#include <linux/sched.h>
16#include <linux/init.h>
17#include <asm/thread_notify.h>
18#include <asm/io.h>
19
20static inline void dsp_save_state(u32 *state)
21{
22 __asm__ __volatile__ (
23 "mrrc p0, 0, %0, %1, c0\n"
24 : "=r" (state[0]), "=r" (state[1]));
25}
26
27static inline void dsp_load_state(u32 *state)
28{
29 __asm__ __volatile__ (
30 "mcrr p0, 0, %0, %1, c0\n"
31 : : "r" (state[0]), "r" (state[1]));
32}
33
34static int dsp_do(struct notifier_block *self, unsigned long cmd, void *t)
35{
36 struct thread_info *thread = t;
37
38 switch (cmd) {
39 case THREAD_NOTIFY_FLUSH:
40 thread->cpu_context.extra[0] = 0;
41 thread->cpu_context.extra[1] = 0;
42 break;
43
44 case THREAD_NOTIFY_SWITCH:
45 dsp_save_state(current_thread_info()->cpu_context.extra);
46 dsp_load_state(thread->cpu_context.extra);
47 break;
48 }
49
50 return NOTIFY_DONE;
51}
52
53static struct notifier_block dsp_notifier_block = {
54 .notifier_call = dsp_do,
55};
56
57
58#ifdef CONFIG_IWMMXT
59static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
60{
61 struct thread_info *thread = t;
62
63 switch (cmd) {
64 case THREAD_NOTIFY_FLUSH:
65 /*
66 * flush_thread() zeroes thread->fpstate, so no need
67 * to do anything here.
68 *
69 * FALLTHROUGH: Ensure we don't try to overwrite our newly
70 * initialised state information on the first fault.
71 */
72
73 case THREAD_NOTIFY_RELEASE:
74 iwmmxt_task_release(thread);
75 break;
76
77 case THREAD_NOTIFY_SWITCH:
78 iwmmxt_task_switch(thread);
79 break;
80 }
81
82 return NOTIFY_DONE;
83}
84
85static struct notifier_block iwmmxt_notifier_block = {
86 .notifier_call = iwmmxt_do,
87};
88#endif
89
90
91static u32 __init xscale_cp_access_read(void)
92{
93 u32 value;
94
95 __asm__ __volatile__ (
96 "mrc p15, 0, %0, c15, c1, 0\n\t"
97 : "=r" (value));
98
99 return value;
100}
101
102static void __init xscale_cp_access_write(u32 value)
103{
104 u32 temp;
105
106 __asm__ __volatile__ (
107 "mcr p15, 0, %1, c15, c1, 0\n\t"
108 "mrc p15, 0, %0, c15, c1, 0\n\t"
109 "mov %0, %0\n\t"
110 "sub pc, pc, #4\n\t"
111 : "=r" (temp) : "r" (value));
112}
113
114/*
115 * Detect whether we have a MAC coprocessor (40 bit register) or an
116 * iWMMXt coprocessor (64 bit registers) by loading 00000100:00000000
117 * into a coprocessor register and reading it back, and checking
118 * whether the upper word survived intact.
119 */
120static int __init cpu_has_iwmmxt(void)
121{
122 u32 lo;
123 u32 hi;
124
125 /*
126 * This sequence is interpreted by the DSP coprocessor as:
127 * mar acc0, %2, %3
128 * mra %0, %1, acc0
129 *
130 * And by the iWMMXt coprocessor as:
131 * tmcrr wR0, %2, %3
132 * tmrrc %0, %1, wR0
133 */
134 __asm__ __volatile__ (
135 "mcrr p0, 0, %2, %3, c0\n"
136 "mrrc p0, 0, %0, %1, c0\n"
137 : "=r" (lo), "=r" (hi)
138 : "r" (0), "r" (0x100));
139
140 return !!hi;
141}
142
143
144/*
145 * If we detect that the CPU has iWMMXt (and CONFIG_IWMMXT=y), we
146 * disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
147 * switch code handle iWMMXt context switching. If on the other
148 * hand the CPU has a DSP coprocessor, we keep access to CP0 enabled
149 * all the time, and save/restore acc0 on context switch in non-lazy
150 * fashion.
151 */
152static int __init xscale_cp0_init(void)
153{
154 u32 cp_access;
155
156 cp_access = xscale_cp_access_read() & ~3;
157 xscale_cp_access_write(cp_access | 1);
158
159 if (cpu_has_iwmmxt()) {
160#ifndef CONFIG_IWMMXT
161 printk(KERN_WARNING "CAUTION: XScale iWMMXt coprocessor "
162 "detected, but kernel support is missing.\n");
163#else
164 printk(KERN_INFO "XScale iWMMXt coprocessor detected.\n");
165 elf_hwcap |= HWCAP_IWMMXT;
166 thread_register_notifier(&iwmmxt_notifier_block);
167#endif
168 } else {
169 printk(KERN_INFO "XScale DSP coprocessor detected.\n");
170 thread_register_notifier(&dsp_notifier_block);
171 cp_access |= 1;
172 }
173
174 xscale_cp_access_write(cp_access);
175
176 return 0;
177}
178
179late_initcall(xscale_cp0_init);
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 03d07cae26c8..9e3d0bdcba07 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -13,12 +13,10 @@ config ARCH_LUBBOCK
13config MACH_LOGICPD_PXA270 13config MACH_LOGICPD_PXA270
14 bool "LogicPD PXA270 Card Engine Development Platform" 14 bool "LogicPD PXA270 Card Engine Development Platform"
15 select PXA27x 15 select PXA27x
16 select IWMMXT
17 16
18config MACH_MAINSTONE 17config MACH_MAINSTONE
19 bool "Intel HCDDBBVA0 Development Platform" 18 bool "Intel HCDDBBVA0 Development Platform"
20 select PXA27x 19 select PXA27x
21 select IWMMXT
22 20
23config ARCH_PXA_IDP 21config ARCH_PXA_IDP
24 bool "Accelent Xscale IDP" 22 bool "Accelent Xscale IDP"
@@ -53,7 +51,6 @@ config PXA_SHARPSL_25x
53config PXA_SHARPSL_27x 51config PXA_SHARPSL_27x
54 bool "Sharp PXA270 models (SL-Cxx00)" 52 bool "Sharp PXA270 models (SL-Cxx00)"
55 select PXA27x 53 select PXA27x
56 select IWMMXT
57 54
58endchoice 55endchoice
59 56
@@ -129,11 +126,6 @@ config PXA27x
129 help 126 help
130 Select code specific to PXA27x variants 127 Select code specific to PXA27x variants
131 128
132config IWMMXT
133 bool
134 help
135 Enable support for iWMMXt
136
137config PXA_SHARP_C7xx 129config PXA_SHARP_C7xx
138 bool 130 bool
139 select PXA_SSP 131 select PXA_SSP
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 2112c414f0e2..b4d8276d6050 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -83,7 +83,8 @@ int pxa_pm_enter(suspend_state_t state)
83 83
84#ifdef CONFIG_IWMMXT 84#ifdef CONFIG_IWMMXT
85 /* force any iWMMXt context to ram **/ 85 /* force any iWMMXt context to ram **/
86 iwmmxt_task_disable(NULL); 86 if (elf_hwcap & HWCAP_IWMMXT)
87 iwmmxt_task_disable(NULL);
87#endif 88#endif
88 89
89 /* preserve current time */ 90 /* preserve current time */
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 906e9de7f83e..cc1004b3e511 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -491,12 +491,7 @@ __xscale_setup:
491 mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB 491 mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB
492 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer 492 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
493 mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs 493 mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs
494#ifdef CONFIG_IWMMXT 494 mov r0, #1 << 6 @ cp6 for IOP3xx and Bulverde
495 mov r0, #0 @ initially disallow access to CP0/CP1
496#else
497 mov r0, #1 @ Allow access to CP0
498#endif
499 orr r0, r0, #1 << 6 @ cp6 for IOP3xx and Bulverde
500 orr r0, r0, #1 << 13 @ Its undefined whether this 495 orr r0, r0, #1 << 13 @ Its undefined whether this
501 mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes 496 mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes
502 497
@@ -909,7 +904,7 @@ __pxa270_proc_info:
909 b __xscale_setup 904 b __xscale_setup
910 .long cpu_arch_name 905 .long cpu_arch_name
911 .long cpu_elf_name 906 .long cpu_elf_name
912 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_IWMMXT 907 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
913 .long cpu_pxa270_name 908 .long cpu_pxa270_name
914 .long xscale_processor_functions 909 .long xscale_processor_functions
915 .long v4wbi_tlb_fns 910 .long v4wbi_tlb_fns
diff --git a/include/asm-arm/elf.h b/include/asm-arm/elf.h
index f3929307a56b..642382d2c9f0 100644
--- a/include/asm-arm/elf.h
+++ b/include/asm-arm/elf.h
@@ -114,40 +114,24 @@ extern char elf_platform[];
114 have no such handler. */ 114 have no such handler. */
115#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 115#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0
116 116
117#ifndef CONFIG_IWMMXT
118
119/* Old NetWinder binaries were compiled in such a way that the iBCS
120 heuristic always trips on them. Until these binaries become uncommon
121 enough not to care, don't trust the `ibcs' flag here. In any case
122 there is no other ELF system currently supported by iBCS.
123 @@ Could print a warning message to encourage users to upgrade. */
124#define SET_PERSONALITY(ex,ibcs2) \
125 set_personality(((ex).e_flags & EF_ARM_APCS26 ? PER_LINUX : PER_LINUX_32BIT))
126
127#else
128
129/* 117/*
130 * All iWMMXt capable CPUs don't support 26-bit mode. Yet they can run 118 * Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0
131 * legacy binaries which used to contain FPA11 floating point instructions 119 * and CP1, we only enable access to the iWMMXt coprocessor if the
132 * that have always been emulated by the kernel. PFA11 and iWMMXt overlap 120 * binary is EABI or softfloat (and thus, guaranteed not to use
133 * on coprocessor 1 space though. We therefore must decide if given task 121 * FPA instructions.)
134 * is allowed to use CP 0 and 1 for iWMMXt, or if they should be blocked
135 * at all times for the prefetch exception handler to catch FPA11 opcodes
136 * and emulate them. The best indication to discriminate those two cases
137 * is the SOFT_FLOAT flag in the ELF header.
138 */ 122 */
139 123#define SET_PERSONALITY(ex, ibcs2) \
140#define SET_PERSONALITY(ex,ibcs2) \ 124 do { \
141do { \ 125 if ((ex).e_flags & EF_ARM_APCS26) { \
142 set_personality(PER_LINUX_32BIT); \ 126 set_personality(PER_LINUX); \
143 if (((ex).e_flags & EF_ARM_EABI_MASK) || \ 127 } else { \
144 ((ex).e_flags & EF_ARM_SOFT_FLOAT)) \ 128 set_personality(PER_LINUX_32BIT); \
145 set_thread_flag(TIF_USING_IWMMXT); \ 129 if (elf_hwcap & HWCAP_IWMMXT && (ex).e_flags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) \
146 else \ 130 set_thread_flag(TIF_USING_IWMMXT); \
147 clear_thread_flag(TIF_USING_IWMMXT); \ 131 else \
148} while (0) 132 clear_thread_flag(TIF_USING_IWMMXT); \
149 133 } \
150#endif 134 } while (0)
151 135
152#endif 136#endif
153 137