18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef __ASM_SH_BITOPS_OP32_H 38c2ecf20Sopenharmony_ci#define __ASM_SH_BITOPS_OP32_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * The bit modifying instructions on SH-2A are only capable of working 78c2ecf20Sopenharmony_ci * with a 3-bit immediate, which signifies the shift position for the bit 88c2ecf20Sopenharmony_ci * being worked on. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#if defined(__BIG_ENDIAN) 118c2ecf20Sopenharmony_ci#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) 128c2ecf20Sopenharmony_ci#define BYTE_NUMBER(nr) ((nr ^ BITOP_LE_SWIZZLE) / BITS_PER_BYTE) 138c2ecf20Sopenharmony_ci#define BYTE_OFFSET(nr) ((nr ^ BITOP_LE_SWIZZLE) % BITS_PER_BYTE) 148c2ecf20Sopenharmony_ci#else 158c2ecf20Sopenharmony_ci#define BYTE_NUMBER(nr) ((nr) / BITS_PER_BYTE) 168c2ecf20Sopenharmony_ci#define BYTE_OFFSET(nr) ((nr) % BITS_PER_BYTE) 178c2ecf20Sopenharmony_ci#endif 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic inline void __set_bit(int nr, volatile unsigned long *addr) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci if (__builtin_constant_p(nr)) { 228c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 238c2ecf20Sopenharmony_ci "bset.b %1, @(%O2,%0) ! __set_bit\n\t" 248c2ecf20Sopenharmony_ci : "+r" (addr) 258c2ecf20Sopenharmony_ci : "i" (BYTE_OFFSET(nr)), "i" (BYTE_NUMBER(nr)) 268c2ecf20Sopenharmony_ci : "t", "memory" 278c2ecf20Sopenharmony_ci ); 288c2ecf20Sopenharmony_ci } else { 298c2ecf20Sopenharmony_ci unsigned long mask = BIT_MASK(nr); 308c2ecf20Sopenharmony_ci unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci *p |= mask; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic inline void __clear_bit(int nr, volatile unsigned long *addr) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci if (__builtin_constant_p(nr)) { 398c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 408c2ecf20Sopenharmony_ci "bclr.b %1, @(%O2,%0) ! __clear_bit\n\t" 418c2ecf20Sopenharmony_ci : "+r" (addr) 428c2ecf20Sopenharmony_ci : "i" (BYTE_OFFSET(nr)), 438c2ecf20Sopenharmony_ci "i" (BYTE_NUMBER(nr)) 448c2ecf20Sopenharmony_ci : "t", "memory" 458c2ecf20Sopenharmony_ci ); 468c2ecf20Sopenharmony_ci } else { 478c2ecf20Sopenharmony_ci unsigned long mask = BIT_MASK(nr); 488c2ecf20Sopenharmony_ci unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci *p &= ~mask; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * __change_bit - Toggle a bit in memory 568c2ecf20Sopenharmony_ci * @nr: the bit to change 578c2ecf20Sopenharmony_ci * @addr: the address to start counting from 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Unlike change_bit(), this function is non-atomic and may be reordered. 608c2ecf20Sopenharmony_ci * If it's called on the same region of memory simultaneously, the effect 618c2ecf20Sopenharmony_ci * may be that only one operation succeeds. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistatic inline void __change_bit(int nr, volatile unsigned long *addr) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci if (__builtin_constant_p(nr)) { 668c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 678c2ecf20Sopenharmony_ci "bxor.b %1, @(%O2,%0) ! __change_bit\n\t" 688c2ecf20Sopenharmony_ci : "+r" (addr) 698c2ecf20Sopenharmony_ci : "i" (BYTE_OFFSET(nr)), 708c2ecf20Sopenharmony_ci "i" (BYTE_NUMBER(nr)) 718c2ecf20Sopenharmony_ci : "t", "memory" 728c2ecf20Sopenharmony_ci ); 738c2ecf20Sopenharmony_ci } else { 748c2ecf20Sopenharmony_ci unsigned long mask = BIT_MASK(nr); 758c2ecf20Sopenharmony_ci unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci *p ^= mask; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * __test_and_set_bit - Set a bit and return its old value 838c2ecf20Sopenharmony_ci * @nr: Bit to set 848c2ecf20Sopenharmony_ci * @addr: Address to count from 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * This operation is non-atomic and can be reordered. 878c2ecf20Sopenharmony_ci * If two examples of this operation race, one can appear to succeed 888c2ecf20Sopenharmony_ci * but actually fail. You must protect multiple accesses with a lock. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistatic inline int __test_and_set_bit(int nr, volatile unsigned long *addr) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci unsigned long mask = BIT_MASK(nr); 938c2ecf20Sopenharmony_ci unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 948c2ecf20Sopenharmony_ci unsigned long old = *p; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci *p = old | mask; 978c2ecf20Sopenharmony_ci return (old & mask) != 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/** 1018c2ecf20Sopenharmony_ci * __test_and_clear_bit - Clear a bit and return its old value 1028c2ecf20Sopenharmony_ci * @nr: Bit to clear 1038c2ecf20Sopenharmony_ci * @addr: Address to count from 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * This operation is non-atomic and can be reordered. 1068c2ecf20Sopenharmony_ci * If two examples of this operation race, one can appear to succeed 1078c2ecf20Sopenharmony_ci * but actually fail. You must protect multiple accesses with a lock. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci unsigned long mask = BIT_MASK(nr); 1128c2ecf20Sopenharmony_ci unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 1138c2ecf20Sopenharmony_ci unsigned long old = *p; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci *p = old & ~mask; 1168c2ecf20Sopenharmony_ci return (old & mask) != 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* WARNING: non atomic and it can be reordered! */ 1208c2ecf20Sopenharmony_cistatic inline int __test_and_change_bit(int nr, 1218c2ecf20Sopenharmony_ci volatile unsigned long *addr) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci unsigned long mask = BIT_MASK(nr); 1248c2ecf20Sopenharmony_ci unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 1258c2ecf20Sopenharmony_ci unsigned long old = *p; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci *p = old ^ mask; 1288c2ecf20Sopenharmony_ci return (old & mask) != 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * test_bit - Determine whether a bit is set 1338c2ecf20Sopenharmony_ci * @nr: bit number to test 1348c2ecf20Sopenharmony_ci * @addr: Address to start counting from 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cistatic inline int test_bit(int nr, const volatile unsigned long *addr) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#endif /* __ASM_SH_BITOPS_OP32_H */ 142