mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
ARM: iwmmxt: Use undef hook to enable coprocessor for task
Define a undef hook to deal with undef exceptions triggered by iwmmxt instructions that were issued with the coprocessor disabled. This removes the dependency on the coprocessor dispatch code in entry-armv.S, which will be made NWFPE-only in a subsequent patch. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
parent
8bcba70cb5
commit
303d6da167
5 changed files with 33 additions and 4 deletions
|
@ -40,6 +40,7 @@ struct task_struct;
|
||||||
DECLARE_PER_CPU(struct task_struct *, __entry_task);
|
DECLARE_PER_CPU(struct task_struct *, __entry_task);
|
||||||
|
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
|
#include <asm/traps.h>
|
||||||
|
|
||||||
struct cpu_context_save {
|
struct cpu_context_save {
|
||||||
__u32 r4;
|
__u32 r4;
|
||||||
|
@ -104,6 +105,21 @@ extern void iwmmxt_task_restore(struct thread_info *, void *);
|
||||||
extern void iwmmxt_task_release(struct thread_info *);
|
extern void iwmmxt_task_release(struct thread_info *);
|
||||||
extern void iwmmxt_task_switch(struct thread_info *);
|
extern void iwmmxt_task_switch(struct thread_info *);
|
||||||
|
|
||||||
|
extern int iwmmxt_undef_handler(struct pt_regs *, u32);
|
||||||
|
|
||||||
|
static inline void register_iwmmxt_undef_handler(void)
|
||||||
|
{
|
||||||
|
static struct undef_hook iwmmxt_undef_hook = {
|
||||||
|
.instr_mask = 0x0c000e00,
|
||||||
|
.instr_val = 0x0c000000,
|
||||||
|
.cpsr_mask = MODE_MASK | PSR_T_BIT,
|
||||||
|
.cpsr_val = USR_MODE,
|
||||||
|
.fn = iwmmxt_undef_handler,
|
||||||
|
};
|
||||||
|
|
||||||
|
register_undef_hook(&iwmmxt_undef_hook);
|
||||||
|
}
|
||||||
|
|
||||||
extern void vfp_sync_hwstate(struct thread_info *);
|
extern void vfp_sync_hwstate(struct thread_info *);
|
||||||
extern void vfp_flush_hwstate(struct thread_info *);
|
extern void vfp_flush_hwstate(struct thread_info *);
|
||||||
|
|
||||||
|
|
|
@ -507,6 +507,7 @@ ARM_BE8(rev r0, r0) @ little endian instruction
|
||||||
ldr r5, [r10, #TI_FLAGS]
|
ldr r5, [r10, #TI_FLAGS]
|
||||||
rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only
|
rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only
|
||||||
movscs r7, r5, lsr #(TIF_USING_IWMMXT + 1)
|
movscs r7, r5, lsr #(TIF_USING_IWMMXT + 1)
|
||||||
|
movcs r0, sp @ pass struct pt_regs
|
||||||
bcs iwmmxt_task_enable
|
bcs iwmmxt_task_enable
|
||||||
#endif
|
#endif
|
||||||
ARM( add pc, pc, r8, lsr #6 )
|
ARM( add pc, pc, r8, lsr #6 )
|
||||||
|
|
|
@ -58,9 +58,19 @@
|
||||||
.text
|
.text
|
||||||
.arm
|
.arm
|
||||||
|
|
||||||
|
ENTRY(iwmmxt_undef_handler)
|
||||||
|
push {r9, r10, lr}
|
||||||
|
get_thread_info r10
|
||||||
|
mov r9, pc
|
||||||
|
b iwmmxt_task_enable
|
||||||
|
mov r0, #0
|
||||||
|
pop {r9, r10, pc}
|
||||||
|
ENDPROC(iwmmxt_undef_handler)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lazy switching of Concan coprocessor context
|
* Lazy switching of Concan coprocessor context
|
||||||
*
|
*
|
||||||
|
* r0 = struct pt_regs pointer
|
||||||
* r10 = struct thread_info pointer
|
* r10 = struct thread_info pointer
|
||||||
* r9 = ret_from_exception
|
* r9 = ret_from_exception
|
||||||
* lr = undefined instr exit
|
* lr = undefined instr exit
|
||||||
|
@ -84,12 +94,12 @@ ENTRY(iwmmxt_task_enable)
|
||||||
PJ4(mcr p15, 0, r2, c1, c0, 2)
|
PJ4(mcr p15, 0, r2, c1, c0, 2)
|
||||||
|
|
||||||
ldr r3, =concan_owner
|
ldr r3, =concan_owner
|
||||||
add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area
|
ldr r2, [r0, #S_PC] @ current task pc value
|
||||||
ldr r2, [sp, #60] @ current task pc value
|
|
||||||
ldr r1, [r3] @ get current Concan owner
|
ldr r1, [r3] @ get current Concan owner
|
||||||
str r0, [r3] @ this task now owns Concan regs
|
|
||||||
sub r2, r2, #4 @ adjust pc back
|
sub r2, r2, #4 @ adjust pc back
|
||||||
str r2, [sp, #60]
|
str r2, [r0, #S_PC]
|
||||||
|
add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area
|
||||||
|
str r0, [r3] @ this task now owns Concan regs
|
||||||
|
|
||||||
mrc p15, 0, r2, c2, c0, 0
|
mrc p15, 0, r2, c2, c0, 0
|
||||||
mov r2, r2 @ cpwait
|
mov r2, r2 @ cpwait
|
||||||
|
|
|
@ -126,6 +126,7 @@ static int __init pj4_cp0_init(void)
|
||||||
pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
|
pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
|
||||||
elf_hwcap |= HWCAP_IWMMXT;
|
elf_hwcap |= HWCAP_IWMMXT;
|
||||||
thread_register_notifier(&iwmmxt_notifier_block);
|
thread_register_notifier(&iwmmxt_notifier_block);
|
||||||
|
register_iwmmxt_undef_handler();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -166,6 +166,7 @@ static int __init xscale_cp0_init(void)
|
||||||
pr_info("XScale iWMMXt coprocessor detected.\n");
|
pr_info("XScale iWMMXt coprocessor detected.\n");
|
||||||
elf_hwcap |= HWCAP_IWMMXT;
|
elf_hwcap |= HWCAP_IWMMXT;
|
||||||
thread_register_notifier(&iwmmxt_notifier_block);
|
thread_register_notifier(&iwmmxt_notifier_block);
|
||||||
|
register_iwmmxt_undef_handler();
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
pr_info("XScale DSP coprocessor detected.\n");
|
pr_info("XScale DSP coprocessor detected.\n");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue