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