Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] i386: generic cmpxchg

- Make cmpxchg generally available on the i386 platform.

- Provide emulation of cmpxchg suitable for uniprocessor if built and run on
386.

From: Christoph Lameter <clameter@sgi.com>

- Cut down patch and small style changes.

Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Nick Piggin and committed by
Linus Torvalds
53e86b91 dbdf65b1

+87 -3
+48
arch/i386/kernel/cpu/intel.c
··· 6 6 #include <linux/bitops.h> 7 7 #include <linux/smp.h> 8 8 #include <linux/thread_info.h> 9 + #include <linux/module.h> 9 10 10 11 #include <asm/processor.h> 11 12 #include <asm/msr.h> ··· 264 263 cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev; 265 264 return 0; 266 265 } 266 + 267 + #ifndef CONFIG_X86_CMPXCHG 268 + unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new) 269 + { 270 + u8 prev; 271 + unsigned long flags; 272 + 273 + /* Poor man's cmpxchg for 386. Unsuitable for SMP */ 274 + local_irq_save(flags); 275 + prev = *(u8 *)ptr; 276 + if (prev == old) 277 + *(u8 *)ptr = new; 278 + local_irq_restore(flags); 279 + return prev; 280 + } 281 + EXPORT_SYMBOL(cmpxchg_386_u8); 282 + 283 + unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new) 284 + { 285 + u16 prev; 286 + unsigned long flags; 287 + 288 + /* Poor man's cmpxchg for 386. Unsuitable for SMP */ 289 + local_irq_save(flags); 290 + prev = *(u16 *)ptr; 291 + if (prev == old) 292 + *(u16 *)ptr = new; 293 + local_irq_restore(flags); 294 + return prev; 295 + } 296 + EXPORT_SYMBOL(cmpxchg_386_u16); 297 + 298 + unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new) 299 + { 300 + u32 prev; 301 + unsigned long flags; 302 + 303 + /* Poor man's cmpxchg for 386. Unsuitable for SMP */ 304 + local_irq_save(flags); 305 + prev = *(u32 *)ptr; 306 + if (prev == old) 307 + *(u32 *)ptr = new; 308 + local_irq_restore(flags); 309 + return prev; 310 + } 311 + EXPORT_SYMBOL(cmpxchg_386_u32); 312 + #endif 267 313 268 314 // arch_initcall(intel_cpu_init); 269 315
+39 -3
include/asm-i386/system.h
··· 263 263 264 264 #ifdef CONFIG_X86_CMPXCHG 265 265 #define __HAVE_ARCH_CMPXCHG 1 266 + #define cmpxchg(ptr,o,n)\ 267 + ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ 268 + (unsigned long)(n),sizeof(*(ptr)))) 269 + #endif 266 270 267 271 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, 268 272 unsigned long new, int size) ··· 295 291 return old; 296 292 } 297 293 298 - #define cmpxchg(ptr,o,n)\ 299 - ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ 300 - (unsigned long)(n),sizeof(*(ptr)))) 294 + #ifndef CONFIG_X86_CMPXCHG 295 + /* 296 + * Building a kernel capable running on 80386. It may be necessary to 297 + * simulate the cmpxchg on the 80386 CPU. For that purpose we define 298 + * a function for each of the sizes we support. 299 + */ 301 300 301 + extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8); 302 + extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16); 303 + extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32); 304 + 305 + static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, 306 + unsigned long new, int size) 307 + { 308 + switch (size) { 309 + case 1: 310 + return cmpxchg_386_u8(ptr, old, new); 311 + case 2: 312 + return cmpxchg_386_u16(ptr, old, new); 313 + case 4: 314 + return cmpxchg_386_u32(ptr, old, new); 315 + } 316 + return old; 317 + } 318 + 319 + #define cmpxchg(ptr,o,n) \ 320 + ({ \ 321 + __typeof__(*(ptr)) __ret; \ 322 + if (likely(boot_cpu_data.x86 > 3)) \ 323 + __ret = __cmpxchg((ptr), (unsigned long)(o), \ 324 + (unsigned long)(n), sizeof(*(ptr))); \ 325 + else \ 326 + __ret = cmpxchg_386((ptr), (unsigned long)(o), \ 327 + (unsigned long)(n), sizeof(*(ptr))); \ 328 + __ret; \ 329 + }) 302 330 #endif 303 331 304 332 #ifdef CONFIG_X86_CMPXCHG64