aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Salter <msalter@redhat.com>2010-10-27 12:28:52 -0400
committerDavid Howells <dhowells@redhat.com>2010-10-27 12:28:52 -0400
commit4f81ca13532981192c83da95ed8c8cb285817d99 (patch)
tree737f558ce1683dacc5a294694cfd9f1a9b6fa972
parent278d91c4609d55202c1e63d5fc5f01466cc7bbab (diff)
MN10300: Implement atomic ops using atomic ops unit
Implement atomic ops using the atomic ops unit available in the AM34 CPU. This allows the equivalent of the LL/SC instructions to be found on other CPUs. Signed-off-by: Mark Salter <msalter@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--arch/mn10300/include/asm/atomic.h350
-rw-r--r--arch/mn10300/include/asm/system.h48
2 files changed, 351 insertions, 47 deletions
diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h
index f0cc1f84a72f..92d2f9298e38 100644
--- a/arch/mn10300/include/asm/atomic.h
+++ b/arch/mn10300/include/asm/atomic.h
@@ -1 +1,351 @@
1/* MN10300 Atomic counter operations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#ifndef _ASM_ATOMIC_H
12#define _ASM_ATOMIC_H
13
14#include <asm/irqflags.h>
15
16#ifndef __ASSEMBLY__
17
18#ifdef CONFIG_SMP
19#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
20static inline
21unsigned long __xchg(volatile unsigned long *m, unsigned long val)
22{
23 unsigned long status;
24 unsigned long oldval;
25
26 asm volatile(
27 "1: mov %4,(_AAR,%3) \n"
28 " mov (_ADR,%3),%1 \n"
29 " mov %5,(_ADR,%3) \n"
30 " mov (_ADR,%3),%0 \n" /* flush */
31 " mov (_ASR,%3),%0 \n"
32 " or %0,%0 \n"
33 " bne 1b \n"
34 : "=&r"(status), "=&r"(oldval), "=m"(*m)
35 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
36 : "memory", "cc");
37
38 return oldval;
39}
40
41static inline unsigned long __cmpxchg(volatile unsigned long *m,
42 unsigned long old, unsigned long new)
43{
44 unsigned long status;
45 unsigned long oldval;
46
47 asm volatile(
48 "1: mov %4,(_AAR,%3) \n"
49 " mov (_ADR,%3),%1 \n"
50 " cmp %5,%1 \n"
51 " bne 2f \n"
52 " mov %6,(_ADR,%3) \n"
53 "2: mov (_ADR,%3),%0 \n" /* flush */
54 " mov (_ASR,%3),%0 \n"
55 " or %0,%0 \n"
56 " bne 1b \n"
57 : "=&r"(status), "=&r"(oldval), "=m"(*m)
58 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
59 "r"(old), "r"(new)
60 : "memory", "cc");
61
62 return oldval;
63}
64#else /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
65#error "No SMP atomic operation support!"
66#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
67
68#else /* CONFIG_SMP */
69
70/*
71 * Emulate xchg for non-SMP MN10300
72 */
73struct __xchg_dummy { unsigned long a[100]; };
74#define __xg(x) ((struct __xchg_dummy *)(x))
75
76static inline
77unsigned long __xchg(volatile unsigned long *m, unsigned long val)
78{
79 unsigned long oldval;
80 unsigned long flags;
81
82 flags = arch_local_cli_save();
83 oldval = *m;
84 *m = val;
85 arch_local_irq_restore(flags);
86 return oldval;
87}
88
89/*
90 * Emulate cmpxchg for non-SMP MN10300
91 */
92static inline unsigned long __cmpxchg(volatile unsigned long *m,
93 unsigned long old, unsigned long new)
94{
95 unsigned long oldval;
96 unsigned long flags;
97
98 flags = arch_local_cli_save();
99 oldval = *m;
100 if (oldval == old)
101 *m = new;
102 arch_local_irq_restore(flags);
103 return oldval;
104}
105
106#endif /* CONFIG_SMP */
107
108#define xchg(ptr, v) \
109 ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \
110 (unsigned long)(v)))
111
112#define cmpxchg(ptr, o, n) \
113 ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
114 (unsigned long)(o), \
115 (unsigned long)(n)))
116
117#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v)))
118#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
119
120#endif /* !__ASSEMBLY__ */
121
122#ifndef CONFIG_SMP
1#include <asm-generic/atomic.h> 123#include <asm-generic/atomic.h>
124#else
125
126/*
127 * Atomic operations that C can't guarantee us. Useful for
128 * resource counting etc..
129 */
130
131#define ATOMIC_INIT(i) { (i) }
132
133#ifdef __KERNEL__
134
135/**
136 * atomic_read - read atomic variable
137 * @v: pointer of type atomic_t
138 *
139 * Atomically reads the value of @v. Note that the guaranteed
140 * useful range of an atomic_t is only 24 bits.
141 */
142#define atomic_read(v) ((v)->counter)
143
144/**
145 * atomic_set - set atomic variable
146 * @v: pointer of type atomic_t
147 * @i: required value
148 *
149 * Atomically sets the value of @v to @i. Note that the guaranteed
150 * useful range of an atomic_t is only 24 bits.
151 */
152#define atomic_set(v, i) (((v)->counter) = (i))
153
154/**
155 * atomic_add_return - add integer to atomic variable
156 * @i: integer value to add
157 * @v: pointer of type atomic_t
158 *
159 * Atomically adds @i to @v and returns the result
160 * Note that the guaranteed useful range of an atomic_t is only 24 bits.
161 */
162static inline int atomic_add_return(int i, atomic_t *v)
163{
164 int retval;
165#ifdef CONFIG_SMP
166 int status;
167
168 asm volatile(
169 "1: mov %4,(_AAR,%3) \n"
170 " mov (_ADR,%3),%1 \n"
171 " add %5,%1 \n"
172 " mov %1,(_ADR,%3) \n"
173 " mov (_ADR,%3),%0 \n" /* flush */
174 " mov (_ASR,%3),%0 \n"
175 " or %0,%0 \n"
176 " bne 1b \n"
177 : "=&r"(status), "=&r"(retval), "=m"(v->counter)
178 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
179 : "memory", "cc");
180
181#else
182 unsigned long flags;
183
184 flags = arch_local_cli_save();
185 retval = v->counter;
186 retval += i;
187 v->counter = retval;
188 arch_local_irq_restore(flags);
189#endif
190 return retval;
191}
192
193/**
194 * atomic_sub_return - subtract integer from atomic variable
195 * @i: integer value to subtract
196 * @v: pointer of type atomic_t
197 *
198 * Atomically subtracts @i from @v and returns the result
199 * Note that the guaranteed useful range of an atomic_t is only 24 bits.
200 */
201static inline int atomic_sub_return(int i, atomic_t *v)
202{
203 int retval;
204#ifdef CONFIG_SMP
205 int status;
206
207 asm volatile(
208 "1: mov %4,(_AAR,%3) \n"
209 " mov (_ADR,%3),%1 \n"
210 " sub %5,%1 \n"
211 " mov %1,(_ADR,%3) \n"
212 " mov (_ADR,%3),%0 \n" /* flush */
213 " mov (_ASR,%3),%0 \n"
214 " or %0,%0 \n"
215 " bne 1b \n"
216 : "=&r"(status), "=&r"(retval), "=m"(v->counter)
217 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
218 : "memory", "cc");
219
220#else
221 unsigned long flags;
222 flags = arch_local_cli_save();
223 retval = v->counter;
224 retval -= i;
225 v->counter = retval;
226 arch_local_irq_restore(flags);
227#endif
228 return retval;
229}
230
231static inline int atomic_add_negative(int i, atomic_t *v)
232{
233 return atomic_add_return(i, v) < 0;
234}
235
236static inline void atomic_add(int i, atomic_t *v)
237{
238 atomic_add_return(i, v);
239}
240
241static inline void atomic_sub(int i, atomic_t *v)
242{
243 atomic_sub_return(i, v);
244}
245
246static inline void atomic_inc(atomic_t *v)
247{
248 atomic_add_return(1, v);
249}
250
251static inline void atomic_dec(atomic_t *v)
252{
253 atomic_sub_return(1, v);
254}
255
256#define atomic_dec_return(v) atomic_sub_return(1, (v))
257#define atomic_inc_return(v) atomic_add_return(1, (v))
258
259#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
260#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
261#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
262
263#define atomic_add_unless(v, a, u) \
264({ \
265 int c, old; \
266 c = atomic_read(v); \
267 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
268 c = old; \
269 c != (u); \
270})
271
272#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
273
274/**
275 * atomic_clear_mask - Atomically clear bits in memory
276 * @mask: Mask of the bits to be cleared
277 * @v: pointer to word in memory
278 *
279 * Atomically clears the bits set in mask from the memory word specified.
280 */
281static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
282{
283#ifdef CONFIG_SMP
284 int status;
285
286 asm volatile(
287 "1: mov %3,(_AAR,%2) \n"
288 " mov (_ADR,%2),%0 \n"
289 " and %4,%0 \n"
290 " mov %0,(_ADR,%2) \n"
291 " mov (_ADR,%2),%0 \n" /* flush */
292 " mov (_ASR,%2),%0 \n"
293 " or %0,%0 \n"
294 " bne 1b \n"
295 : "=&r"(status), "=m"(*addr)
296 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask)
297 : "memory", "cc");
298#else
299 unsigned long flags;
300
301 mask = ~mask;
302 flags = arch_local_cli_save();
303 *addr &= mask;
304 arch_local_irq_restore(flags);
305#endif
306}
307
308/**
309 * atomic_set_mask - Atomically set bits in memory
310 * @mask: Mask of the bits to be set
311 * @v: pointer to word in memory
312 *
313 * Atomically sets the bits set in mask from the memory word specified.
314 */
315static inline void atomic_set_mask(unsigned long mask, unsigned long *addr)
316{
317#ifdef CONFIG_SMP
318 int status;
319
320 asm volatile(
321 "1: mov %3,(_AAR,%2) \n"
322 " mov (_ADR,%2),%0 \n"
323 " or %4,%0 \n"
324 " mov %0,(_ADR,%2) \n"
325 " mov (_ADR,%2),%0 \n" /* flush */
326 " mov (_ASR,%2),%0 \n"
327 " or %0,%0 \n"
328 " bne 1b \n"
329 : "=&r"(status), "=m"(*addr)
330 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask)
331 : "memory", "cc");
332#else
333 unsigned long flags;
334
335 flags = arch_local_cli_save();
336 *addr |= mask;
337 arch_local_irq_restore(flags);
338#endif
339}
340
341/* Atomic operations are already serializing on MN10300??? */
342#define smp_mb__before_atomic_dec() barrier()
343#define smp_mb__after_atomic_dec() barrier()
344#define smp_mb__before_atomic_inc() barrier()
345#define smp_mb__after_atomic_inc() barrier()
346
347#include <asm-generic/atomic-long.h>
348
349#endif /* __KERNEL__ */
350#endif /* CONFIG_SMP */
351#endif /* _ASM_ATOMIC_H */
diff --git a/arch/mn10300/include/asm/system.h b/arch/mn10300/include/asm/system.h
index 3c272a1a1015..7de90bc4cf80 100644
--- a/arch/mn10300/include/asm/system.h
+++ b/arch/mn10300/include/asm/system.h
@@ -18,6 +18,7 @@
18 18
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/irqflags.h> 20#include <linux/irqflags.h>
21#include <asm/atomic.h>
21 22
22#if !defined(CONFIG_LAZY_SAVE_FPU) 23#if !defined(CONFIG_LAZY_SAVE_FPU)
23struct fpu_state_struct; 24struct fpu_state_struct;
@@ -96,52 +97,5 @@ do { \
96#define read_barrier_depends() do {} while (0) 97#define read_barrier_depends() do {} while (0)
97#define smp_read_barrier_depends() do {} while (0) 98#define smp_read_barrier_depends() do {} while (0)
98 99
99/*****************************************************************************/
100/*
101 * MN10300 doesn't actually have an exchange instruction
102 */
103#ifndef __ASSEMBLY__
104
105struct __xchg_dummy { unsigned long a[100]; };
106#define __xg(x) ((struct __xchg_dummy *)(x))
107
108static inline
109unsigned long __xchg(volatile unsigned long *m, unsigned long val)
110{
111 unsigned long retval;
112 unsigned long flags;
113
114 local_irq_save(flags);
115 retval = *m;
116 *m = val;
117 local_irq_restore(flags);
118 return retval;
119}
120
121#define xchg(ptr, v) \
122 ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \
123 (unsigned long)(v)))
124
125static inline unsigned long __cmpxchg(volatile unsigned long *m,
126 unsigned long old, unsigned long new)
127{
128 unsigned long retval;
129 unsigned long flags;
130
131 local_irq_save(flags);
132 retval = *m;
133 if (retval == old)
134 *m = new;
135 local_irq_restore(flags);
136 return retval;
137}
138
139#define cmpxchg(ptr, o, n) \
140 ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
141 (unsigned long)(o), \
142 (unsigned long)(n)))
143
144#endif /* !__ASSEMBLY__ */
145
146#endif /* __KERNEL__ */ 100#endif /* __KERNEL__ */
147#endif /* _ASM_SYSTEM_H */ 101#endif /* _ASM_SYSTEM_H */