162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#include <asm/assembler.h>
362306a36Sopenharmony_ci#include <asm/unwind.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6
662306a36Sopenharmony_ci	.macro	bitop, name, instr
762306a36Sopenharmony_ciENTRY(	\name		)
862306a36Sopenharmony_ciUNWIND(	.fnstart	)
962306a36Sopenharmony_ci	ands	ip, r1, #3
1062306a36Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
1162306a36Sopenharmony_ci	mov	r2, #1
1262306a36Sopenharmony_ci	and	r3, r0, #31		@ Get bit offset
1362306a36Sopenharmony_ci	mov	r0, r0, lsr #5
1462306a36Sopenharmony_ci	add	r1, r1, r0, lsl #2	@ Get word offset
1562306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
1662306a36Sopenharmony_ci	.arch_extension	mp
1762306a36Sopenharmony_ci	ALT_SMP(W(pldw)	[r1])
1862306a36Sopenharmony_ci	ALT_UP(W(nop))
1962306a36Sopenharmony_ci#endif
2062306a36Sopenharmony_ci	mov	r3, r2, lsl r3
2162306a36Sopenharmony_ci1:	ldrex	r2, [r1]
2262306a36Sopenharmony_ci	\instr	r2, r2, r3
2362306a36Sopenharmony_ci	strex	r0, r2, [r1]
2462306a36Sopenharmony_ci	cmp	r0, #0
2562306a36Sopenharmony_ci	bne	1b
2662306a36Sopenharmony_ci	bx	lr
2762306a36Sopenharmony_ciUNWIND(	.fnend		)
2862306a36Sopenharmony_ciENDPROC(\name		)
2962306a36Sopenharmony_ci	.endm
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	.macro	__testop, name, instr, store, barrier
3262306a36Sopenharmony_ciENTRY(	\name		)
3362306a36Sopenharmony_ciUNWIND(	.fnstart	)
3462306a36Sopenharmony_ci	ands	ip, r1, #3
3562306a36Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
3662306a36Sopenharmony_ci	mov	r2, #1
3762306a36Sopenharmony_ci	and	r3, r0, #31		@ Get bit offset
3862306a36Sopenharmony_ci	mov	r0, r0, lsr #5
3962306a36Sopenharmony_ci	add	r1, r1, r0, lsl #2	@ Get word offset
4062306a36Sopenharmony_ci	mov	r3, r2, lsl r3		@ create mask
4162306a36Sopenharmony_ci	\barrier
4262306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
4362306a36Sopenharmony_ci	.arch_extension	mp
4462306a36Sopenharmony_ci	ALT_SMP(W(pldw)	[r1])
4562306a36Sopenharmony_ci	ALT_UP(W(nop))
4662306a36Sopenharmony_ci#endif
4762306a36Sopenharmony_ci1:	ldrex	r2, [r1]
4862306a36Sopenharmony_ci	ands	r0, r2, r3		@ save old value of bit
4962306a36Sopenharmony_ci	\instr	r2, r2, r3		@ toggle bit
5062306a36Sopenharmony_ci	strex	ip, r2, [r1]
5162306a36Sopenharmony_ci	cmp	ip, #0
5262306a36Sopenharmony_ci	bne	1b
5362306a36Sopenharmony_ci	\barrier
5462306a36Sopenharmony_ci	cmp	r0, #0
5562306a36Sopenharmony_ci	movne	r0, #1
5662306a36Sopenharmony_ci2:	bx	lr
5762306a36Sopenharmony_ciUNWIND(	.fnend		)
5862306a36Sopenharmony_ciENDPROC(\name		)
5962306a36Sopenharmony_ci	.endm
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	.macro	testop, name, instr, store
6262306a36Sopenharmony_ci	__testop \name, \instr, \store, smp_dmb
6362306a36Sopenharmony_ci	.endm
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	.macro	sync_testop, name, instr, store
6662306a36Sopenharmony_ci	__testop \name, \instr, \store, __smp_dmb
6762306a36Sopenharmony_ci	.endm
6862306a36Sopenharmony_ci#else
6962306a36Sopenharmony_ci	.macro	bitop, name, instr
7062306a36Sopenharmony_ciENTRY(	\name		)
7162306a36Sopenharmony_ciUNWIND(	.fnstart	)
7262306a36Sopenharmony_ci	ands	ip, r1, #3
7362306a36Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
7462306a36Sopenharmony_ci	and	r2, r0, #31
7562306a36Sopenharmony_ci	mov	r0, r0, lsr #5
7662306a36Sopenharmony_ci	mov	r3, #1
7762306a36Sopenharmony_ci	mov	r3, r3, lsl r2
7862306a36Sopenharmony_ci	save_and_disable_irqs ip
7962306a36Sopenharmony_ci	ldr	r2, [r1, r0, lsl #2]
8062306a36Sopenharmony_ci	\instr	r2, r2, r3
8162306a36Sopenharmony_ci	str	r2, [r1, r0, lsl #2]
8262306a36Sopenharmony_ci	restore_irqs ip
8362306a36Sopenharmony_ci	ret	lr
8462306a36Sopenharmony_ciUNWIND(	.fnend		)
8562306a36Sopenharmony_ciENDPROC(\name		)
8662306a36Sopenharmony_ci	.endm
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * testop - implement a test_and_xxx_bit operation.
9062306a36Sopenharmony_ci * @instr: operational instruction
9162306a36Sopenharmony_ci * @store: store instruction
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * Note: we can trivially conditionalise the store instruction
9462306a36Sopenharmony_ci * to avoid dirtying the data cache.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci	.macro	testop, name, instr, store
9762306a36Sopenharmony_ciENTRY(	\name		)
9862306a36Sopenharmony_ciUNWIND(	.fnstart	)
9962306a36Sopenharmony_ci	ands	ip, r1, #3
10062306a36Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
10162306a36Sopenharmony_ci	and	r3, r0, #31
10262306a36Sopenharmony_ci	mov	r0, r0, lsr #5
10362306a36Sopenharmony_ci	save_and_disable_irqs ip
10462306a36Sopenharmony_ci	ldr	r2, [r1, r0, lsl #2]!
10562306a36Sopenharmony_ci	mov	r0, #1
10662306a36Sopenharmony_ci	tst	r2, r0, lsl r3
10762306a36Sopenharmony_ci	\instr	r2, r2, r0, lsl r3
10862306a36Sopenharmony_ci	\store	r2, [r1]
10962306a36Sopenharmony_ci	moveq	r0, #0
11062306a36Sopenharmony_ci	restore_irqs ip
11162306a36Sopenharmony_ci	ret	lr
11262306a36Sopenharmony_ciUNWIND(	.fnend		)
11362306a36Sopenharmony_ciENDPROC(\name		)
11462306a36Sopenharmony_ci	.endm
11562306a36Sopenharmony_ci#endif
116