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