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