1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 /*
4  * This file provides wrappers with sanitizer instrumentation for atomic bit
5  * operations.
6  *
7  * To use this functionality, an arch's bitops.h file needs to define each of
8  * the below bit operations with an arch_ prefix (e.g. arch_set_bit(),
9  * arch___set_bit(), etc.).
10  */
11 #ifndef _ASM_GENERIC_BITOPS_INSTRUMENTED_ATOMIC_H
12 #define _ASM_GENERIC_BITOPS_INSTRUMENTED_ATOMIC_H
13 
14 #include <linux/instrumented.h>
15 
16 /**
17  * set_bit - Atomically set a bit in memory
18  * @nr: the bit to set
19  * @addr: the address to start counting from
20  *
21  * This is a relaxed atomic operation (no implied memory barriers).
22  *
23  * Note that @nr may be almost arbitrarily large; this function is not
24  * restricted to acting on a single-word quantity.
25  */
26 static __always_inline void set_bit(long nr, volatile unsigned long *addr)
27 {
28 	instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
29 	arch_set_bit(nr, addr);
30 }
31 
32 /**
33  * clear_bit - Clears a bit in memory
34  * @nr: Bit to clear
35  * @addr: Address to start counting from
36  *
37  * This is a relaxed atomic operation (no implied memory barriers).
38  */
39 static __always_inline void clear_bit(long nr, volatile unsigned long *addr)
40 {
41 	instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
42 	arch_clear_bit(nr, addr);
43 }
44 
45 /**
46  * change_bit - Toggle a bit in memory
47  * @nr: Bit to change
48  * @addr: Address to start counting from
49  *
50  * This is a relaxed atomic operation (no implied memory barriers).
51  *
52  * Note that @nr may be almost arbitrarily large; this function is not
53  * restricted to acting on a single-word quantity.
54  */
55 static __always_inline void change_bit(long nr, volatile unsigned long *addr)
56 {
57 	instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
58 	arch_change_bit(nr, addr);
59 }
60 
61 /**
62  * test_and_set_bit - Set a bit and return its old value
63  * @nr: Bit to set
64  * @addr: Address to count from
65  *
66  * This is an atomic fully-ordered operation (implied full memory barrier).
67  */
68 static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
69 {
70 	kcsan_mb();
71 	instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
72 	return arch_test_and_set_bit(nr, addr);
73 }
74 
75 /**
76  * test_and_clear_bit - Clear a bit and return its old value
77  * @nr: Bit to clear
78  * @addr: Address to count from
79  *
80  * This is an atomic fully-ordered operation (implied full memory barrier).
81  */
82 static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
83 {
84 	kcsan_mb();
85 	instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
86 	return arch_test_and_clear_bit(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 is an atomic fully-ordered operation (implied full memory barrier).
95  */
96 static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr)
97 {
98 	kcsan_mb();
99 	instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
100 	return arch_test_and_change_bit(nr, addr);
101 }
102 
103 #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */
104