Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+33 -4
+16
arch/arm/include/asm/thread_info.h
··· 40 40 DECLARE_PER_CPU(struct task_struct *, __entry_task); 41 41 42 42 #include <asm/types.h> 43 + #include <asm/traps.h> 43 44 44 45 struct cpu_context_save { 45 46 __u32 r4; ··· 104 103 extern void iwmmxt_task_restore(struct thread_info *, void *); 105 104 extern void iwmmxt_task_release(struct thread_info *); 106 105 extern void iwmmxt_task_switch(struct thread_info *); 106 + 107 + extern int iwmmxt_undef_handler(struct pt_regs *, u32); 108 + 109 + static inline void register_iwmmxt_undef_handler(void) 110 + { 111 + static struct undef_hook iwmmxt_undef_hook = { 112 + .instr_mask = 0x0c000e00, 113 + .instr_val = 0x0c000000, 114 + .cpsr_mask = MODE_MASK | PSR_T_BIT, 115 + .cpsr_val = USR_MODE, 116 + .fn = iwmmxt_undef_handler, 117 + }; 118 + 119 + register_undef_hook(&iwmmxt_undef_hook); 120 + } 107 121 108 122 extern void vfp_sync_hwstate(struct thread_info *); 109 123 extern void vfp_flush_hwstate(struct thread_info *);
+1
arch/arm/kernel/entry-armv.S
··· 507 507 ldr r5, [r10, #TI_FLAGS] 508 508 rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only 509 509 movscs r7, r5, lsr #(TIF_USING_IWMMXT + 1) 510 + movcs r0, sp @ pass struct pt_regs 510 511 bcs iwmmxt_task_enable 511 512 #endif 512 513 ARM( add pc, pc, r8, lsr #6 )
+14 -4
arch/arm/kernel/iwmmxt.S
··· 58 58 .text 59 59 .arm 60 60 61 + ENTRY(iwmmxt_undef_handler) 62 + push {r9, r10, lr} 63 + get_thread_info r10 64 + mov r9, pc 65 + b iwmmxt_task_enable 66 + mov r0, #0 67 + pop {r9, r10, pc} 68 + ENDPROC(iwmmxt_undef_handler) 69 + 61 70 /* 62 71 * Lazy switching of Concan coprocessor context 63 72 * 73 + * r0 = struct pt_regs pointer 64 74 * r10 = struct thread_info pointer 65 75 * r9 = ret_from_exception 66 76 * lr = undefined instr exit ··· 94 84 PJ4(mcr p15, 0, r2, c1, c0, 2) 95 85 96 86 ldr r3, =concan_owner 97 - add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area 98 - ldr r2, [sp, #60] @ current task pc value 87 + ldr r2, [r0, #S_PC] @ current task pc value 99 88 ldr r1, [r3] @ get current Concan owner 100 - str r0, [r3] @ this task now owns Concan regs 101 89 sub r2, r2, #4 @ adjust pc back 102 - str r2, [sp, #60] 90 + str r2, [r0, #S_PC] 91 + add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area 92 + str r0, [r3] @ this task now owns Concan regs 103 93 104 94 mrc p15, 0, r2, c2, c0, 0 105 95 mov r2, r2 @ cpwait
+1
arch/arm/kernel/pj4-cp0.c
··· 126 126 pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers); 127 127 elf_hwcap |= HWCAP_IWMMXT; 128 128 thread_register_notifier(&iwmmxt_notifier_block); 129 + register_iwmmxt_undef_handler(); 129 130 #endif 130 131 131 132 return 0;
+1
arch/arm/kernel/xscale-cp0.c
··· 166 166 pr_info("XScale iWMMXt coprocessor detected.\n"); 167 167 elf_hwcap |= HWCAP_IWMMXT; 168 168 thread_register_notifier(&iwmmxt_notifier_block); 169 + register_iwmmxt_undef_handler(); 169 170 #endif 170 171 } else { 171 172 pr_info("XScale DSP coprocessor detected.\n");