xref: /linux/arch/arm/lib/bitops.h (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
26ebbf2ceSRussell King #include <asm/assembler.h>
3c36ef4b1SWill Deacon #include <asm/unwind.h>
4c36ef4b1SWill Deacon 
56323f0ccSRussell King #if __LINUX_ARM_ARCH__ >= 6
6c36ef4b1SWill Deacon 	.macro	bitop, name, instr
7c36ef4b1SWill Deacon ENTRY(	\name		)
8c36ef4b1SWill Deacon UNWIND(	.fnstart	)
9a16ede35SRussell King 	ands	ip, r1, #3
10c001899aSStefan Agner 	strbne	r1, [ip]		@ assert word-aligned
1154ea06f6SRussell King 	mov	r2, #1
126323f0ccSRussell King 	and	r3, r0, #31		@ Get bit offset
136323f0ccSRussell King 	mov	r0, r0, lsr #5
146323f0ccSRussell King 	add	r1, r1, r0, lsl #2	@ Get word offset
15b7ec6994SWill Deacon #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
16d779c07dSWill Deacon 	.arch_extension	mp
17d779c07dSWill Deacon 	ALT_SMP(W(pldw)	[r1])
18d779c07dSWill Deacon 	ALT_UP(W(nop))
19d779c07dSWill Deacon #endif
2054ea06f6SRussell King 	mov	r3, r2, lsl r3
216323f0ccSRussell King 1:	ldrex	r2, [r1]
2254ea06f6SRussell King 	\instr	r2, r2, r3
236323f0ccSRussell King 	strex	r0, r2, [r1]
24e7ec0293SRussell King 	cmp	r0, #0
2554ea06f6SRussell King 	bne	1b
263ba6e69aSDave Martin 	bx	lr
27c36ef4b1SWill Deacon UNWIND(	.fnend		)
28c36ef4b1SWill Deacon ENDPROC(\name		)
2954ea06f6SRussell King 	.endm
3054ea06f6SRussell King 
31*dda5f312SMark Rutland 	.macro	__testop, name, instr, store, barrier
32c36ef4b1SWill Deacon ENTRY(	\name		)
33c36ef4b1SWill Deacon UNWIND(	.fnstart	)
34a16ede35SRussell King 	ands	ip, r1, #3
35c001899aSStefan Agner 	strbne	r1, [ip]		@ assert word-aligned
3654ea06f6SRussell King 	mov	r2, #1
376323f0ccSRussell King 	and	r3, r0, #31		@ Get bit offset
386323f0ccSRussell King 	mov	r0, r0, lsr #5
396323f0ccSRussell King 	add	r1, r1, r0, lsl #2	@ Get word offset
4054ea06f6SRussell King 	mov	r3, r2, lsl r3		@ create mask
41*dda5f312SMark Rutland 	\barrier
42c32ffce0SWill Deacon #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
43c32ffce0SWill Deacon 	.arch_extension	mp
44c32ffce0SWill Deacon 	ALT_SMP(W(pldw)	[r1])
45c32ffce0SWill Deacon 	ALT_UP(W(nop))
46c32ffce0SWill Deacon #endif
476323f0ccSRussell King 1:	ldrex	r2, [r1]
4854ea06f6SRussell King 	ands	r0, r2, r3		@ save old value of bit
49614d73edSRussell King 	\instr	r2, r2, r3		@ toggle bit
506323f0ccSRussell King 	strex	ip, r2, [r1]
51614d73edSRussell King 	cmp	ip, #0
5254ea06f6SRussell King 	bne	1b
53*dda5f312SMark Rutland 	\barrier
5454ea06f6SRussell King 	cmp	r0, #0
5554ea06f6SRussell King 	movne	r0, #1
563ba6e69aSDave Martin 2:	bx	lr
57c36ef4b1SWill Deacon UNWIND(	.fnend		)
58c36ef4b1SWill Deacon ENDPROC(\name		)
5954ea06f6SRussell King 	.endm
60*dda5f312SMark Rutland 
61*dda5f312SMark Rutland 	.macro	testop, name, instr, store
62*dda5f312SMark Rutland 	__testop \name, \instr, \store, smp_dmb
63*dda5f312SMark Rutland 	.endm
64*dda5f312SMark Rutland 
65*dda5f312SMark Rutland 	.macro	sync_testop, name, instr, store
66*dda5f312SMark Rutland 	__testop \name, \instr, \store, __smp_dmb
67*dda5f312SMark Rutland 	.endm
6854ea06f6SRussell King #else
69c36ef4b1SWill Deacon 	.macro	bitop, name, instr
70c36ef4b1SWill Deacon ENTRY(	\name		)
71c36ef4b1SWill Deacon UNWIND(	.fnstart	)
72a16ede35SRussell King 	ands	ip, r1, #3
73c001899aSStefan Agner 	strbne	r1, [ip]		@ assert word-aligned
746323f0ccSRussell King 	and	r2, r0, #31
756323f0ccSRussell King 	mov	r0, r0, lsr #5
767a55fd0bSRussell King 	mov	r3, #1
777a55fd0bSRussell King 	mov	r3, r3, lsl r2
7859d1ff3bSRussell King 	save_and_disable_irqs ip
796323f0ccSRussell King 	ldr	r2, [r1, r0, lsl #2]
807a55fd0bSRussell King 	\instr	r2, r2, r3
816323f0ccSRussell King 	str	r2, [r1, r0, lsl #2]
827a55fd0bSRussell King 	restore_irqs ip
836ebbf2ceSRussell King 	ret	lr
84c36ef4b1SWill Deacon UNWIND(	.fnend		)
85c36ef4b1SWill Deacon ENDPROC(\name		)
867a55fd0bSRussell King 	.endm
877a55fd0bSRussell King 
887a55fd0bSRussell King /**
897a55fd0bSRussell King  * testop - implement a test_and_xxx_bit operation.
907a55fd0bSRussell King  * @instr: operational instruction
917a55fd0bSRussell King  * @store: store instruction
927a55fd0bSRussell King  *
937a55fd0bSRussell King  * Note: we can trivially conditionalise the store instruction
946cbdc8c5SSimon Arlott  * to avoid dirtying the data cache.
957a55fd0bSRussell King  */
96c36ef4b1SWill Deacon 	.macro	testop, name, instr, store
97c36ef4b1SWill Deacon ENTRY(	\name		)
98c36ef4b1SWill Deacon UNWIND(	.fnstart	)
99a16ede35SRussell King 	ands	ip, r1, #3
100c001899aSStefan Agner 	strbne	r1, [ip]		@ assert word-aligned
1016323f0ccSRussell King 	and	r3, r0, #31
1026323f0ccSRussell King 	mov	r0, r0, lsr #5
10359d1ff3bSRussell King 	save_and_disable_irqs ip
1046323f0ccSRussell King 	ldr	r2, [r1, r0, lsl #2]!
1056323f0ccSRussell King 	mov	r0, #1
1067a55fd0bSRussell King 	tst	r2, r0, lsl r3
1077a55fd0bSRussell King 	\instr	r2, r2, r0, lsl r3
1087a55fd0bSRussell King 	\store	r2, [r1]
1097a55fd0bSRussell King 	moveq	r0, #0
1100d928b0bSUwe Kleine-König 	restore_irqs ip
1116ebbf2ceSRussell King 	ret	lr
112c36ef4b1SWill Deacon UNWIND(	.fnend		)
113c36ef4b1SWill Deacon ENDPROC(\name		)
1147a55fd0bSRussell King 	.endm
11554ea06f6SRussell King #endif
116