18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#include <asm/assembler.h>
38c2ecf20Sopenharmony_ci#include <asm/unwind.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6
68c2ecf20Sopenharmony_ci	.macro	bitop, name, instr
78c2ecf20Sopenharmony_ciENTRY(	\name		)
88c2ecf20Sopenharmony_ciUNWIND(	.fnstart	)
98c2ecf20Sopenharmony_ci	ands	ip, r1, #3
108c2ecf20Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
118c2ecf20Sopenharmony_ci	mov	r2, #1
128c2ecf20Sopenharmony_ci	and	r3, r0, #31		@ Get bit offset
138c2ecf20Sopenharmony_ci	mov	r0, r0, lsr #5
148c2ecf20Sopenharmony_ci	add	r1, r1, r0, lsl #2	@ Get word offset
158c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
168c2ecf20Sopenharmony_ci	.arch_extension	mp
178c2ecf20Sopenharmony_ci	ALT_SMP(W(pldw)	[r1])
188c2ecf20Sopenharmony_ci	ALT_UP(W(nop))
198c2ecf20Sopenharmony_ci#endif
208c2ecf20Sopenharmony_ci	mov	r3, r2, lsl r3
218c2ecf20Sopenharmony_ci1:	ldrex	r2, [r1]
228c2ecf20Sopenharmony_ci	\instr	r2, r2, r3
238c2ecf20Sopenharmony_ci	strex	r0, r2, [r1]
248c2ecf20Sopenharmony_ci	cmp	r0, #0
258c2ecf20Sopenharmony_ci	bne	1b
268c2ecf20Sopenharmony_ci	bx	lr
278c2ecf20Sopenharmony_ciUNWIND(	.fnend		)
288c2ecf20Sopenharmony_ciENDPROC(\name		)
298c2ecf20Sopenharmony_ci	.endm
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	.macro	testop, name, instr, store
328c2ecf20Sopenharmony_ciENTRY(	\name		)
338c2ecf20Sopenharmony_ciUNWIND(	.fnstart	)
348c2ecf20Sopenharmony_ci	ands	ip, r1, #3
358c2ecf20Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
368c2ecf20Sopenharmony_ci	mov	r2, #1
378c2ecf20Sopenharmony_ci	and	r3, r0, #31		@ Get bit offset
388c2ecf20Sopenharmony_ci	mov	r0, r0, lsr #5
398c2ecf20Sopenharmony_ci	add	r1, r1, r0, lsl #2	@ Get word offset
408c2ecf20Sopenharmony_ci	mov	r3, r2, lsl r3		@ create mask
418c2ecf20Sopenharmony_ci	smp_dmb
428c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
438c2ecf20Sopenharmony_ci	.arch_extension	mp
448c2ecf20Sopenharmony_ci	ALT_SMP(W(pldw)	[r1])
458c2ecf20Sopenharmony_ci	ALT_UP(W(nop))
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci1:	ldrex	r2, [r1]
488c2ecf20Sopenharmony_ci	ands	r0, r2, r3		@ save old value of bit
498c2ecf20Sopenharmony_ci	\instr	r2, r2, r3		@ toggle bit
508c2ecf20Sopenharmony_ci	strex	ip, r2, [r1]
518c2ecf20Sopenharmony_ci	cmp	ip, #0
528c2ecf20Sopenharmony_ci	bne	1b
538c2ecf20Sopenharmony_ci	smp_dmb
548c2ecf20Sopenharmony_ci	cmp	r0, #0
558c2ecf20Sopenharmony_ci	movne	r0, #1
568c2ecf20Sopenharmony_ci2:	bx	lr
578c2ecf20Sopenharmony_ciUNWIND(	.fnend		)
588c2ecf20Sopenharmony_ciENDPROC(\name		)
598c2ecf20Sopenharmony_ci	.endm
608c2ecf20Sopenharmony_ci#else
618c2ecf20Sopenharmony_ci	.macro	bitop, name, instr
628c2ecf20Sopenharmony_ciENTRY(	\name		)
638c2ecf20Sopenharmony_ciUNWIND(	.fnstart	)
648c2ecf20Sopenharmony_ci	ands	ip, r1, #3
658c2ecf20Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
668c2ecf20Sopenharmony_ci	and	r2, r0, #31
678c2ecf20Sopenharmony_ci	mov	r0, r0, lsr #5
688c2ecf20Sopenharmony_ci	mov	r3, #1
698c2ecf20Sopenharmony_ci	mov	r3, r3, lsl r2
708c2ecf20Sopenharmony_ci	save_and_disable_irqs ip
718c2ecf20Sopenharmony_ci	ldr	r2, [r1, r0, lsl #2]
728c2ecf20Sopenharmony_ci	\instr	r2, r2, r3
738c2ecf20Sopenharmony_ci	str	r2, [r1, r0, lsl #2]
748c2ecf20Sopenharmony_ci	restore_irqs ip
758c2ecf20Sopenharmony_ci	ret	lr
768c2ecf20Sopenharmony_ciUNWIND(	.fnend		)
778c2ecf20Sopenharmony_ciENDPROC(\name		)
788c2ecf20Sopenharmony_ci	.endm
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/**
818c2ecf20Sopenharmony_ci * testop - implement a test_and_xxx_bit operation.
828c2ecf20Sopenharmony_ci * @instr: operational instruction
838c2ecf20Sopenharmony_ci * @store: store instruction
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci * Note: we can trivially conditionalise the store instruction
868c2ecf20Sopenharmony_ci * to avoid dirtying the data cache.
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_ci	.macro	testop, name, instr, store
898c2ecf20Sopenharmony_ciENTRY(	\name		)
908c2ecf20Sopenharmony_ciUNWIND(	.fnstart	)
918c2ecf20Sopenharmony_ci	ands	ip, r1, #3
928c2ecf20Sopenharmony_ci	strbne	r1, [ip]		@ assert word-aligned
938c2ecf20Sopenharmony_ci	and	r3, r0, #31
948c2ecf20Sopenharmony_ci	mov	r0, r0, lsr #5
958c2ecf20Sopenharmony_ci	save_and_disable_irqs ip
968c2ecf20Sopenharmony_ci	ldr	r2, [r1, r0, lsl #2]!
978c2ecf20Sopenharmony_ci	mov	r0, #1
988c2ecf20Sopenharmony_ci	tst	r2, r0, lsl r3
998c2ecf20Sopenharmony_ci	\instr	r2, r2, r0, lsl r3
1008c2ecf20Sopenharmony_ci	\store	r2, [r1]
1018c2ecf20Sopenharmony_ci	moveq	r0, #0
1028c2ecf20Sopenharmony_ci	restore_irqs ip
1038c2ecf20Sopenharmony_ci	ret	lr
1048c2ecf20Sopenharmony_ciUNWIND(	.fnend		)
1058c2ecf20Sopenharmony_ciENDPROC(\name		)
1068c2ecf20Sopenharmony_ci	.endm
1078c2ecf20Sopenharmony_ci#endif
108