diff options
Diffstat (limited to 'arch/arm/vfp')
| -rw-r--r-- | arch/arm/vfp/entry.S | 20 | ||||
| -rw-r--r-- | arch/arm/vfp/vfphw.S | 32 | ||||
| -rw-r--r-- | arch/arm/vfp/vfpmodule.c | 27 | 
3 files changed, 47 insertions, 32 deletions
| diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 9a89264cdcc0..62206ef25037 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -22,18 +22,10 @@  @  IRQs enabled.  @  ENTRY(do_vfp) -	local_bh_disable r10, r4 - 	ldr	r4, .LCvfp -	ldr	r11, [r10, #TI_CPU]	@ CPU number -	add	r10, r10, #TI_VFPSTATE	@ r10 = workspace -	ldr	pc, [r4]		@ call VFP entry point +	mov	r1, r10 +	str	lr, [sp, #-8]! +	add	r3, sp, #4 +	str	r9, [r3] +	bl	vfp_entry +	ldr	pc, [sp], #8  ENDPROC(do_vfp) - -ENTRY(vfp_null_entry) -	local_bh_enable_ti r10, r4 -	ret	lr -ENDPROC(vfp_null_entry) - -	.align	2 -.LCvfp: -	.word	vfp_vector diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 26c4f61ecfa3..a4610d0f3215 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -6,9 +6,9 @@   *  Written by Deep Blue Solutions Limited.   *   * This code is called from the kernel's undefined instruction trap. - * r9 holds the return address for successful handling. + * r1 holds the thread_info pointer + * r3 holds the return address for successful handling.   * lr holds the return address for unrecognised instructions. - * r10 points at the start of the private FP workspace in the thread structure   * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h)   */  #include <linux/init.h> @@ -69,13 +69,15 @@  @ VFP hardware support entry point.  @  @  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb) +@  r1  = thread_info pointer  @  r2  = PC value to resume execution after successful emulation -@  r9  = normal "successful" return address -@  r10 = vfp_state union -@  r11 = CPU number +@  r3  = normal "successful" return address  @  lr  = unrecognised instruction return address  @  IRQs enabled.  ENTRY(vfp_support_entry) +	ldr	r11, [r1, #TI_CPU]	@ CPU number +	add	r10, r1, #TI_VFPSTATE	@ r10 = workspace +  	DBGSTR3	"instr %08x pc %08x state %p", r0, r2, r10  	.fpu	vfpv2 @@ -85,9 +87,9 @@ ENTRY(vfp_support_entry)  	bne	look_for_VFP_exceptions	@ VFP is already enabled  	DBGSTR1 "enable %x", r10 -	ldr	r3, vfp_current_hw_state_address +	ldr	r9, vfp_current_hw_state_address  	orr	r1, r1, #FPEXC_EN	@ user FPEXC has the enable bit set -	ldr	r4, [r3, r11, lsl #2]	@ vfp_current_hw_state pointer +	ldr	r4, [r9, r11, lsl #2]	@ vfp_current_hw_state pointer  	bic	r5, r1, #FPEXC_EX	@ make sure exceptions are disabled  	cmp	r4, r10			@ this thread owns the hw context?  #ifndef CONFIG_SMP @@ -146,7 +148,7 @@ vfp_reload_hw:  #endif  	DBGSTR1	"load state %p", r10 -	str	r10, [r3, r11, lsl #2]	@ update the vfp_current_hw_state pointer +	str	r10, [r9, r11, lsl #2]	@ update the vfp_current_hw_state pointer  					@ Load the saved state back into the VFP  	VFPFLDMIA r10, r5		@ reload the working registers while  					@ FPEXC is in a safe state @@ -170,14 +172,18 @@ vfp_hw_state_valid:  					@ out before setting an FPEXC that  					@ stops us reading stuff  	VFPFMXR	FPEXC, r1		@ Restore FPEXC last +	mov	sp, r3			@ we think we have handled things +	pop	{lr}  	sub	r2, r2, #4		@ Retry current instruction - if Thumb  	str	r2, [sp, #S_PC]		@ mode it's two 16-bit instructions,  					@ else it's one 32-bit instruction, so  					@ always subtract 4 from the following  					@ instruction address. -	local_bh_enable_ti r10, r4 -	ret	r9			@ we think we have handled things +local_bh_enable_and_ret: +	adr	r0, . +	mov	r1, #SOFTIRQ_DISABLE_OFFSET +	b	__local_bh_enable_ip	@ tail call  look_for_VFP_exceptions:  	@ Check for synchronous or asynchronous exception @@ -200,13 +206,13 @@ skip:  	@ not recognised by VFP  	DBGSTR	"not VFP" -	local_bh_enable_ti r10, r4 -	ret	lr +	b	local_bh_enable_and_ret  process_exception:  	DBGSTR	"bounce" +	mov	sp, r3			@ setup for a return to the user code. +	pop	{lr}  	mov	r2, sp			@ nothing stacked - regdump is at TOS -	mov	lr, r9			@ setup for a return to the user code.  	@ Now call the C code to package up the bounce to the support code  	@   r0 holds the trigger instruction diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 01bc48d73847..349dcb944a93 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -32,10 +32,9 @@  /*   * Our undef handlers (in entry.S)   */ -asmlinkage void vfp_support_entry(void); -asmlinkage void vfp_null_entry(void); +asmlinkage void vfp_support_entry(u32, void *, u32, u32); -asmlinkage void (*vfp_vector)(void) = vfp_null_entry; +static bool have_vfp __ro_after_init;  /*   * Dual-use variable. @@ -645,6 +644,25 @@ static int vfp_starting_cpu(unsigned int unused)  	return 0;  } +/* + * Entered with: + * + *  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb) + *  r1  = thread_info pointer + *  r2  = PC value to resume execution after successful emulation + *  r3  = normal "successful" return address + *  lr  = unrecognised instruction return address + */ +asmlinkage void vfp_entry(u32 trigger, struct thread_info *ti, u32 resume_pc, +			  u32 resume_return_address) +{ +	if (unlikely(!have_vfp)) +		return; + +	local_bh_disable(); +	vfp_support_entry(trigger, ti, resume_pc, resume_return_address); +} +  #ifdef CONFIG_KERNEL_MODE_NEON  static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr) @@ -798,7 +816,6 @@ static int __init vfp_init(void)  	vfpsid = fmrx(FPSID);  	barrier();  	unregister_undef_hook(&vfp_detect_hook); -	vfp_vector = vfp_null_entry;  	pr_info("VFP support v0.3: ");  	if (VFP_arch) { @@ -883,7 +900,7 @@ static int __init vfp_init(void)  				  "arm/vfp:starting", vfp_starting_cpu,  				  vfp_dying_cpu); -	vfp_vector = vfp_support_entry; +	have_vfp = true;  	thread_register_notifier(&vfp_notifier_block);  	vfp_pm_init(); | 
