Commit | Line | Data |
---|---|---|
5a0015d6 CZ |
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 | * | |
c658eac6 | 11 | * Copyright (C) 2003 - 2007 Tensilica Inc. |
5a0015d6 CZ |
12 | */ |
13 | ||
5a0015d6 | 14 | |
5a0015d6 | 15 | #include <linux/linkage.h> |
c658eac6 | 16 | #include <asm/asm-offsets.h> |
5a0015d6 | 17 | #include <asm/processor.h> |
c658eac6 CZ |
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> | |
5a0015d6 | 28 | |
c658eac6 CZ |
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 | */ | |
5a0015d6 | 42 | |
c658eac6 | 43 | /* IO protection is currently unsupported. */ |
5a0015d6 | 44 | |
c658eac6 CZ |
45 | ENTRY(fast_io_protect) |
46 | wsr a0, EXCSAVE_1 | |
47 | movi a0, unrecoverable_exception | |
48 | callx0 a0 | |
5a0015d6 | 49 | |
c658eac6 | 50 | #if XTENSA_HAVE_COPROCESSORS |
5a0015d6 | 51 | |
c658eac6 CZ |
52 | /* |
53 | * Macros for lazy context switch. | |
54 | */ | |
5a0015d6 | 55 | |
c658eac6 CZ |
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 | |
5a0015d6 | 63 | |
c658eac6 CZ |
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 | |
5a0015d6 | 71 | |
5a0015d6 | 72 | |
c658eac6 CZ |
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 | |
5a0015d6 | 80 | |
c658eac6 CZ |
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 | |
5a0015d6 | 88 | |
c658eac6 CZ |
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) | |
5a0015d6 | 97 | |
c658eac6 CZ |
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) | |
5a0015d6 | 106 | |
c658eac6 CZ |
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) | |
5a0015d6 | 117 | |
c658eac6 CZ |
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) | |
5a0015d6 | 127 | |
c658eac6 CZ |
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 | */ | |
5a0015d6 | 140 | |
c658eac6 CZ |
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 | |
5a0015d6 CZ |
151 | retw |
152 | ||
c658eac6 CZ |
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 | |
5a0015d6 CZ |
163 | retw |
164 | ||
c658eac6 CZ |
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 | |
5a0015d6 CZ |
192 | retw |
193 | ||
c658eac6 CZ |
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 | |
5a0015d6 CZ |
207 | |
208 | /* | |
c658eac6 | 209 | * Entry condition: |
5a0015d6 | 210 | * |
c658eac6 CZ |
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 | |
5a0015d6 | 217 | * |
c658eac6 CZ |
218 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
219 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | |
5a0015d6 CZ |
220 | */ |
221 | ||
c658eac6 CZ |
222 | ENTRY(fast_coprocessor_double) |
223 | wsr a0, EXCSAVE_1 | |
224 | movi a0, unrecoverable_exception | |
225 | callx0 a0 | |
5a0015d6 | 226 | |
5a0015d6 | 227 | |
c658eac6 CZ |
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 */ | |
5a0015d6 | 335 |