 6ebbf2ce43
			
		
	
	
	6ebbf2ce43
	
	
	
		
			
			ARMv6 and greater introduced a new instruction ("bx") which can be used
to return from function calls.  Recent CPUs perform better when the
"bx lr" instruction is used rather than the "mov pc, lr" instruction,
and this sequence is strongly recommended to be used by the ARM
architecture manual (section A.4.1.1).
We provide a new macro "ret" with all its variants for the condition
code which will resolve to the appropriate instruction.
Rather than doing this piecemeal, and miss some instances, change all
the "mov pc" instances to use the new macro, with the exception of
the "movs" instruction and the kprobes code.  This allows us to detect
the "mov pc, lr" case and fix it up - and also gives us the possibility
of deploying this for other registers depending on the CPU selection.
Reported-by: Will Deacon <will.deacon@arm.com>
Tested-by: Stephen Warren <swarren@nvidia.com> # Tegra Jetson TK1
Tested-by: Robert Jarzmik <robert.jarzmik@free.fr> # mioa701_bootresume.S
Tested-by: Andrew Lunn <andrew@lunn.ch> # Kirkwood
Tested-by: Shawn Guo <shawn.guo@freescale.com>
Tested-by: Tony Lindgren <tony@atomide.com> # OMAPs
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com> # Armada XP, 375, 385
Acked-by: Sekhar Nori <nsekhar@ti.com> # DaVinci
Acked-by: Christoffer Dall <christoffer.dall@linaro.org> # kvm/hyp
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> # PXA3xx
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> # Xen
Tested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> # ARMv7M
Tested-by: Simon Horman <horms+renesas@verge.net.au> # Shmobile
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
		
	
			
		
			
				
	
	
		
			106 lines
		
	
	
	
		
			2.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
	
		
			2.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <asm/assembler.h>
 | |
| #include <asm/unwind.h>
 | |
| 
 | |
| #if __LINUX_ARM_ARCH__ >= 6
 | |
| 	.macro	bitop, name, instr
 | |
| ENTRY(	\name		)
 | |
| UNWIND(	.fnstart	)
 | |
| 	ands	ip, r1, #3
 | |
| 	strneb	r1, [ip]		@ assert word-aligned
 | |
| 	mov	r2, #1
 | |
| 	and	r3, r0, #31		@ Get bit offset
 | |
| 	mov	r0, r0, lsr #5
 | |
| 	add	r1, r1, r0, lsl #2	@ Get word offset
 | |
| #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
 | |
| 	.arch_extension	mp
 | |
| 	ALT_SMP(W(pldw)	[r1])
 | |
| 	ALT_UP(W(nop))
 | |
| #endif
 | |
| 	mov	r3, r2, lsl r3
 | |
| 1:	ldrex	r2, [r1]
 | |
| 	\instr	r2, r2, r3
 | |
| 	strex	r0, r2, [r1]
 | |
| 	cmp	r0, #0
 | |
| 	bne	1b
 | |
| 	bx	lr
 | |
| UNWIND(	.fnend		)
 | |
| ENDPROC(\name		)
 | |
| 	.endm
 | |
| 
 | |
| 	.macro	testop, name, instr, store
 | |
| ENTRY(	\name		)
 | |
| UNWIND(	.fnstart	)
 | |
| 	ands	ip, r1, #3
 | |
| 	strneb	r1, [ip]		@ assert word-aligned
 | |
| 	mov	r2, #1
 | |
| 	and	r3, r0, #31		@ Get bit offset
 | |
| 	mov	r0, r0, lsr #5
 | |
| 	add	r1, r1, r0, lsl #2	@ Get word offset
 | |
| 	mov	r3, r2, lsl r3		@ create mask
 | |
| 	smp_dmb
 | |
| #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
 | |
| 	.arch_extension	mp
 | |
| 	ALT_SMP(W(pldw)	[r1])
 | |
| 	ALT_UP(W(nop))
 | |
| #endif
 | |
| 1:	ldrex	r2, [r1]
 | |
| 	ands	r0, r2, r3		@ save old value of bit
 | |
| 	\instr	r2, r2, r3		@ toggle bit
 | |
| 	strex	ip, r2, [r1]
 | |
| 	cmp	ip, #0
 | |
| 	bne	1b
 | |
| 	smp_dmb
 | |
| 	cmp	r0, #0
 | |
| 	movne	r0, #1
 | |
| 2:	bx	lr
 | |
| UNWIND(	.fnend		)
 | |
| ENDPROC(\name		)
 | |
| 	.endm
 | |
| #else
 | |
| 	.macro	bitop, name, instr
 | |
| ENTRY(	\name		)
 | |
| UNWIND(	.fnstart	)
 | |
| 	ands	ip, r1, #3
 | |
| 	strneb	r1, [ip]		@ assert word-aligned
 | |
| 	and	r2, r0, #31
 | |
| 	mov	r0, r0, lsr #5
 | |
| 	mov	r3, #1
 | |
| 	mov	r3, r3, lsl r2
 | |
| 	save_and_disable_irqs ip
 | |
| 	ldr	r2, [r1, r0, lsl #2]
 | |
| 	\instr	r2, r2, r3
 | |
| 	str	r2, [r1, r0, lsl #2]
 | |
| 	restore_irqs ip
 | |
| 	ret	lr
 | |
| UNWIND(	.fnend		)
 | |
| ENDPROC(\name		)
 | |
| 	.endm
 | |
| 
 | |
| /**
 | |
|  * testop - implement a test_and_xxx_bit operation.
 | |
|  * @instr: operational instruction
 | |
|  * @store: store instruction
 | |
|  *
 | |
|  * Note: we can trivially conditionalise the store instruction
 | |
|  * to avoid dirtying the data cache.
 | |
|  */
 | |
| 	.macro	testop, name, instr, store
 | |
| ENTRY(	\name		)
 | |
| UNWIND(	.fnstart	)
 | |
| 	ands	ip, r1, #3
 | |
| 	strneb	r1, [ip]		@ assert word-aligned
 | |
| 	and	r3, r0, #31
 | |
| 	mov	r0, r0, lsr #5
 | |
| 	save_and_disable_irqs ip
 | |
| 	ldr	r2, [r1, r0, lsl #2]!
 | |
| 	mov	r0, #1
 | |
| 	tst	r2, r0, lsl r3
 | |
| 	\instr	r2, r2, r0, lsl r3
 | |
| 	\store	r2, [r1]
 | |
| 	moveq	r0, #0
 | |
| 	restore_irqs ip
 | |
| 	ret	lr
 | |
| UNWIND(	.fnend		)
 | |
| ENDPROC(\name		)
 | |
| 	.endm
 | |
| #endif
 |