Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / arch / xtensa / kernel / coprocessor.S
1 /*
2  * arch/xtensa/kernel/coprocessor.S
3  *
4  * Xtensa processor configuration-specific table of coprocessor and
5  * other custom register layout information.
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  *
11  * Copyright (C) 2003 - 2007 Tensilica Inc.
12  */
13
14
15 #include <linux/linkage.h>
16 #include <asm/asm-offsets.h>
17 #include <asm/processor.h>
18 #include <asm/coprocessor.h>
19 #include <asm/thread_info.h>
20 #include <asm/uaccess.h>
21 #include <asm/unistd.h>
22 #include <asm/ptrace.h>
23 #include <asm/current.h>
24 #include <asm/pgtable.h>
25 #include <asm/page.h>
26 #include <asm/signal.h>
27 #include <asm/tlbflush.h>
28
29 /*
30  * Entry condition:
31  *
32  *   a0:        trashed, original value saved on stack (PT_AREG0)
33  *   a1:        a1
34  *   a2:        new stack pointer, original in DEPC
35  *   a3:        dispatch table
36  *   depc:      a2, original value saved on stack (PT_DEPC)
37  *   excsave_1: a3
38  *
39  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
40  *           <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
41  */
42
43 /* IO protection is currently unsupported. */
44
45 ENTRY(fast_io_protect)
46         wsr     a0, EXCSAVE_1
47         movi    a0, unrecoverable_exception
48         callx0  a0
49
50 #if XTENSA_HAVE_COPROCESSORS
51
52 /*
53  * Macros for lazy context switch. 
54  */
55
56 #define SAVE_CP_REGS(x)                                                 \
57         .align 4;                                                       \
58         .Lsave_cp_regs_cp##x:                                           \
59         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
60                 xchal_cp##x##_store a2 a4 a5 a6 a7;                     \
61         .endif;                                                         \
62         jx      a0
63
64 #define SAVE_CP_REGS_TAB(x)                                             \
65         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
66                 .long .Lsave_cp_regs_cp##x - .Lsave_cp_regs_jump_table; \
67         .else;                                                          \
68                 .long 0;                                                \
69         .endif;                                                         \
70         .long THREAD_XTREGS_CP##x
71
72
73 #define LOAD_CP_REGS(x)                                                 \
74         .align 4;                                                       \
75         .Lload_cp_regs_cp##x:                                           \
76         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
77                 xchal_cp##x##_load a2 a4 a5 a6 a7;                      \
78         .endif;                                                         \
79         jx      a0
80
81 #define LOAD_CP_REGS_TAB(x)                                             \
82         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
83                 .long .Lload_cp_regs_cp##x - .Lload_cp_regs_jump_table; \
84         .else;                                                          \
85                 .long 0;                                                \
86         .endif;                                                         \
87         .long THREAD_XTREGS_CP##x
88
89         SAVE_CP_REGS(0)
90         SAVE_CP_REGS(1)
91         SAVE_CP_REGS(2)
92         SAVE_CP_REGS(3)
93         SAVE_CP_REGS(4)
94         SAVE_CP_REGS(5)
95         SAVE_CP_REGS(6)
96         SAVE_CP_REGS(7)
97
98         LOAD_CP_REGS(0)
99         LOAD_CP_REGS(1)
100         LOAD_CP_REGS(2)
101         LOAD_CP_REGS(3)
102         LOAD_CP_REGS(4)
103         LOAD_CP_REGS(5)
104         LOAD_CP_REGS(6)
105         LOAD_CP_REGS(7)
106
107         .align 4
108 .Lsave_cp_regs_jump_table:
109         SAVE_CP_REGS_TAB(0)
110         SAVE_CP_REGS_TAB(1)
111         SAVE_CP_REGS_TAB(2)
112         SAVE_CP_REGS_TAB(3)
113         SAVE_CP_REGS_TAB(4)
114         SAVE_CP_REGS_TAB(5)
115         SAVE_CP_REGS_TAB(6)
116         SAVE_CP_REGS_TAB(7)
117
118 .Lload_cp_regs_jump_table:
119         LOAD_CP_REGS_TAB(0)
120         LOAD_CP_REGS_TAB(1)
121         LOAD_CP_REGS_TAB(2)
122         LOAD_CP_REGS_TAB(3)
123         LOAD_CP_REGS_TAB(4)
124         LOAD_CP_REGS_TAB(5)
125         LOAD_CP_REGS_TAB(6)
126         LOAD_CP_REGS_TAB(7)
127
128 /*
129  * coprocessor_save(buffer, index) 
130  *                    a2      a3
131  * coprocessor_load(buffer, index)
132  *                    a2      a3
133  *
134  * Save or load coprocessor registers for coprocessor 'index'. 
135  * The register values are saved to or loaded from them 'buffer' address.
136  *
137  * Note that these functions don't update the coprocessor_owner information!
138  *
139  */
140
141 ENTRY(coprocessor_save)
142         entry   a1, 32
143         s32i    a0, a1, 0
144         movi    a0, .Lsave_cp_regs_jump_table
145         addx8   a3, a3, a0
146         l32i    a3, a3, 0
147         beqz    a3, 1f
148         add     a0, a0, a3
149         callx0  a0
150 1:      l32i    a0, a1, 0
151         retw
152
153 ENTRY(coprocessor_load)
154         entry   a1, 32
155         s32i    a0, a1, 0
156         movi    a0, .Lload_cp_regs_jump_table
157         addx4   a3, a3, a0
158         l32i    a3, a3, 0
159         beqz    a3, 1f
160         add     a0, a0, a3
161         callx0  a0
162 1:      l32i    a0, a1, 0
163         retw
164
165 /*
166  * coprocessor_flush(struct task_info*, index) 
167  *                             a2        a3
168  * coprocessor_restore(struct task_info*, index)
169  *                              a2         a3
170  *
171  * Save or load coprocessor registers for coprocessor 'index'. 
172  * The register values are saved to or loaded from the coprocessor area 
173  * inside the task_info structure.
174  *
175  * Note that these functions don't update the coprocessor_owner information!
176  *
177  */
178
179
180 ENTRY(coprocessor_flush)
181         entry   a1, 32
182         s32i    a0, a1, 0
183         movi    a0, .Lsave_cp_regs_jump_table
184         addx8   a3, a3, a0
185         l32i    a4, a3, 4
186         l32i    a3, a3, 0
187         add     a2, a2, a4
188         beqz    a3, 1f
189         add     a0, a0, a3
190         callx0  a0
191 1:      l32i    a0, a1, 0
192         retw
193
194 ENTRY(coprocessor_restore)
195         entry   a1, 32
196         s32i    a0, a1, 0
197         movi    a0, .Lload_cp_regs_jump_table
198         addx4   a3, a3, a0
199         l32i    a4, a3, 4
200         l32i    a3, a3, 0
201         add     a2, a2, a4
202         beqz    a3, 1f
203         add     a0, a0, a3
204         callx0  a0
205 1:      l32i    a0, a1, 0
206         retw
207
208 /*
209  * Entry condition:
210  *
211  *   a0:        trashed, original value saved on stack (PT_AREG0)
212  *   a1:        a1
213  *   a2:        new stack pointer, original in DEPC
214  *   a3:        dispatch table
215  *   depc:      a2, original value saved on stack (PT_DEPC)
216  *   excsave_1: a3
217  *
218  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
219  *           <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
220  */
221
222 ENTRY(fast_coprocessor_double)
223         wsr     a0, EXCSAVE_1
224         movi    a0, unrecoverable_exception
225         callx0  a0
226
227
228 ENTRY(fast_coprocessor)
229
230         /* Save remaining registers a1-a3 and SAR */
231
232         xsr     a3, EXCSAVE_1
233         s32i    a3, a2, PT_AREG3
234         rsr     a3, SAR
235         s32i    a1, a2, PT_AREG1
236         s32i    a3, a2, PT_SAR
237         mov     a1, a2
238         rsr     a2, DEPC
239         s32i    a2, a1, PT_AREG2
240
241         /*
242          * The hal macros require up to 4 temporary registers. We use a3..a6.
243          */
244
245         s32i    a4, a1, PT_AREG4
246         s32i    a5, a1, PT_AREG5
247         s32i    a6, a1, PT_AREG6
248
249         /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
250
251         rsr     a3, EXCCAUSE
252         addi    a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
253
254         /* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/
255
256         ssl     a3                      # SAR: 32 - coprocessor_number
257         movi    a2, 1
258         rsr     a0, CPENABLE
259         sll     a2, a2
260         or      a0, a0, a2
261         wsr     a0, CPENABLE
262         rsync
263
264         /* Retrieve previous owner. (a3 still holds CP number) */
265
266         movi    a0, coprocessor_owner   # list of owners
267         addx4   a0, a3, a0              # entry for CP
268         l32i    a4, a0, 0
269
270         beqz    a4, 1f                  # skip 'save' if no previous owner
271
272         /* Disable coprocessor for previous owner. (a2 = 1 << CP number) */
273
274         l32i    a5, a4, THREAD_CPENABLE
275         xor     a5, a5, a2              # (1 << cp-id) still in a2
276         s32i    a5, a4, THREAD_CPENABLE
277
278         /*
279          * Get context save area and 'call' save routine. 
280          * (a4 still holds previous owner (thread_info), a3 CP number)
281          */
282
283         movi    a5, .Lsave_cp_regs_jump_table
284         movi    a0, 2f                  # a0: 'return' address
285         addx8   a3, a3, a5              # a3: coprocessor number
286         l32i    a2, a3, 4               # a2: xtregs offset
287         l32i    a3, a3, 0               # a3: jump offset
288         add     a2, a2, a4
289         add     a4, a3, a5              # a4: address of save routine
290         jx      a4
291
292         /* Note that only a0 and a1 were preserved. */
293
294 2:      rsr     a3, EXCCAUSE
295         addi    a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
296         movi    a0, coprocessor_owner
297         addx4   a0, a3, a0
298
299         /* Set new 'owner' (a0 points to the CP owner, a3 contains the CP nr) */
300
301 1:      GET_THREAD_INFO (a4, a1)
302         s32i    a4, a0, 0
303
304         /* Get context save area and 'call' load routine. */
305
306         movi    a5, .Lload_cp_regs_jump_table
307         movi    a0, 1f
308         addx8   a3, a3, a5
309         l32i    a2, a3, 4               # a2: xtregs offset
310         l32i    a3, a3, 0               # a3: jump offset
311         add     a2, a2, a4
312         add     a4, a3, a5
313         jx      a4
314
315         /* Restore all registers and return from exception handler. */
316
317 1:      l32i    a6, a1, PT_AREG6
318         l32i    a5, a1, PT_AREG5
319         l32i    a4, a1, PT_AREG4
320
321         l32i    a0, a1, PT_SAR
322         l32i    a3, a1, PT_AREG3
323         l32i    a2, a1, PT_AREG2
324         wsr     a0, SAR
325         l32i    a0, a1, PT_AREG0
326         l32i    a1, a1, PT_AREG1
327
328         rfe
329
330         .data
331 ENTRY(coprocessor_owner)
332         .fill XCHAL_CP_MAX, 4, 0
333
334 #endif /* XTENSA_HAVE_COPROCESSORS */
335