Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / arch / arm / kernel / iwmmxt.S
1 /*
2  *  linux/arch/arm/kernel/iwmmxt.S
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/linkage.h>
18 #include <asm/ptrace.h>
19 #include <asm/thread_info.h>
20 #include <asm/asm-offsets.h>
21 #include <asm/assembler.h>
22
23 #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
24 #define PJ4(code...)            code
25 #define XSC(code...)
26 #elif defined(CONFIG_CPU_MOHAWK) || \
27         defined(CONFIG_CPU_XSC3) || \
28         defined(CONFIG_CPU_XSCALE)
29 #define PJ4(code...)
30 #define XSC(code...)            code
31 #else
32 #error "Unsupported iWMMXt architecture"
33 #endif
34
35 #define MMX_WR0                 (0x00)
36 #define MMX_WR1                 (0x08)
37 #define MMX_WR2                 (0x10)
38 #define MMX_WR3                 (0x18)
39 #define MMX_WR4                 (0x20)
40 #define MMX_WR5                 (0x28)
41 #define MMX_WR6                 (0x30)
42 #define MMX_WR7                 (0x38)
43 #define MMX_WR8                 (0x40)
44 #define MMX_WR9                 (0x48)
45 #define MMX_WR10                (0x50)
46 #define MMX_WR11                (0x58)
47 #define MMX_WR12                (0x60)
48 #define MMX_WR13                (0x68)
49 #define MMX_WR14                (0x70)
50 #define MMX_WR15                (0x78)
51 #define MMX_WCSSF               (0x80)
52 #define MMX_WCASF               (0x84)
53 #define MMX_WCGR0               (0x88)
54 #define MMX_WCGR1               (0x8C)
55 #define MMX_WCGR2               (0x90)
56 #define MMX_WCGR3               (0x94)
57
58 #define MMX_SIZE                (0x98)
59
60         .text
61         .arm
62
63 /*
64  * Lazy switching of Concan coprocessor context
65  *
66  * r10 = struct thread_info pointer
67  * r9  = ret_from_exception
68  * lr  = undefined instr exit
69  *
70  * called from prefetch exception handler with interrupts enabled
71  */
72
73 ENTRY(iwmmxt_task_enable)
74         inc_preempt_count r10, r3
75
76         XSC(mrc p15, 0, r2, c15, c1, 0)
77         PJ4(mrc p15, 0, r2, c1, c0, 2)
78         @ CP0 and CP1 accessible?
79         XSC(tst r2, #0x3)
80         PJ4(tst r2, #0xf)
81         bne     4f                              @ if so no business here
82         @ enable access to CP0 and CP1
83         XSC(orr r2, r2, #0x3)
84         XSC(mcr p15, 0, r2, c15, c1, 0)
85         PJ4(orr r2, r2, #0xf)
86         PJ4(mcr p15, 0, r2, c1, c0, 2)
87
88         ldr     r3, =concan_owner
89         add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
90         ldr     r2, [sp, #60]                   @ current task pc value
91         ldr     r1, [r3]                        @ get current Concan owner
92         str     r0, [r3]                        @ this task now owns Concan regs
93         sub     r2, r2, #4                      @ adjust pc back
94         str     r2, [sp, #60]
95
96         mrc     p15, 0, r2, c2, c0, 0
97         mov     r2, r2                          @ cpwait
98         bl      concan_save
99
100 #ifdef CONFIG_PREEMPT_COUNT
101         get_thread_info r10
102 #endif
103 4:      dec_preempt_count r10, r3
104         ret     r9                              @ normal exit from exception
105
106 concan_save:
107
108         teq     r1, #0                          @ test for last ownership
109         beq     concan_load                     @ no owner, skip save
110
111         tmrc    r2, wCon
112
113         @ CUP? wCx
114         tst     r2, #0x1
115         beq     1f
116
117 concan_dump:
118
119         wstrw   wCSSF, [r1, #MMX_WCSSF]
120         wstrw   wCASF, [r1, #MMX_WCASF]
121         wstrw   wCGR0, [r1, #MMX_WCGR0]
122         wstrw   wCGR1, [r1, #MMX_WCGR1]
123         wstrw   wCGR2, [r1, #MMX_WCGR2]
124         wstrw   wCGR3, [r1, #MMX_WCGR3]
125
126 1:      @ MUP? wRn
127         tst     r2, #0x2
128         beq     2f
129
130         wstrd   wR0,  [r1, #MMX_WR0]
131         wstrd   wR1,  [r1, #MMX_WR1]
132         wstrd   wR2,  [r1, #MMX_WR2]
133         wstrd   wR3,  [r1, #MMX_WR3]
134         wstrd   wR4,  [r1, #MMX_WR4]
135         wstrd   wR5,  [r1, #MMX_WR5]
136         wstrd   wR6,  [r1, #MMX_WR6]
137         wstrd   wR7,  [r1, #MMX_WR7]
138         wstrd   wR8,  [r1, #MMX_WR8]
139         wstrd   wR9,  [r1, #MMX_WR9]
140         wstrd   wR10, [r1, #MMX_WR10]
141         wstrd   wR11, [r1, #MMX_WR11]
142         wstrd   wR12, [r1, #MMX_WR12]
143         wstrd   wR13, [r1, #MMX_WR13]
144         wstrd   wR14, [r1, #MMX_WR14]
145         wstrd   wR15, [r1, #MMX_WR15]
146
147 2:      teq     r0, #0                          @ anything to load?
148         reteq   lr                              @ if not, return
149
150 concan_load:
151
152         @ Load wRn
153         wldrd   wR0,  [r0, #MMX_WR0]
154         wldrd   wR1,  [r0, #MMX_WR1]
155         wldrd   wR2,  [r0, #MMX_WR2]
156         wldrd   wR3,  [r0, #MMX_WR3]
157         wldrd   wR4,  [r0, #MMX_WR4]
158         wldrd   wR5,  [r0, #MMX_WR5]
159         wldrd   wR6,  [r0, #MMX_WR6]
160         wldrd   wR7,  [r0, #MMX_WR7]
161         wldrd   wR8,  [r0, #MMX_WR8]
162         wldrd   wR9,  [r0, #MMX_WR9]
163         wldrd   wR10, [r0, #MMX_WR10]
164         wldrd   wR11, [r0, #MMX_WR11]
165         wldrd   wR12, [r0, #MMX_WR12]
166         wldrd   wR13, [r0, #MMX_WR13]
167         wldrd   wR14, [r0, #MMX_WR14]
168         wldrd   wR15, [r0, #MMX_WR15]
169
170         @ Load wCx
171         wldrw   wCSSF, [r0, #MMX_WCSSF]
172         wldrw   wCASF, [r0, #MMX_WCASF]
173         wldrw   wCGR0, [r0, #MMX_WCGR0]
174         wldrw   wCGR1, [r0, #MMX_WCGR1]
175         wldrw   wCGR2, [r0, #MMX_WCGR2]
176         wldrw   wCGR3, [r0, #MMX_WCGR3]
177
178         @ clear CUP/MUP (only if r1 != 0)
179         teq     r1, #0
180         mov     r2, #0
181         reteq   lr
182
183         tmcr    wCon, r2
184         ret     lr
185
186 ENDPROC(iwmmxt_task_enable)
187
188 /*
189  * Back up Concan regs to save area and disable access to them
190  * (mainly for gdb or sleep mode usage)
191  *
192  * r0 = struct thread_info pointer of target task or NULL for any
193  */
194
195 ENTRY(iwmmxt_task_disable)
196
197         stmfd   sp!, {r4, lr}
198
199         mrs     ip, cpsr
200         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
201         msr     cpsr_c, r2
202
203         ldr     r3, =concan_owner
204         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
205         ldr     r1, [r3]                        @ get current Concan owner
206         teq     r1, #0                          @ any current owner?
207         beq     1f                              @ no: quit
208         teq     r0, #0                          @ any owner?
209         teqne   r1, r2                          @ or specified one?
210         bne     1f                              @ no: quit
211
212         @ enable access to CP0 and CP1
213         XSC(mrc p15, 0, r4, c15, c1, 0)
214         XSC(orr r4, r4, #0x3)
215         XSC(mcr p15, 0, r4, c15, c1, 0)
216         PJ4(mrc p15, 0, r4, c1, c0, 2)
217         PJ4(orr r4, r4, #0xf)
218         PJ4(mcr p15, 0, r4, c1, c0, 2)
219
220         mov     r0, #0                          @ nothing to load
221         str     r0, [r3]                        @ no more current owner
222         mrc     p15, 0, r2, c2, c0, 0
223         mov     r2, r2                          @ cpwait
224         bl      concan_save
225
226         @ disable access to CP0 and CP1
227         XSC(bic r4, r4, #0x3)
228         XSC(mcr p15, 0, r4, c15, c1, 0)
229         PJ4(bic r4, r4, #0xf)
230         PJ4(mcr p15, 0, r4, c1, c0, 2)
231
232         mrc     p15, 0, r2, c2, c0, 0
233         mov     r2, r2                          @ cpwait
234
235 1:      msr     cpsr_c, ip                      @ restore interrupt mode
236         ldmfd   sp!, {r4, pc}
237
238 ENDPROC(iwmmxt_task_disable)
239
240 /*
241  * Copy Concan state to given memory address
242  *
243  * r0 = struct thread_info pointer of target task
244  * r1 = memory address where to store Concan state
245  *
246  * this is called mainly in the creation of signal stack frames
247  */
248
249 ENTRY(iwmmxt_task_copy)
250
251         mrs     ip, cpsr
252         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
253         msr     cpsr_c, r2
254
255         ldr     r3, =concan_owner
256         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
257         ldr     r3, [r3]                        @ get current Concan owner
258         teq     r2, r3                          @ does this task own it...
259         beq     1f
260
261         @ current Concan values are in the task save area
262         msr     cpsr_c, ip                      @ restore interrupt mode
263         mov     r0, r1
264         mov     r1, r2
265         mov     r2, #MMX_SIZE
266         b       memcpy
267
268 1:      @ this task owns Concan regs -- grab a copy from there
269         mov     r0, #0                          @ nothing to load
270         mov     r2, #3                          @ save all regs
271         mov     r3, lr                          @ preserve return address
272         bl      concan_dump
273         msr     cpsr_c, ip                      @ restore interrupt mode
274         ret     r3
275
276 ENDPROC(iwmmxt_task_copy)
277
278 /*
279  * Restore Concan state from given memory address
280  *
281  * r0 = struct thread_info pointer of target task
282  * r1 = memory address where to get Concan state from
283  *
284  * this is used to restore Concan state when unwinding a signal stack frame
285  */
286
287 ENTRY(iwmmxt_task_restore)
288
289         mrs     ip, cpsr
290         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
291         msr     cpsr_c, r2
292
293         ldr     r3, =concan_owner
294         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
295         ldr     r3, [r3]                        @ get current Concan owner
296         bic     r2, r2, #0x7                    @ 64-bit alignment
297         teq     r2, r3                          @ does this task own it...
298         beq     1f
299
300         @ this task doesn't own Concan regs -- use its save area
301         msr     cpsr_c, ip                      @ restore interrupt mode
302         mov     r0, r2
303         mov     r2, #MMX_SIZE
304         b       memcpy
305
306 1:      @ this task owns Concan regs -- load them directly
307         mov     r0, r1
308         mov     r1, #0                          @ don't clear CUP/MUP
309         mov     r3, lr                          @ preserve return address
310         bl      concan_load
311         msr     cpsr_c, ip                      @ restore interrupt mode
312         ret     r3
313
314 ENDPROC(iwmmxt_task_restore)
315
316 /*
317  * Concan handling on task switch
318  *
319  * r0 = next thread_info pointer
320  *
321  * Called only from the iwmmxt notifier with task preemption disabled.
322  */
323 ENTRY(iwmmxt_task_switch)
324
325         XSC(mrc p15, 0, r1, c15, c1, 0)
326         PJ4(mrc p15, 0, r1, c1, c0, 2)
327         @ CP0 and CP1 accessible?
328         XSC(tst r1, #0x3)
329         PJ4(tst r1, #0xf)
330         bne     1f                              @ yes: block them for next task
331
332         ldr     r2, =concan_owner
333         add     r3, r0, #TI_IWMMXT_STATE        @ get next task Concan save area
334         ldr     r2, [r2]                        @ get current Concan owner
335         teq     r2, r3                          @ next task owns it?
336         retne   lr                              @ no: leave Concan disabled
337
338 1:      @ flip Concan access
339         XSC(eor r1, r1, #0x3)
340         XSC(mcr p15, 0, r1, c15, c1, 0)
341         PJ4(eor r1, r1, #0xf)
342         PJ4(mcr p15, 0, r1, c1, c0, 2)
343
344         mrc     p15, 0, r1, c2, c0, 0
345         sub     pc, lr, r1, lsr #32             @ cpwait and return
346
347 ENDPROC(iwmmxt_task_switch)
348
349 /*
350  * Remove Concan ownership of given task
351  *
352  * r0 = struct thread_info pointer
353  */
354 ENTRY(iwmmxt_task_release)
355
356         mrs     r2, cpsr
357         orr     ip, r2, #PSR_I_BIT              @ disable interrupts
358         msr     cpsr_c, ip
359         ldr     r3, =concan_owner
360         add     r0, r0, #TI_IWMMXT_STATE        @ get task Concan save area
361         ldr     r1, [r3]                        @ get current Concan owner
362         eors    r0, r0, r1                      @ if equal...
363         streq   r0, [r3]                        @ then clear ownership
364         msr     cpsr_c, r2                      @ restore interrupts
365         ret     lr
366
367 ENDPROC(iwmmxt_task_release)
368
369         .data
370         .align  2
371 concan_owner:
372         .word   0
373