diff options
author | Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | 2008-01-30 07:30:47 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:47 -0500 |
commit | 2c0b8a7578f7653e1e5312a5232e8ead563cf477 (patch) | |
tree | bc220bff551e39f9faff17e807d828094f420607 /arch | |
parent | 5f627f8e122a163ce53908d55e088247db31f1d7 (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 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/intel.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index cc8c501b9f39..867ff94579be 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
@@ -342,5 +342,22 @@ unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new) | |||
342 | EXPORT_SYMBOL(cmpxchg_386_u32); | 342 | EXPORT_SYMBOL(cmpxchg_386_u32); |
343 | #endif | 343 | #endif |
344 | 344 | ||
345 | #ifndef CONFIG_X86_CMPXCHG64 | ||
346 | unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new) | ||
347 | { | ||
348 | u64 prev; | ||
349 | unsigned long flags; | ||
350 | |||
351 | /* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */ | ||
352 | local_irq_save(flags); | ||
353 | prev = *(u64 *)ptr; | ||
354 | if (prev == old) | ||
355 | *(u64 *)ptr = new; | ||
356 | local_irq_restore(flags); | ||
357 | return prev; | ||
358 | } | ||
359 | EXPORT_SYMBOL(cmpxchg_486_u64); | ||
360 | #endif | ||
361 | |||
345 | // arch_initcall(intel_cpu_init); | 362 | // arch_initcall(intel_cpu_init); |
346 | 363 | ||