xref: /openbmc/linux/arch/loongarch/include/asm/local.h (revision db30dc1a)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4  */
5 #ifndef _ARCH_LOONGARCH_LOCAL_H
6 #define _ARCH_LOONGARCH_LOCAL_H
7 
8 #include <linux/percpu.h>
9 #include <linux/bitops.h>
10 #include <linux/atomic.h>
11 #include <asm/cmpxchg.h>
12 #include <asm/compiler.h>
13 
14 typedef struct {
15 	atomic_long_t a;
16 } local_t;
17 
18 #define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
19 
20 #define local_read(l)	atomic_long_read(&(l)->a)
21 #define local_set(l, i) atomic_long_set(&(l)->a, (i))
22 
23 #define local_add(i, l) atomic_long_add((i), (&(l)->a))
24 #define local_sub(i, l) atomic_long_sub((i), (&(l)->a))
25 #define local_inc(l)	atomic_long_inc(&(l)->a)
26 #define local_dec(l)	atomic_long_dec(&(l)->a)
27 
28 /*
29  * Same as above, but return the result value
30  */
31 static inline long local_add_return(long i, local_t *l)
32 {
33 	unsigned long result;
34 
35 	__asm__ __volatile__(
36 	"   " __AMADD " %1, %2, %0      \n"
37 	: "+ZB" (l->a.counter), "=&r" (result)
38 	: "r" (i)
39 	: "memory");
40 	result = result + i;
41 
42 	return result;
43 }
44 
45 static inline long local_sub_return(long i, local_t *l)
46 {
47 	unsigned long result;
48 
49 	__asm__ __volatile__(
50 	"   " __AMADD "%1, %2, %0       \n"
51 	: "+ZB" (l->a.counter), "=&r" (result)
52 	: "r" (-i)
53 	: "memory");
54 
55 	result = result - i;
56 
57 	return result;
58 }
59 
60 #define local_cmpxchg(l, o, n) \
61 	((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
62 #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n)))
63 
64 /**
65  * local_add_unless - add unless the number is a given value
66  * @l: pointer of type local_t
67  * @a: the amount to add to l...
68  * @u: ...unless l is equal to u.
69  *
70  * Atomically adds @a to @l, so long as it was not @u.
71  * Returns non-zero if @l was not @u, and zero otherwise.
72  */
73 #define local_add_unless(l, a, u)				\
74 ({								\
75 	long c, old;						\
76 	c = local_read(l);					\
77 	while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
78 		c = old;					\
79 	c != (u);						\
80 })
81 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
82 
83 #define local_dec_return(l) local_sub_return(1, (l))
84 #define local_inc_return(l) local_add_return(1, (l))
85 
86 /*
87  * local_sub_and_test - subtract value from variable and test result
88  * @i: integer value to subtract
89  * @l: pointer of type local_t
90  *
91  * Atomically subtracts @i from @l and returns
92  * true if the result is zero, or false for all
93  * other cases.
94  */
95 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
96 
97 /*
98  * local_inc_and_test - increment and test
99  * @l: pointer of type local_t
100  *
101  * Atomically increments @l by 1
102  * and returns true if the result is zero, or false for all
103  * other cases.
104  */
105 #define local_inc_and_test(l) (local_inc_return(l) == 0)
106 
107 /*
108  * local_dec_and_test - decrement by 1 and test
109  * @l: pointer of type local_t
110  *
111  * Atomically decrements @l by 1 and
112  * returns true if the result is 0, or false for all other
113  * cases.
114  */
115 #define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
116 
117 /*
118  * local_add_negative - add and test if negative
119  * @l: pointer of type local_t
120  * @i: integer value to add
121  *
122  * Atomically adds @i to @l and returns true
123  * if the result is negative, or false when
124  * result is greater than or equal to zero.
125  */
126 #define local_add_negative(i, l) (local_add_return(i, (l)) < 0)
127 
128 /* Use these for per-cpu local_t variables: on some archs they are
129  * much more efficient than these naive implementations.  Note they take
130  * a variable, not an address.
131  */
132 
133 #define __local_inc(l)		((l)->a.counter++)
134 #define __local_dec(l)		((l)->a.counter++)
135 #define __local_add(i, l)	((l)->a.counter += (i))
136 #define __local_sub(i, l)	((l)->a.counter -= (i))
137 
138 #endif /* _ARCH_LOONGARCH_LOCAL_H */
139