root/arch/xtensa/kernel/coprocessor.S

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

/* [<][>][^][v][top][bottom][index][help] */