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