aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>2008-01-30 07:30:47 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:30:47 -0500
commit2c0b8a7578f7653e1e5312a5232e8ead563cf477 (patch)
treebc220bff551e39f9faff17e807d828094f420607 /include
parent5f627f8e122a163ce53908d55e088247db31f1d7 (diff)
x86: fall back on interrupt disable in cmpxchg8b on 80386 and 80486
Actually, on 386, cmpxchg and cmpxchg_local fall back on cmpxchg_386_u8/16/32: it disables interruptions around non atomic updates to mimic the cmpxchg behavior. The comment: /* Poor man's cmpxchg for 386. Unsuitable for SMP */ already present in cmpxchg_386_u32 tells much about how this cmpxchg implementation should not be used in a SMP context. However, the cmpxchg_local can perfectly use this fallback, since it only needs to be atomic wrt the local cpu. This patch adds a cmpxchg_486_u64 and uses it as a fallback for cmpxchg64 and cmpxchg64_local on 80386 and 80486. Q: but why is it called cmpxchg_486 when the other functions are called A: Because the standard cmpxchg is missing only on 386, but cmpxchg8b is missing both on 386 and 486. Citing Intel's Instruction set reference: cmpxchg: This instruction is not supported on Intel processors earlier than the Intel486 processors. cmpxchg8b: This instruction encoding is not supported on Intel processors earlier than the Pentium processors. Q: What's the reason to have cmpxchg64_local on 32 bit architectures? Without that need all this would just be a few simple defines. A: cmpxchg64_local on 32 bits architectures takes unsigned long long parameters, but cmpxchg_local only takes longs. Since we have cmpxchg8b to execute a 8 byte cmpxchg atomically on pentium and +, it makes sense to provide a flavor of cmpxchg and cmpxchg_local using this instruction. Also, for 32 bits architectures lacking the 64 bits atomic cmpxchg, it makes sense _not_ to define cmpxchg64 while cmpxchg could still be available. Moreover, the fallback for cmpxchg8b on i386 for 386 and 486 is a However, cmpxchg64_local will be emulated by disabling interrupts on all architectures where it is not supported atomically. Therefore, we *could* turn cmpxchg64_local into a cmpxchg_local, but it would make the 386/486 fallbacks ugly, make its design different from cmpxchg/cmpxchg64 (which really depends on atomic operations and cannot be emulated) and require the __cmpxchg_local to be expressed as a macro rather than an inline function so the parameters would not be fixed to unsigned long long in every case. So I think cmpxchg64_local makes sense there, but I am open to suggestions. Q: Are there any callers? A: I am actually using it in LTTng in my timestamping code. I use it to work around CPUs with asynchronous TSCs. I need to update 64 bits values atomically on this 32 bits architecture. Changelog: - Ran though checkpatch. Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'include')
-rw-r--r--include/asm-x86/cmpxchg_32.h122
1 files changed, 79 insertions, 43 deletions
diff --git a/include/asm-x86/cmpxchg_32.h b/include/asm-x86/cmpxchg_32.h
index f86ede28f6dc..cea1dae288a7 100644
--- a/include/asm-x86/cmpxchg_32.h
+++ b/include/asm-x86/cmpxchg_32.h
@@ -105,15 +105,24 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
105 105
106#ifdef CONFIG_X86_CMPXCHG 106#ifdef CONFIG_X86_CMPXCHG
107#define __HAVE_ARCH_CMPXCHG 1 107#define __HAVE_ARCH_CMPXCHG 1
108#define cmpxchg(ptr,o,n)\ 108#define cmpxchg(ptr, o, n) \
109 ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ 109 ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
110 (unsigned long)(n),sizeof(*(ptr)))) 110 (unsigned long)(n), sizeof(*(ptr))))
111#define sync_cmpxchg(ptr,o,n)\ 111#define sync_cmpxchg(ptr, o, n) \
112 ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\ 112 ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o), \
113 (unsigned long)(n),sizeof(*(ptr)))) 113 (unsigned long)(n), sizeof(*(ptr))))
114#define cmpxchg_local(ptr,o,n)\ 114#define cmpxchg_local(ptr, o, n) \
115 ((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\ 115 ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
116 (unsigned long)(n),sizeof(*(ptr)))) 116 (unsigned long)(n), sizeof(*(ptr))))
117#endif
118
119#ifdef CONFIG_X86_CMPXCHG64
120#define cmpxchg64(ptr, o, n) \
121 ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
122 (unsigned long long)(n)))
123#define cmpxchg64_local(ptr, o, n) \
124 ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o),\
125 (unsigned long long)(n)))
117#endif 126#endif
118 127
119static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, 128static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
@@ -203,6 +212,34 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
203 return old; 212 return old;
204} 213}
205 214
215static inline unsigned long long __cmpxchg64(volatile void *ptr,
216 unsigned long long old, unsigned long long new)
217{
218 unsigned long long prev;
219 __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3"
220 : "=A"(prev)
221 : "b"((unsigned long)new),
222 "c"((unsigned long)(new >> 32)),
223 "m"(*__xg(ptr)),
224 "0"(old)
225 : "memory");
226 return prev;
227}
228
229static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
230 unsigned long long old, unsigned long long new)
231{
232 unsigned long long prev;
233 __asm__ __volatile__("cmpxchg8b %3"
234 : "=A"(prev)
235 : "b"((unsigned long)new),
236 "c"((unsigned long)(new >> 32)),
237 "m"(*__xg(ptr)),
238 "0"(old)
239 : "memory");
240 return prev;
241}
242
206#ifndef CONFIG_X86_CMPXCHG 243#ifndef CONFIG_X86_CMPXCHG
207/* 244/*
208 * Building a kernel capable running on 80386. It may be necessary to 245 * Building a kernel capable running on 80386. It may be necessary to
@@ -228,7 +265,7 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
228 return old; 265 return old;
229} 266}
230 267
231#define cmpxchg(ptr,o,n) \ 268#define cmpxchg(ptr, o, n) \
232({ \ 269({ \
233 __typeof__(*(ptr)) __ret; \ 270 __typeof__(*(ptr)) __ret; \
234 if (likely(boot_cpu_data.x86 > 3)) \ 271 if (likely(boot_cpu_data.x86 > 3)) \
@@ -239,7 +276,7 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
239 (unsigned long)(n), sizeof(*(ptr))); \ 276 (unsigned long)(n), sizeof(*(ptr))); \
240 __ret; \ 277 __ret; \
241}) 278})
242#define cmpxchg_local(ptr,o,n) \ 279#define cmpxchg_local(ptr, o, n) \
243({ \ 280({ \
244 __typeof__(*(ptr)) __ret; \ 281 __typeof__(*(ptr)) __ret; \
245 if (likely(boot_cpu_data.x86 > 3)) \ 282 if (likely(boot_cpu_data.x86 > 3)) \
@@ -252,38 +289,37 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
252}) 289})
253#endif 290#endif
254 291
255static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old, 292#ifndef CONFIG_X86_CMPXCHG64
256 unsigned long long new) 293/*
257{ 294 * Building a kernel capable running on 80386 and 80486. It may be necessary
258 unsigned long long prev; 295 * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
259 __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3" 296 */
260 : "=A"(prev)
261 : "b"((unsigned long)new),
262 "c"((unsigned long)(new >> 32)),
263 "m"(*__xg(ptr)),
264 "0"(old)
265 : "memory");
266 return prev;
267}
268 297
269static inline unsigned long long __cmpxchg64_local(volatile void *ptr, 298extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
270 unsigned long long old, unsigned long long new) 299
271{ 300#define cmpxchg64(ptr, o, n) \
272 unsigned long long prev; 301({ \
273 __asm__ __volatile__("cmpxchg8b %3" 302 __typeof__(*(ptr)) __ret; \
274 : "=A"(prev) 303 if (likely(boot_cpu_data.x86 > 4)) \
275 : "b"((unsigned long)new), 304 __ret = __cmpxchg64((ptr), (unsigned long long)(o), \
276 "c"((unsigned long)(new >> 32)), 305 (unsigned long long)(n)); \
277 "m"(*__xg(ptr)), 306 else \
278 "0"(old) 307 __ret = cmpxchg_486_u64((ptr), (unsigned long long)(o), \
279 : "memory"); 308 (unsigned long long)(n)); \
280 return prev; 309 __ret; \
281} 310})
311#define cmpxchg64_local(ptr, o, n) \
312({ \
313 __typeof__(*(ptr)) __ret; \
314 if (likely(boot_cpu_data.x86 > 4)) \
315 __ret = __cmpxchg64_local((ptr), (unsigned long long)(o), \
316 (unsigned long long)(n)); \
317 else \
318 __ret = cmpxchg_486_u64((ptr), (unsigned long long)(o), \
319 (unsigned long long)(n)); \
320 __ret; \
321})
322
323#endif
282 324
283#define cmpxchg64(ptr,o,n)\
284 ((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
285 (unsigned long long)(n)))
286#define cmpxchg64_local(ptr,o,n)\
287 ((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
288 (unsigned long long)(n)))
289#endif 325#endif