Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[pandora-kernel.git] / arch / x86 / lib / cmpxchg16b_emu.S
1 /*
2  *      This program is free software; you can redistribute it and/or
3  *      modify it under the terms of the GNU General Public License
4  *      as published by the Free Software Foundation; version 2
5  *      of the License.
6  *
7  */
8 #include <linux/linkage.h>
9 #include <asm/alternative-asm.h>
10 #include <asm/frame.h>
11 #include <asm/dwarf2.h>
12
13 #ifdef CONFIG_SMP
14 #define SEG_PREFIX %gs:
15 #else
16 #define SEG_PREFIX
17 #endif
18
19 .text
20
21 /*
22  * Inputs:
23  * %rsi : memory location to compare
24  * %rax : low 64 bits of old value
25  * %rdx : high 64 bits of old value
26  * %rbx : low 64 bits of new value
27  * %rcx : high 64 bits of new value
28  * %al  : Operation successful
29  */
30 ENTRY(this_cpu_cmpxchg16b_emu)
31 CFI_STARTPROC
32
33 #
34 # Emulate 'cmpxchg16b %gs:(%rsi)' except we return the result in %al not
35 # via the ZF.  Caller will access %al to get result.
36 #
37 # Note that this is only useful for a cpuops operation.  Meaning that we
38 # do *not* have a fully atomic operation but just an operation that is
39 # *atomic* on a single cpu (as provided by the this_cpu_xx class of
40 # macros).
41 #
42 this_cpu_cmpxchg16b_emu:
43         pushf
44         cli
45
46         cmpq SEG_PREFIX(%rsi), %rax
47         jne not_same
48         cmpq SEG_PREFIX 8(%rsi), %rdx
49         jne not_same
50
51         movq %rbx, SEG_PREFIX(%rsi)
52         movq %rcx, SEG_PREFIX 8(%rsi)
53
54         popf
55         mov $1, %al
56         ret
57
58  not_same:
59         popf
60         xor %al,%al
61         ret
62
63 CFI_ENDPROC
64
65 ENDPROC(this_cpu_cmpxchg16b_emu)