|  | /* SPDX-License-Identifier: GPL-2.0 */ | 
|  | #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 |