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