hc
2024-05-10 23fa18eaa71266feff7ba8d83022d9e1cc83c65a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * arch/arm/kernel/crunch-bits.S
 * Cirrus MaverickCrunch context switching and handling
 *
 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
 *
 * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
 * Copyright (c) 2003-2004, MontaVista Software, Inc.
 */
 
#include <linux/linkage.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
#include <asm/assembler.h>
#include <mach/ep93xx-regs.h>
 
/*
 * We can't use hex constants here due to a bug in gas.
 */
#define CRUNCH_MVDX0        0
#define CRUNCH_MVDX1        8
#define CRUNCH_MVDX2        16
#define CRUNCH_MVDX3        24
#define CRUNCH_MVDX4        32
#define CRUNCH_MVDX5        40
#define CRUNCH_MVDX6        48
#define CRUNCH_MVDX7        56
#define CRUNCH_MVDX8        64
#define CRUNCH_MVDX9        72
#define CRUNCH_MVDX10        80
#define CRUNCH_MVDX11        88
#define CRUNCH_MVDX12        96
#define CRUNCH_MVDX13        104
#define CRUNCH_MVDX14        112
#define CRUNCH_MVDX15        120
#define CRUNCH_MVAX0L        128
#define CRUNCH_MVAX0M        132
#define CRUNCH_MVAX0H        136
#define CRUNCH_MVAX1L        140
#define CRUNCH_MVAX1M        144
#define CRUNCH_MVAX1H        148
#define CRUNCH_MVAX2L        152
#define CRUNCH_MVAX2M        156
#define CRUNCH_MVAX2H        160
#define CRUNCH_MVAX3L        164
#define CRUNCH_MVAX3M        168
#define CRUNCH_MVAX3H        172
#define CRUNCH_DSPSC        176
 
#define CRUNCH_SIZE        184
 
   .text
 
/*
 * Lazy switching of crunch coprocessor context
 *
 * r10 = struct thread_info pointer
 * r9  = ret_from_exception
 * lr  = undefined instr exit
 *
 * called from prefetch exception handler with interrupts enabled
 */
ENTRY(crunch_task_enable)
   inc_preempt_count r10, r3
 
   ldr    r8, =(EP93XX_APB_VIRT_BASE + 0x00130000)    @ syscon addr
 
   ldr    r1, [r8, #0x80]
   tst    r1, #0x00800000            @ access to crunch enabled?
   bne    2f                @ if so no business here
   mov    r3, #0xaa            @ unlock syscon swlock
   str    r3, [r8, #0xc0]
   orr    r1, r1, #0x00800000        @ enable access to crunch
   str    r1, [r8, #0x80]
 
   ldr    r3, =crunch_owner
   add    r0, r10, #TI_CRUNCH_STATE    @ get task crunch save area
   ldr    r2, [sp, #60]            @ current task pc value
   ldr    r1, [r3]            @ get current crunch owner
   str    r0, [r3]            @ this task now owns crunch
   sub    r2, r2, #4            @ adjust pc back
   str    r2, [sp, #60]
 
   ldr    r2, [r8, #0x80]
   mov    r2, r2                @ flush out enable (@@@)
 
   teq    r1, #0                @ test for last ownership
   mov    lr, r9                @ normal exit from exception
   beq    crunch_load            @ no owner, skip save
 
crunch_save:
   cfstr64        mvdx0, [r1, #CRUNCH_MVDX0]    @ save 64b registers
   cfstr64        mvdx1, [r1, #CRUNCH_MVDX1]
   cfstr64        mvdx2, [r1, #CRUNCH_MVDX2]
   cfstr64        mvdx3, [r1, #CRUNCH_MVDX3]
   cfstr64        mvdx4, [r1, #CRUNCH_MVDX4]
   cfstr64        mvdx5, [r1, #CRUNCH_MVDX5]
   cfstr64        mvdx6, [r1, #CRUNCH_MVDX6]
   cfstr64        mvdx7, [r1, #CRUNCH_MVDX7]
   cfstr64        mvdx8, [r1, #CRUNCH_MVDX8]
   cfstr64        mvdx9, [r1, #CRUNCH_MVDX9]
   cfstr64        mvdx10, [r1, #CRUNCH_MVDX10]
   cfstr64        mvdx11, [r1, #CRUNCH_MVDX11]
   cfstr64        mvdx12, [r1, #CRUNCH_MVDX12]
   cfstr64        mvdx13, [r1, #CRUNCH_MVDX13]
   cfstr64        mvdx14, [r1, #CRUNCH_MVDX14]
   cfstr64        mvdx15, [r1, #CRUNCH_MVDX15]
 
#ifdef __ARMEB__
#error fix me for ARMEB
#endif
 
   cfmv32al    mvfx0, mvax0            @ save 72b accumulators
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX0L]
   cfmv32am    mvfx0, mvax0
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX0M]
   cfmv32ah    mvfx0, mvax0
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX0H]
   cfmv32al    mvfx0, mvax1
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX1L]
   cfmv32am    mvfx0, mvax1
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX1M]
   cfmv32ah    mvfx0, mvax1
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX1H]
   cfmv32al    mvfx0, mvax2
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX2L]
   cfmv32am    mvfx0, mvax2
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX2M]
   cfmv32ah    mvfx0, mvax2
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX2H]
   cfmv32al    mvfx0, mvax3
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX3L]
   cfmv32am    mvfx0, mvax3
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX3M]
   cfmv32ah    mvfx0, mvax3
   cfstr32        mvfx0, [r1, #CRUNCH_MVAX3H]
 
   cfmv32sc    mvdx0, dspsc            @ save status word
   cfstr64        mvdx0, [r1, #CRUNCH_DSPSC]
 
   teq        r0, #0                @ anything to load?
   cfldr64eq    mvdx0, [r1, #CRUNCH_MVDX0]    @ mvdx0 was clobbered
   beq        1f
 
crunch_load:
   cfldr64        mvdx0, [r0, #CRUNCH_DSPSC]    @ load status word
   cfmvsc32    dspsc, mvdx0
 
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX0L]    @ load 72b accumulators
   cfmval32    mvax0, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX0M]
   cfmvam32    mvax0, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX0H]
   cfmvah32    mvax0, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX1L]
   cfmval32    mvax1, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX1M]
   cfmvam32    mvax1, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX1H]
   cfmvah32    mvax1, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX2L]
   cfmval32    mvax2, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX2M]
   cfmvam32    mvax2, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX2H]
   cfmvah32    mvax2, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX3L]
   cfmval32    mvax3, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX3M]
   cfmvam32    mvax3, mvfx0
   cfldr32        mvfx0, [r0, #CRUNCH_MVAX3H]
   cfmvah32    mvax3, mvfx0
 
   cfldr64        mvdx0, [r0, #CRUNCH_MVDX0]    @ load 64b registers
   cfldr64        mvdx1, [r0, #CRUNCH_MVDX1]
   cfldr64        mvdx2, [r0, #CRUNCH_MVDX2]
   cfldr64        mvdx3, [r0, #CRUNCH_MVDX3]
   cfldr64        mvdx4, [r0, #CRUNCH_MVDX4]
   cfldr64        mvdx5, [r0, #CRUNCH_MVDX5]
   cfldr64        mvdx6, [r0, #CRUNCH_MVDX6]
   cfldr64        mvdx7, [r0, #CRUNCH_MVDX7]
   cfldr64        mvdx8, [r0, #CRUNCH_MVDX8]
   cfldr64        mvdx9, [r0, #CRUNCH_MVDX9]
   cfldr64        mvdx10, [r0, #CRUNCH_MVDX10]
   cfldr64        mvdx11, [r0, #CRUNCH_MVDX11]
   cfldr64        mvdx12, [r0, #CRUNCH_MVDX12]
   cfldr64        mvdx13, [r0, #CRUNCH_MVDX13]
   cfldr64        mvdx14, [r0, #CRUNCH_MVDX14]
   cfldr64        mvdx15, [r0, #CRUNCH_MVDX15]
 
1:
#ifdef CONFIG_PREEMPT_COUNT
   get_thread_info r10
#endif
2:    dec_preempt_count r10, r3
   ret    lr
 
/*
 * Back up crunch regs to save area and disable access to them
 * (mainly for gdb or sleep mode usage)
 *
 * r0 = struct thread_info pointer of target task or NULL for any
 */
ENTRY(crunch_task_disable)
   stmfd    sp!, {r4, r5, lr}
 
   mrs    ip, cpsr
   orr    r2, ip, #PSR_I_BIT        @ disable interrupts
   msr    cpsr_c, r2
 
   ldr    r4, =(EP93XX_APB_VIRT_BASE + 0x00130000)    @ syscon addr
 
   ldr    r3, =crunch_owner
   add    r2, r0, #TI_CRUNCH_STATE    @ get task crunch save area
   ldr    r1, [r3]            @ get current crunch owner
   teq    r1, #0                @ any current owner?
   beq    1f                @ no: quit
   teq    r0, #0                @ any owner?
   teqne    r1, r2                @ or specified one?
   bne    1f                @ no: quit
 
   ldr    r5, [r4, #0x80]            @ enable access to crunch
   mov    r2, #0xaa
   str    r2, [r4, #0xc0]
   orr    r5, r5, #0x00800000
   str    r5, [r4, #0x80]
 
   mov    r0, #0                @ nothing to load
   str    r0, [r3]            @ no more current owner
   ldr    r2, [r4, #0x80]            @ flush out enable (@@@)
   mov    r2, r2
   bl    crunch_save
 
   mov    r2, #0xaa            @ disable access to crunch
   str    r2, [r4, #0xc0]
   bic    r5, r5, #0x00800000
   str    r5, [r4, #0x80]
   ldr    r5, [r4, #0x80]            @ flush out enable (@@@)
   mov    r5, r5
 
1:    msr    cpsr_c, ip            @ restore interrupt mode
   ldmfd    sp!, {r4, r5, pc}
 
/*
 * Copy crunch state to given memory address
 *
 * r0 = struct thread_info pointer of target task
 * r1 = memory address where to store crunch state
 *
 * this is called mainly in the creation of signal stack frames
 */
ENTRY(crunch_task_copy)
   mrs    ip, cpsr
   orr    r2, ip, #PSR_I_BIT        @ disable interrupts
   msr    cpsr_c, r2
 
   ldr    r3, =crunch_owner
   add    r2, r0, #TI_CRUNCH_STATE    @ get task crunch save area
   ldr    r3, [r3]            @ get current crunch owner
   teq    r2, r3                @ does this task own it...
   beq    1f
 
   @ current crunch values are in the task save area
   msr    cpsr_c, ip            @ restore interrupt mode
   mov    r0, r1
   mov    r1, r2
   mov    r2, #CRUNCH_SIZE
   b    memcpy
 
1:    @ this task owns crunch regs -- grab a copy from there
   mov    r0, #0                @ nothing to load
   mov    r3, lr                @ preserve return address
   bl    crunch_save
   msr    cpsr_c, ip            @ restore interrupt mode
   ret    r3
 
/*
 * Restore crunch state from given memory address
 *
 * r0 = struct thread_info pointer of target task
 * r1 = memory address where to get crunch state from
 *
 * this is used to restore crunch state when unwinding a signal stack frame
 */
ENTRY(crunch_task_restore)
   mrs    ip, cpsr
   orr    r2, ip, #PSR_I_BIT        @ disable interrupts
   msr    cpsr_c, r2
 
   ldr    r3, =crunch_owner
   add    r2, r0, #TI_CRUNCH_STATE    @ get task crunch save area
   ldr    r3, [r3]            @ get current crunch owner
   teq    r2, r3                @ does this task own it...
   beq    1f
 
   @ this task doesn't own crunch regs -- use its save area
   msr    cpsr_c, ip            @ restore interrupt mode
   mov    r0, r2
   mov    r2, #CRUNCH_SIZE
   b    memcpy
 
1:    @ this task owns crunch regs -- load them directly
   mov    r0, r1
   mov    r1, #0                @ nothing to save
   mov    r3, lr                @ preserve return address
   bl    crunch_load
   msr    cpsr_c, ip            @ restore interrupt mode
   ret    r3