bitops.h (5772B)
1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * Copyright (C) 2012 Regents of the University of California 4 */ 5 6#ifndef _ASM_RISCV_BITOPS_H 7#define _ASM_RISCV_BITOPS_H 8 9#ifndef _LINUX_BITOPS_H 10#error "Only <linux/bitops.h> can be included directly" 11#endif /* _LINUX_BITOPS_H */ 12 13#include <linux/compiler.h> 14#include <linux/irqflags.h> 15#include <asm/barrier.h> 16#include <asm/bitsperlong.h> 17 18#include <asm-generic/bitops/__ffs.h> 19#include <asm-generic/bitops/ffz.h> 20#include <asm-generic/bitops/fls.h> 21#include <asm-generic/bitops/__fls.h> 22#include <asm-generic/bitops/fls64.h> 23#include <asm-generic/bitops/sched.h> 24#include <asm-generic/bitops/ffs.h> 25 26#include <asm-generic/bitops/hweight.h> 27 28#if (BITS_PER_LONG == 64) 29#define __AMO(op) "amo" #op ".d" 30#elif (BITS_PER_LONG == 32) 31#define __AMO(op) "amo" #op ".w" 32#else 33#error "Unexpected BITS_PER_LONG" 34#endif 35 36#define __test_and_op_bit_ord(op, mod, nr, addr, ord) \ 37({ \ 38 unsigned long __res, __mask; \ 39 __mask = BIT_MASK(nr); \ 40 __asm__ __volatile__ ( \ 41 __AMO(op) #ord " %0, %2, %1" \ 42 : "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \ 43 : "r" (mod(__mask)) \ 44 : "memory"); \ 45 ((__res & __mask) != 0); \ 46}) 47 48#define __op_bit_ord(op, mod, nr, addr, ord) \ 49 __asm__ __volatile__ ( \ 50 __AMO(op) #ord " zero, %1, %0" \ 51 : "+A" (addr[BIT_WORD(nr)]) \ 52 : "r" (mod(BIT_MASK(nr))) \ 53 : "memory"); 54 55#define __test_and_op_bit(op, mod, nr, addr) \ 56 __test_and_op_bit_ord(op, mod, nr, addr, .aqrl) 57#define __op_bit(op, mod, nr, addr) \ 58 __op_bit_ord(op, mod, nr, addr, ) 59 60/* Bitmask modifiers */ 61#define __NOP(x) (x) 62#define __NOT(x) (~(x)) 63 64/** 65 * test_and_set_bit - Set a bit and return its old value 66 * @nr: Bit to set 67 * @addr: Address to count from 68 * 69 * This operation may be reordered on other architectures than x86. 70 */ 71static inline int test_and_set_bit(int nr, volatile unsigned long *addr) 72{ 73 return __test_and_op_bit(or, __NOP, nr, addr); 74} 75 76/** 77 * test_and_clear_bit - Clear a bit and return its old value 78 * @nr: Bit to clear 79 * @addr: Address to count from 80 * 81 * This operation can be reordered on other architectures other than x86. 82 */ 83static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) 84{ 85 return __test_and_op_bit(and, __NOT, nr, addr); 86} 87 88/** 89 * test_and_change_bit - Change a bit and return its old value 90 * @nr: Bit to change 91 * @addr: Address to count from 92 * 93 * This operation is atomic and cannot be reordered. 94 * It also implies a memory barrier. 95 */ 96static inline int test_and_change_bit(int nr, volatile unsigned long *addr) 97{ 98 return __test_and_op_bit(xor, __NOP, nr, addr); 99} 100 101/** 102 * set_bit - Atomically set a bit in memory 103 * @nr: the bit to set 104 * @addr: the address to start counting from 105 * 106 * Note: there are no guarantees that this function will not be reordered 107 * on non x86 architectures, so if you are writing portable code, 108 * make sure not to rely on its reordering guarantees. 109 * 110 * Note that @nr may be almost arbitrarily large; this function is not 111 * restricted to acting on a single-word quantity. 112 */ 113static inline void set_bit(int nr, volatile unsigned long *addr) 114{ 115 __op_bit(or, __NOP, nr, addr); 116} 117 118/** 119 * clear_bit - Clears a bit in memory 120 * @nr: Bit to clear 121 * @addr: Address to start counting from 122 * 123 * Note: there are no guarantees that this function will not be reordered 124 * on non x86 architectures, so if you are writing portable code, 125 * make sure not to rely on its reordering guarantees. 126 */ 127static inline void clear_bit(int nr, volatile unsigned long *addr) 128{ 129 __op_bit(and, __NOT, nr, addr); 130} 131 132/** 133 * change_bit - Toggle a bit in memory 134 * @nr: Bit to change 135 * @addr: Address to start counting from 136 * 137 * change_bit() may be reordered on other architectures than x86. 138 * Note that @nr may be almost arbitrarily large; this function is not 139 * restricted to acting on a single-word quantity. 140 */ 141static inline void change_bit(int nr, volatile unsigned long *addr) 142{ 143 __op_bit(xor, __NOP, nr, addr); 144} 145 146/** 147 * test_and_set_bit_lock - Set a bit and return its old value, for lock 148 * @nr: Bit to set 149 * @addr: Address to count from 150 * 151 * This operation is atomic and provides acquire barrier semantics. 152 * It can be used to implement bit locks. 153 */ 154static inline int test_and_set_bit_lock( 155 unsigned long nr, volatile unsigned long *addr) 156{ 157 return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq); 158} 159 160/** 161 * clear_bit_unlock - Clear a bit in memory, for unlock 162 * @nr: the bit to set 163 * @addr: the address to start counting from 164 * 165 * This operation is atomic and provides release barrier semantics. 166 */ 167static inline void clear_bit_unlock( 168 unsigned long nr, volatile unsigned long *addr) 169{ 170 __op_bit_ord(and, __NOT, nr, addr, .rl); 171} 172 173/** 174 * __clear_bit_unlock - Clear a bit in memory, for unlock 175 * @nr: the bit to set 176 * @addr: the address to start counting from 177 * 178 * This operation is like clear_bit_unlock, however it is not atomic. 179 * It does provide release barrier semantics so it can be used to unlock 180 * a bit lock, however it would only be used if no other CPU can modify 181 * any bits in the memory until the lock is released (a good example is 182 * if the bit lock itself protects access to the other bits in the word). 183 * 184 * On RISC-V systems there seems to be no benefit to taking advantage of the 185 * non-atomic property here: it's a lot more instructions and we still have to 186 * provide release semantics anyway. 187 */ 188static inline void __clear_bit_unlock( 189 unsigned long nr, volatile unsigned long *addr) 190{ 191 clear_bit_unlock(nr, addr); 192} 193 194#undef __test_and_op_bit 195#undef __op_bit 196#undef __NOP 197#undef __NOT 198#undef __AMO 199 200#include <asm-generic/bitops/non-atomic.h> 201#include <asm-generic/bitops/le.h> 202#include <asm-generic/bitops/ext2-atomic.h> 203 204#endif /* _ASM_RISCV_BITOPS_H */