• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef __M32R_LOCAL_H
2 #define __M32R_LOCAL_H
3 
4 /*
5  *  linux/include/asm-m32r/local.h
6  *
7  *  M32R version:
8  *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
9  *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
10  *    Copyright (C) 2007  Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
11  */
12 
13 #include <linux/percpu.h>
14 #include <asm/assembler.h>
15 #include <asm/local.h>
16 
17 /*
18  * Atomic operations that C can't guarantee us.  Useful for
19  * resource counting etc..
20  */
21 
22 /*
23  * Make sure gcc doesn't try to be clever and move things around
24  * on us. We need to use _exactly_ the address the user gave us,
25  * not some alias that contains the same information.
26  */
27 typedef struct { volatile int counter; } local_t;
28 
29 #define LOCAL_INIT(i)	{ (i) }
30 
31 /**
32  * local_read - read local variable
33  * @l: pointer of type local_t
34  *
35  * Atomically reads the value of @l.
36  */
37 #define local_read(l)	((l)->counter)
38 
39 /**
40  * local_set - set local variable
41  * @l: pointer of type local_t
42  * @i: required value
43  *
44  * Atomically sets the value of @l to @i.
45  */
46 #define local_set(l, i)	(((l)->counter) = (i))
47 
48 /**
49  * local_add_return - add long to local variable and return it
50  * @i: long value to add
51  * @l: pointer of type local_t
52  *
53  * Atomically adds @i to @l and return (@i + @l).
54  */
local_add_return(long i,local_t * l)55 static inline long local_add_return(long i, local_t *l)
56 {
57 	unsigned long flags;
58 	long result;
59 
60 	local_irq_save(flags);
61 	__asm__ __volatile__ (
62 		"# local_add_return		\n\t"
63 		DCACHE_CLEAR("%0", "r4", "%1")
64 		"ld %0, @%1;			\n\t"
65 		"add	%0, %2;			\n\t"
66 		"st %0, @%1;			\n\t"
67 		: "=&r" (result)
68 		: "r" (&l->counter), "r" (i)
69 		: "memory"
70 #ifdef CONFIG_CHIP_M32700_TS1
71 		, "r4"
72 #endif	/* CONFIG_CHIP_M32700_TS1 */
73 	);
74 	local_irq_restore(flags);
75 
76 	return result;
77 }
78 
79 /**
80  * local_sub_return - subtract long from local variable and return it
81  * @i: long value to subtract
82  * @l: pointer of type local_t
83  *
84  * Atomically subtracts @i from @l and return (@l - @i).
85  */
local_sub_return(long i,local_t * l)86 static inline long local_sub_return(long i, local_t *l)
87 {
88 	unsigned long flags;
89 	long result;
90 
91 	local_irq_save(flags);
92 	__asm__ __volatile__ (
93 		"# local_sub_return		\n\t"
94 		DCACHE_CLEAR("%0", "r4", "%1")
95 		"ld %0, @%1;			\n\t"
96 		"sub	%0, %2;			\n\t"
97 		"st %0, @%1;			\n\t"
98 		: "=&r" (result)
99 		: "r" (&l->counter), "r" (i)
100 		: "memory"
101 #ifdef CONFIG_CHIP_M32700_TS1
102 		, "r4"
103 #endif	/* CONFIG_CHIP_M32700_TS1 */
104 	);
105 	local_irq_restore(flags);
106 
107 	return result;
108 }
109 
110 /**
111  * local_add - add long to local variable
112  * @i: long value to add
113  * @l: pointer of type local_t
114  *
115  * Atomically adds @i to @l.
116  */
117 #define local_add(i, l) ((void) local_add_return((i), (l)))
118 
119 /**
120  * local_sub - subtract the local variable
121  * @i: long value to subtract
122  * @l: pointer of type local_t
123  *
124  * Atomically subtracts @i from @l.
125  */
126 #define local_sub(i, l) ((void) local_sub_return((i), (l)))
127 
128 /**
129  * local_sub_and_test - subtract value from variable and test result
130  * @i: integer value to subtract
131  * @l: pointer of type local_t
132  *
133  * Atomically subtracts @i from @l and returns
134  * true if the result is zero, or false for all
135  * other cases.
136  */
137 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
138 
139 /**
140  * local_inc_return - increment local variable and return it
141  * @l: pointer of type local_t
142  *
143  * Atomically increments @l by 1 and returns the result.
144  */
local_inc_return(local_t * l)145 static inline long local_inc_return(local_t *l)
146 {
147 	unsigned long flags;
148 	long result;
149 
150 	local_irq_save(flags);
151 	__asm__ __volatile__ (
152 		"# local_inc_return		\n\t"
153 		DCACHE_CLEAR("%0", "r4", "%1")
154 		"ld %0, @%1;			\n\t"
155 		"addi	%0, #1;			\n\t"
156 		"st %0, @%1;			\n\t"
157 		: "=&r" (result)
158 		: "r" (&l->counter)
159 		: "memory"
160 #ifdef CONFIG_CHIP_M32700_TS1
161 		, "r4"
162 #endif	/* CONFIG_CHIP_M32700_TS1 */
163 	);
164 	local_irq_restore(flags);
165 
166 	return result;
167 }
168 
169 /**
170  * local_dec_return - decrement local variable and return it
171  * @l: pointer of type local_t
172  *
173  * Atomically decrements @l by 1 and returns the result.
174  */
local_dec_return(local_t * l)175 static inline long local_dec_return(local_t *l)
176 {
177 	unsigned long flags;
178 	long result;
179 
180 	local_irq_save(flags);
181 	__asm__ __volatile__ (
182 		"# local_dec_return		\n\t"
183 		DCACHE_CLEAR("%0", "r4", "%1")
184 		"ld %0, @%1;			\n\t"
185 		"addi	%0, #-1;		\n\t"
186 		"st %0, @%1;			\n\t"
187 		: "=&r" (result)
188 		: "r" (&l->counter)
189 		: "memory"
190 #ifdef CONFIG_CHIP_M32700_TS1
191 		, "r4"
192 #endif	/* CONFIG_CHIP_M32700_TS1 */
193 	);
194 	local_irq_restore(flags);
195 
196 	return result;
197 }
198 
199 /**
200  * local_inc - increment local variable
201  * @l: pointer of type local_t
202  *
203  * Atomically increments @l by 1.
204  */
205 #define local_inc(l) ((void)local_inc_return(l))
206 
207 /**
208  * local_dec - decrement local variable
209  * @l: pointer of type local_t
210  *
211  * Atomically decrements @l by 1.
212  */
213 #define local_dec(l) ((void)local_dec_return(l))
214 
215 /**
216  * local_inc_and_test - increment and test
217  * @l: pointer of type local_t
218  *
219  * Atomically increments @l by 1
220  * and returns true if the result is zero, or false for all
221  * other cases.
222  */
223 #define local_inc_and_test(l) (local_inc_return(l) == 0)
224 
225 /**
226  * local_dec_and_test - decrement and test
227  * @l: pointer of type local_t
228  *
229  * Atomically decrements @l by 1 and
230  * returns true if the result is 0, or false for all
231  * other cases.
232  */
233 #define local_dec_and_test(l) (local_dec_return(l) == 0)
234 
235 /**
236  * local_add_negative - add and test if negative
237  * @l: pointer of type local_t
238  * @i: integer value to add
239  *
240  * Atomically adds @i to @l and returns true
241  * if the result is negative, or false when
242  * result is greater than or equal to zero.
243  */
244 #define local_add_negative(i, l) (local_add_return((i), (l)) < 0)
245 
246 #define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n)))
247 #define local_xchg(v, new) (xchg_local(&((l)->counter), new))
248 
249 /**
250  * local_add_unless - add unless the number is a given value
251  * @l: pointer of type local_t
252  * @a: the amount to add to l...
253  * @u: ...unless l is equal to u.
254  *
255  * Atomically adds @a to @l, so long as it was not @u.
256  * Returns non-zero if @l was not @u, and zero otherwise.
257  */
local_add_unless(local_t * l,long a,long u)258 static inline int local_add_unless(local_t *l, long a, long u)
259 {
260 	long c, old;
261 	c = local_read(l);
262 	for (;;) {
263 		if (unlikely(c == (u)))
264 			break;
265 		old = local_cmpxchg((l), c, c + (a));
266 		if (likely(old == c))
267 			break;
268 		c = old;
269 	}
270 	return c != (u);
271 }
272 
273 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
274 
local_clear_mask(unsigned long mask,local_t * addr)275 static inline void local_clear_mask(unsigned long  mask, local_t *addr)
276 {
277 	unsigned long flags;
278 	unsigned long tmp;
279 
280 	local_irq_save(flags);
281 	__asm__ __volatile__ (
282 		"# local_clear_mask		\n\t"
283 		DCACHE_CLEAR("%0", "r5", "%1")
284 		"ld %0, @%1;			\n\t"
285 		"and	%0, %2;			\n\t"
286 		"st %0, @%1;			\n\t"
287 		: "=&r" (tmp)
288 		: "r" (addr), "r" (~mask)
289 		: "memory"
290 #ifdef CONFIG_CHIP_M32700_TS1
291 		, "r5"
292 #endif	/* CONFIG_CHIP_M32700_TS1 */
293 	);
294 	local_irq_restore(flags);
295 }
296 
local_set_mask(unsigned long mask,local_t * addr)297 static inline void local_set_mask(unsigned long  mask, local_t *addr)
298 {
299 	unsigned long flags;
300 	unsigned long tmp;
301 
302 	local_irq_save(flags);
303 	__asm__ __volatile__ (
304 		"# local_set_mask		\n\t"
305 		DCACHE_CLEAR("%0", "r5", "%1")
306 		"ld %0, @%1;			\n\t"
307 		"or	%0, %2;			\n\t"
308 		"st %0, @%1;			\n\t"
309 		: "=&r" (tmp)
310 		: "r" (addr), "r" (mask)
311 		: "memory"
312 #ifdef CONFIG_CHIP_M32700_TS1
313 		, "r5"
314 #endif	/* CONFIG_CHIP_M32700_TS1 */
315 	);
316 	local_irq_restore(flags);
317 }
318 
319 /* Atomic operations are already serializing on m32r */
320 #define smp_mb__before_local_dec()	barrier()
321 #define smp_mb__after_local_dec()	barrier()
322 #define smp_mb__before_local_inc()	barrier()
323 #define smp_mb__after_local_inc()	barrier()
324 
325 /* Use these for per-cpu local_t variables: on some archs they are
326  * much more efficient than these naive implementations.  Note they take
327  * a variable, not an address.
328  */
329 
330 #define __local_inc(l)		((l)->a.counter++)
331 #define __local_dec(l)		((l)->a.counter++)
332 #define __local_add(i, l)	((l)->a.counter += (i))
333 #define __local_sub(i, l)	((l)->a.counter -= (i))
334 
335 /* Use these for per-cpu local_t variables: on some archs they are
336  * much more efficient than these naive implementations.  Note they take
337  * a variable, not an address.
338  */
339 
340 #endif /* __M32R_LOCAL_H */
341