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