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/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#if XTENSA_HAVE_COPROCESSORS 30 31/* 32 * Macros for lazy context switch. 33 */ 34 35#define SAVE_CP_REGS(x) \ 36 .align 4; \ 37 .Lsave_cp_regs_cp##x: \ 38 .if XTENSA_HAVE_COPROCESSOR(x); \ 39 xchal_cp##x##_store a2 a4 a5 a6 a7; \ 40 .endif; \ 41 jx a0 42 43#define SAVE_CP_REGS_TAB(x) \ 44 .if XTENSA_HAVE_COPROCESSOR(x); \ 45 .long .Lsave_cp_regs_cp##x - .Lsave_cp_regs_jump_table; \ 46 .else; \ 47 .long 0; \ 48 .endif; \ 49 .long THREAD_XTREGS_CP##x 50 51 52#define LOAD_CP_REGS(x) \ 53 .align 4; \ 54 .Lload_cp_regs_cp##x: \ 55 .if XTENSA_HAVE_COPROCESSOR(x); \ 56 xchal_cp##x##_load a2 a4 a5 a6 a7; \ 57 .endif; \ 58 jx a0 59 60#define LOAD_CP_REGS_TAB(x) \ 61 .if XTENSA_HAVE_COPROCESSOR(x); \ 62 .long .Lload_cp_regs_cp##x - .Lload_cp_regs_jump_table; \ 63 .else; \ 64 .long 0; \ 65 .endif; \ 66 .long THREAD_XTREGS_CP##x 67 68 SAVE_CP_REGS(0) 69 SAVE_CP_REGS(1) 70 SAVE_CP_REGS(2) 71 SAVE_CP_REGS(3) 72 SAVE_CP_REGS(4) 73 SAVE_CP_REGS(5) 74 SAVE_CP_REGS(6) 75 SAVE_CP_REGS(7) 76 77 LOAD_CP_REGS(0) 78 LOAD_CP_REGS(1) 79 LOAD_CP_REGS(2) 80 LOAD_CP_REGS(3) 81 LOAD_CP_REGS(4) 82 LOAD_CP_REGS(5) 83 LOAD_CP_REGS(6) 84 LOAD_CP_REGS(7) 85 86 .align 4 87.Lsave_cp_regs_jump_table: 88 SAVE_CP_REGS_TAB(0) 89 SAVE_CP_REGS_TAB(1) 90 SAVE_CP_REGS_TAB(2) 91 SAVE_CP_REGS_TAB(3) 92 SAVE_CP_REGS_TAB(4) 93 SAVE_CP_REGS_TAB(5) 94 SAVE_CP_REGS_TAB(6) 95 SAVE_CP_REGS_TAB(7) 96 97.Lload_cp_regs_jump_table: 98 LOAD_CP_REGS_TAB(0) 99 LOAD_CP_REGS_TAB(1) 100 LOAD_CP_REGS_TAB(2) 101 LOAD_CP_REGS_TAB(3) 102 LOAD_CP_REGS_TAB(4) 103 LOAD_CP_REGS_TAB(5) 104 LOAD_CP_REGS_TAB(6) 105 LOAD_CP_REGS_TAB(7) 106 107/* 108 * coprocessor_flush(struct thread_info*, index) 109 * a2 a3 110 * 111 * Save coprocessor registers for coprocessor 'index'. 112 * The register values are saved to or loaded from the coprocessor area 113 * inside the task_info structure. 114 * 115 * Note that this function doesn't update the coprocessor_owner information! 116 * 117 */ 118 119ENTRY(coprocessor_flush) 120 121 entry a1, 32 122 s32i a0, a1, 0 123 movi a0, .Lsave_cp_regs_jump_table 124 addx8 a3, a3, a0 125 l32i a4, a3, 4 126 l32i a3, a3, 0 127 add a2, a2, a4 128 beqz a3, 1f 129 add a0, a0, a3 130 callx0 a0 1311: l32i a0, a1, 0 132 retw 133 134ENDPROC(coprocessor_flush) 135 136/* 137 * Entry condition: 138 * 139 * a0: trashed, original value saved on stack (PT_AREG0) 140 * a1: a1 141 * a2: new stack pointer, original in DEPC 142 * a3: a3 143 * depc: a2, original value saved on stack (PT_DEPC) 144 * excsave_1: dispatch table 145 * 146 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 147 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 148 */ 149 150ENTRY(fast_coprocessor_double) 151 152 wsr a0, excsave1 153 call0 unrecoverable_exception 154 155ENDPROC(fast_coprocessor_double) 156 157ENTRY(fast_coprocessor) 158 159 /* Save remaining registers a1-a3 and SAR */ 160 161 s32i a3, a2, PT_AREG3 162 rsr a3, sar 163 s32i a1, a2, PT_AREG1 164 s32i a3, a2, PT_SAR 165 mov a1, a2 166 rsr a2, depc 167 s32i a2, a1, PT_AREG2 168 169 /* 170 * The hal macros require up to 4 temporary registers. We use a3..a6. 171 */ 172 173 s32i a4, a1, PT_AREG4 174 s32i a5, a1, PT_AREG5 175 s32i a6, a1, PT_AREG6 176 177 /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */ 178 179 rsr a3, exccause 180 addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED 181 182 /* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/ 183 184 ssl a3 # SAR: 32 - coprocessor_number 185 movi a2, 1 186 rsr a0, cpenable 187 sll a2, a2 188 or a0, a0, a2 189 wsr a0, cpenable 190 rsync 191 192 /* Retrieve previous owner. (a3 still holds CP number) */ 193 194 movi a0, coprocessor_owner # list of owners 195 addx4 a0, a3, a0 # entry for CP 196 l32i a4, a0, 0 197 198 beqz a4, 1f # skip 'save' if no previous owner 199 200 /* Disable coprocessor for previous owner. (a2 = 1 << CP number) */ 201 202 l32i a5, a4, THREAD_CPENABLE 203 xor a5, a5, a2 # (1 << cp-id) still in a2 204 s32i a5, a4, THREAD_CPENABLE 205 206 /* 207 * Get context save area and 'call' save routine. 208 * (a4 still holds previous owner (thread_info), a3 CP number) 209 */ 210 211 movi a5, .Lsave_cp_regs_jump_table 212 movi a0, 2f # a0: 'return' address 213 addx8 a3, a3, a5 # a3: coprocessor number 214 l32i a2, a3, 4 # a2: xtregs offset 215 l32i a3, a3, 0 # a3: jump offset 216 add a2, a2, a4 217 add a4, a3, a5 # a4: address of save routine 218 jx a4 219 220 /* Note that only a0 and a1 were preserved. */ 221 2222: rsr a3, exccause 223 addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED 224 movi a0, coprocessor_owner 225 addx4 a0, a3, a0 226 227 /* Set new 'owner' (a0 points to the CP owner, a3 contains the CP nr) */ 228 2291: GET_THREAD_INFO (a4, a1) 230 s32i a4, a0, 0 231 232 /* Get context save area and 'call' load routine. */ 233 234 movi a5, .Lload_cp_regs_jump_table 235 movi a0, 1f 236 addx8 a3, a3, a5 237 l32i a2, a3, 4 # a2: xtregs offset 238 l32i a3, a3, 0 # a3: jump offset 239 add a2, a2, a4 240 add a4, a3, a5 241 jx a4 242 243 /* Restore all registers and return from exception handler. */ 244 2451: l32i a6, a1, PT_AREG6 246 l32i a5, a1, PT_AREG5 247 l32i a4, a1, PT_AREG4 248 249 l32i a0, a1, PT_SAR 250 l32i a3, a1, PT_AREG3 251 l32i a2, a1, PT_AREG2 252 wsr a0, sar 253 l32i a0, a1, PT_AREG0 254 l32i a1, a1, PT_AREG1 255 256 rfe 257 258ENDPROC(fast_coprocessor) 259 260 .data 261 262ENTRY(coprocessor_owner) 263 264 .fill XCHAL_CP_MAX, 4, 0 265 266END(coprocessor_owner) 267 268#endif /* XTENSA_HAVE_COPROCESSORS */ 269