Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  *  linux/arch/arm/kernel/iwmmxt.S
0004  *
0005  *  XScale iWMMXt (Concan) context switching and handling
0006  *
0007  *  Initial code:
0008  *  Copyright (c) 2003, Intel Corporation
0009  *
0010  *  Full lazy switching support, optimizations and more, by Nicolas Pitre
0011 *   Copyright (c) 2003-2004, MontaVista Software, Inc.
0012  */
0013 
0014 #include <linux/linkage.h>
0015 #include <asm/ptrace.h>
0016 #include <asm/thread_info.h>
0017 #include <asm/asm-offsets.h>
0018 #include <asm/assembler.h>
0019 #include "iwmmxt.h"
0020 
0021 #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
0022 #define PJ4(code...)        code
0023 #define XSC(code...)
0024 #elif defined(CONFIG_CPU_MOHAWK) || \
0025     defined(CONFIG_CPU_XSC3) || \
0026     defined(CONFIG_CPU_XSCALE)
0027 #define PJ4(code...)
0028 #define XSC(code...)        code
0029 #else
0030 #error "Unsupported iWMMXt architecture"
0031 #endif
0032 
0033 #define MMX_WR0         (0x00)
0034 #define MMX_WR1         (0x08)
0035 #define MMX_WR2         (0x10)
0036 #define MMX_WR3         (0x18)
0037 #define MMX_WR4         (0x20)
0038 #define MMX_WR5         (0x28)
0039 #define MMX_WR6         (0x30)
0040 #define MMX_WR7         (0x38)
0041 #define MMX_WR8         (0x40)
0042 #define MMX_WR9         (0x48)
0043 #define MMX_WR10        (0x50)
0044 #define MMX_WR11        (0x58)
0045 #define MMX_WR12        (0x60)
0046 #define MMX_WR13        (0x68)
0047 #define MMX_WR14        (0x70)
0048 #define MMX_WR15        (0x78)
0049 #define MMX_WCSSF       (0x80)
0050 #define MMX_WCASF       (0x84)
0051 #define MMX_WCGR0       (0x88)
0052 #define MMX_WCGR1       (0x8C)
0053 #define MMX_WCGR2       (0x90)
0054 #define MMX_WCGR3       (0x94)
0055 
0056 #define MMX_SIZE        (0x98)
0057 
0058     .text
0059     .arm
0060 
0061 /*
0062  * Lazy switching of Concan coprocessor context
0063  *
0064  * r10 = struct thread_info pointer
0065  * r9  = ret_from_exception
0066  * lr  = undefined instr exit
0067  *
0068  * called from prefetch exception handler with interrupts enabled
0069  */
0070 
0071 ENTRY(iwmmxt_task_enable)
0072     inc_preempt_count r10, r3
0073 
0074     XSC(mrc p15, 0, r2, c15, c1, 0)
0075     PJ4(mrc p15, 0, r2, c1, c0, 2)
0076     @ CP0 and CP1 accessible?
0077     XSC(tst r2, #0x3)
0078     PJ4(tst r2, #0xf)
0079     bne 4f              @ if so no business here
0080     @ enable access to CP0 and CP1
0081     XSC(orr r2, r2, #0x3)
0082     XSC(mcr p15, 0, r2, c15, c1, 0)
0083     PJ4(orr r2, r2, #0xf)
0084     PJ4(mcr p15, 0, r2, c1, c0, 2)
0085 
0086     ldr r3, =concan_owner
0087     add r0, r10, #TI_IWMMXT_STATE   @ get task Concan save area
0088     ldr r2, [sp, #60]           @ current task pc value
0089     ldr r1, [r3]            @ get current Concan owner
0090     str r0, [r3]            @ this task now owns Concan regs
0091     sub r2, r2, #4          @ adjust pc back
0092     str r2, [sp, #60]
0093 
0094     mrc p15, 0, r2, c2, c0, 0
0095     mov r2, r2              @ cpwait
0096     bl  concan_save
0097 
0098 #ifdef CONFIG_PREEMPT_COUNT
0099     get_thread_info r10
0100 #endif
0101 4:  dec_preempt_count r10, r3
0102     ret r9              @ normal exit from exception
0103 
0104 concan_save:
0105 
0106     teq r1, #0              @ test for last ownership
0107     beq concan_load         @ no owner, skip save
0108 
0109     tmrc    r2, wCon
0110 
0111     @ CUP? wCx
0112     tst r2, #0x1
0113     beq     1f
0114 
0115 concan_dump:
0116 
0117     wstrw   wCSSF, r1, MMX_WCSSF
0118     wstrw   wCASF, r1, MMX_WCASF
0119     wstrw   wCGR0, r1, MMX_WCGR0
0120     wstrw   wCGR1, r1, MMX_WCGR1
0121     wstrw   wCGR2, r1, MMX_WCGR2
0122     wstrw   wCGR3, r1, MMX_WCGR3
0123 
0124 1:  @ MUP? wRn
0125     tst r2, #0x2
0126     beq 2f
0127 
0128     wstrd   wR0,  r1, MMX_WR0
0129     wstrd   wR1,  r1, MMX_WR1
0130     wstrd   wR2,  r1, MMX_WR2
0131     wstrd   wR3,  r1, MMX_WR3
0132     wstrd   wR4,  r1, MMX_WR4
0133     wstrd   wR5,  r1, MMX_WR5
0134     wstrd   wR6,  r1, MMX_WR6
0135     wstrd   wR7,  r1, MMX_WR7
0136     wstrd   wR8,  r1, MMX_WR8
0137     wstrd   wR9,  r1, MMX_WR9
0138     wstrd   wR10, r1, MMX_WR10
0139     wstrd   wR11, r1, MMX_WR11
0140     wstrd   wR12, r1, MMX_WR12
0141     wstrd   wR13, r1, MMX_WR13
0142     wstrd   wR14, r1, MMX_WR14
0143     wstrd   wR15, r1, MMX_WR15
0144 
0145 2:  teq r0, #0              @ anything to load?
0146     reteq   lr              @ if not, return
0147 
0148 concan_load:
0149 
0150     @ Load wRn
0151     wldrd   wR0,  r0, MMX_WR0
0152     wldrd   wR1,  r0, MMX_WR1
0153     wldrd   wR2,  r0, MMX_WR2
0154     wldrd   wR3,  r0, MMX_WR3
0155     wldrd   wR4,  r0, MMX_WR4
0156     wldrd   wR5,  r0, MMX_WR5
0157     wldrd   wR6,  r0, MMX_WR6
0158     wldrd   wR7,  r0, MMX_WR7
0159     wldrd   wR8,  r0, MMX_WR8
0160     wldrd   wR9,  r0, MMX_WR9
0161     wldrd   wR10, r0, MMX_WR10
0162     wldrd   wR11, r0, MMX_WR11
0163     wldrd   wR12, r0, MMX_WR12
0164     wldrd   wR13, r0, MMX_WR13
0165     wldrd   wR14, r0, MMX_WR14
0166     wldrd   wR15, r0, MMX_WR15
0167 
0168     @ Load wCx
0169     wldrw   wCSSF, r0, MMX_WCSSF
0170     wldrw   wCASF, r0, MMX_WCASF
0171     wldrw   wCGR0, r0, MMX_WCGR0
0172     wldrw   wCGR1, r0, MMX_WCGR1
0173     wldrw   wCGR2, r0, MMX_WCGR2
0174     wldrw   wCGR3, r0, MMX_WCGR3
0175 
0176     @ clear CUP/MUP (only if r1 != 0)
0177     teq r1, #0
0178     mov     r2, #0
0179     reteq   lr
0180 
0181     tmcr    wCon, r2
0182     ret lr
0183 
0184 ENDPROC(iwmmxt_task_enable)
0185 
0186 /*
0187  * Back up Concan regs to save area and disable access to them
0188  * (mainly for gdb or sleep mode usage)
0189  *
0190  * r0 = struct thread_info pointer of target task or NULL for any
0191  */
0192 
0193 ENTRY(iwmmxt_task_disable)
0194 
0195     stmfd   sp!, {r4, lr}
0196 
0197     mrs ip, cpsr
0198     orr r2, ip, #PSR_I_BIT      @ disable interrupts
0199     msr cpsr_c, r2
0200 
0201     ldr r3, =concan_owner
0202     add r2, r0, #TI_IWMMXT_STATE    @ get task Concan save area
0203     ldr r1, [r3]            @ get current Concan owner
0204     teq r1, #0              @ any current owner?
0205     beq 1f              @ no: quit
0206     teq r0, #0              @ any owner?
0207     teqne   r1, r2              @ or specified one?
0208     bne 1f              @ no: quit
0209 
0210     @ enable access to CP0 and CP1
0211     XSC(mrc p15, 0, r4, c15, c1, 0)
0212     XSC(orr r4, r4, #0x3)
0213     XSC(mcr p15, 0, r4, c15, c1, 0)
0214     PJ4(mrc p15, 0, r4, c1, c0, 2)
0215     PJ4(orr r4, r4, #0xf)
0216     PJ4(mcr p15, 0, r4, c1, c0, 2)
0217 
0218     mov r0, #0              @ nothing to load
0219     str r0, [r3]            @ no more current owner
0220     mrc p15, 0, r2, c2, c0, 0
0221     mov r2, r2              @ cpwait
0222     bl  concan_save
0223 
0224     @ disable access to CP0 and CP1
0225     XSC(bic r4, r4, #0x3)
0226     XSC(mcr p15, 0, r4, c15, c1, 0)
0227     PJ4(bic r4, r4, #0xf)
0228     PJ4(mcr p15, 0, r4, c1, c0, 2)
0229 
0230     mrc p15, 0, r2, c2, c0, 0
0231     mov r2, r2              @ cpwait
0232 
0233 1:  msr cpsr_c, ip          @ restore interrupt mode
0234     ldmfd   sp!, {r4, pc}
0235 
0236 ENDPROC(iwmmxt_task_disable)
0237 
0238 /*
0239  * Copy Concan state to given memory address
0240  *
0241  * r0 = struct thread_info pointer of target task
0242  * r1 = memory address where to store Concan state
0243  *
0244  * this is called mainly in the creation of signal stack frames
0245  */
0246 
0247 ENTRY(iwmmxt_task_copy)
0248 
0249     mrs ip, cpsr
0250     orr r2, ip, #PSR_I_BIT      @ disable interrupts
0251     msr cpsr_c, r2
0252 
0253     ldr r3, =concan_owner
0254     add r2, r0, #TI_IWMMXT_STATE    @ get task Concan save area
0255     ldr r3, [r3]            @ get current Concan owner
0256     teq r2, r3              @ does this task own it...
0257     beq 1f
0258 
0259     @ current Concan values are in the task save area
0260     msr cpsr_c, ip          @ restore interrupt mode
0261     mov r0, r1
0262     mov r1, r2
0263     mov r2, #MMX_SIZE
0264     b   memcpy
0265 
0266 1:  @ this task owns Concan regs -- grab a copy from there
0267     mov r0, #0              @ nothing to load
0268     mov r2, #3              @ save all regs
0269     mov r3, lr              @ preserve return address
0270     bl  concan_dump
0271     msr cpsr_c, ip          @ restore interrupt mode
0272     ret r3
0273 
0274 ENDPROC(iwmmxt_task_copy)
0275 
0276 /*
0277  * Restore Concan state from given memory address
0278  *
0279  * r0 = struct thread_info pointer of target task
0280  * r1 = memory address where to get Concan state from
0281  *
0282  * this is used to restore Concan state when unwinding a signal stack frame
0283  */
0284 
0285 ENTRY(iwmmxt_task_restore)
0286 
0287     mrs ip, cpsr
0288     orr r2, ip, #PSR_I_BIT      @ disable interrupts
0289     msr cpsr_c, r2
0290 
0291     ldr r3, =concan_owner
0292     add r2, r0, #TI_IWMMXT_STATE    @ get task Concan save area
0293     ldr r3, [r3]            @ get current Concan owner
0294     bic r2, r2, #0x7            @ 64-bit alignment
0295     teq r2, r3              @ does this task own it...
0296     beq 1f
0297 
0298     @ this task doesn't own Concan regs -- use its save area
0299     msr cpsr_c, ip          @ restore interrupt mode
0300     mov r0, r2
0301     mov r2, #MMX_SIZE
0302     b   memcpy
0303 
0304 1:  @ this task owns Concan regs -- load them directly
0305     mov r0, r1
0306     mov r1, #0              @ don't clear CUP/MUP
0307     mov r3, lr              @ preserve return address
0308     bl  concan_load
0309     msr cpsr_c, ip          @ restore interrupt mode
0310     ret r3
0311 
0312 ENDPROC(iwmmxt_task_restore)
0313 
0314 /*
0315  * Concan handling on task switch
0316  *
0317  * r0 = next thread_info pointer
0318  *
0319  * Called only from the iwmmxt notifier with task preemption disabled.
0320  */
0321 ENTRY(iwmmxt_task_switch)
0322 
0323     XSC(mrc p15, 0, r1, c15, c1, 0)
0324     PJ4(mrc p15, 0, r1, c1, c0, 2)
0325     @ CP0 and CP1 accessible?
0326     XSC(tst r1, #0x3)
0327     PJ4(tst r1, #0xf)
0328     bne 1f              @ yes: block them for next task
0329 
0330     ldr r2, =concan_owner
0331     add r3, r0, #TI_IWMMXT_STATE    @ get next task Concan save area
0332     ldr r2, [r2]            @ get current Concan owner
0333     teq r2, r3              @ next task owns it?
0334     retne   lr              @ no: leave Concan disabled
0335 
0336 1:  @ flip Concan access
0337     XSC(eor r1, r1, #0x3)
0338     XSC(mcr p15, 0, r1, c15, c1, 0)
0339     PJ4(eor r1, r1, #0xf)
0340     PJ4(mcr p15, 0, r1, c1, c0, 2)
0341 
0342     mrc p15, 0, r1, c2, c0, 0
0343     sub pc, lr, r1, lsr #32     @ cpwait and return
0344 
0345 ENDPROC(iwmmxt_task_switch)
0346 
0347 /*
0348  * Remove Concan ownership of given task
0349  *
0350  * r0 = struct thread_info pointer
0351  */
0352 ENTRY(iwmmxt_task_release)
0353 
0354     mrs r2, cpsr
0355     orr ip, r2, #PSR_I_BIT      @ disable interrupts
0356     msr cpsr_c, ip
0357     ldr r3, =concan_owner
0358     add r0, r0, #TI_IWMMXT_STATE    @ get task Concan save area
0359     ldr r1, [r3]            @ get current Concan owner
0360     eors    r0, r0, r1          @ if equal...
0361     streq   r0, [r3]            @ then clear ownership
0362     msr cpsr_c, r2          @ restore interrupts
0363     ret lr
0364 
0365 ENDPROC(iwmmxt_task_release)
0366 
0367     .data
0368     .align  2
0369 concan_owner:
0370     .word   0
0371