xref: /linux/arch/arm/lib/bitops.h (revision 6a87e0f0ce1ae8d70566935215430e718ea776ff)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <asm/assembler.h>
3 #include <asm/unwind.h>
4 
5 #if __LINUX_ARM_ARCH__ >= 6
6 	.macro	bitop, name, instr
7 ENTRY(	\name		)
8 UNWIND(	.fnstart	)
9 	ands	ip, r1, #3
10 	strbne	r1, [ip]		@ assert word-aligned
11 	mov	r2, #1
12 	and	r3, r0, #31		@ Get bit offset
13 	mov	r0, r0, lsr #5
14 	add	r1, r1, r0, lsl #2	@ Get word offset
15 #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
16 	.arch_extension	mp
17 	ALT_SMP(W(pldw)	[r1])
18 	ALT_UP(W(nop))
19 #endif
20 	mov	r3, r2, lsl r3
21 1:	ldrex	r2, [r1]
22 	\instr	r2, r2, r3
23 	strex	r0, r2, [r1]
24 	cmp	r0, #0
25 	bne	1b
26 	bx	lr
27 UNWIND(	.fnend		)
28 ENDPROC(\name		)
29 	.endm
30 
31 	.macro	__testop, name, instr, store, barrier
32 ENTRY(	\name		)
33 UNWIND(	.fnstart	)
34 	ands	ip, r1, #3
35 	strbne	r1, [ip]		@ assert word-aligned
36 	mov	r2, #1
37 	and	r3, r0, #31		@ Get bit offset
38 	mov	r0, r0, lsr #5
39 	add	r1, r1, r0, lsl #2	@ Get word offset
40 	mov	r3, r2, lsl r3		@ create mask
41 	\barrier
42 #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
43 	.arch_extension	mp
44 	ALT_SMP(W(pldw)	[r1])
45 	ALT_UP(W(nop))
46 #endif
47 1:	ldrex	r2, [r1]
48 	ands	r0, r2, r3		@ save old value of bit
49 	\instr	r2, r2, r3		@ toggle bit
50 	strex	ip, r2, [r1]
51 	cmp	ip, #0
52 	bne	1b
53 	\barrier
54 	cmp	r0, #0
55 	movne	r0, #1
56 2:	bx	lr
57 UNWIND(	.fnend		)
58 ENDPROC(\name		)
59 	.endm
60 
61 	.macro	testop, name, instr, store
62 	__testop \name, \instr, \store, smp_dmb
63 	.endm
64 
65 	.macro	sync_testop, name, instr, store
66 	__testop \name, \instr, \store, __smp_dmb
67 	.endm
68 #else
69 	.macro	bitop, name, instr
70 ENTRY(	\name		)
71 UNWIND(	.fnstart	)
72 	ands	ip, r1, #3
73 	strbne	r1, [ip]		@ assert word-aligned
74 	and	r2, r0, #31
75 	mov	r0, r0, lsr #5
76 	mov	r3, #1
77 	mov	r3, r3, lsl r2
78 	save_and_disable_irqs ip
79 	ldr	r2, [r1, r0, lsl #2]
80 	\instr	r2, r2, r3
81 	str	r2, [r1, r0, lsl #2]
82 	restore_irqs ip
83 	ret	lr
84 UNWIND(	.fnend		)
85 ENDPROC(\name		)
86 	.endm
87 
88 /**
89  * testop - implement a test_and_xxx_bit operation.
90  * @instr: operational instruction
91  * @store: store instruction
92  *
93  * Note: we can trivially conditionalise the store instruction
94  * to avoid dirtying the data cache.
95  */
96 	.macro	testop, name, instr, store
97 ENTRY(	\name		)
98 UNWIND(	.fnstart	)
99 	ands	ip, r1, #3
100 	strbne	r1, [ip]		@ assert word-aligned
101 	and	r3, r0, #31
102 	mov	r0, r0, lsr #5
103 	save_and_disable_irqs ip
104 	ldr	r2, [r1, r0, lsl #2]!
105 	mov	r0, #1
106 	tst	r2, r0, lsl r3
107 	\instr	r2, r2, r0, lsl r3
108 	\store	r2, [r1]
109 	moveq	r0, #0
110 	restore_irqs ip
111 	ret	lr
112 UNWIND(	.fnend		)
113 ENDPROC(\name		)
114 	.endm
115 #endif
116