summaryrefslogtreecommitdiff
path: root/arch/arm/mach-ep93xx/crunch-bits.S
blob: ee0be2af5c61b2e4abc086abb9167230a0f29d2b (plain) (blame)
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
311
312
313
/*
 * 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.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#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