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