diff options
Diffstat (limited to 'arch/x86/lib/atomic64_cx8_32.S')
-rw-r--r-- | arch/x86/lib/atomic64_cx8_32.S | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S new file mode 100644 index 000000000..90afb488b --- /dev/null +++ b/arch/x86/lib/atomic64_cx8_32.S @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * atomic64_t for 586+ + * + * Copyright © 2010 Luca Barbieri + */ + +#include <linux/linkage.h> +#include <asm/alternative.h> + +.macro read64 reg + movl %ebx, %eax + movl %ecx, %edx +/* we need LOCK_PREFIX since otherwise cmpxchg8b always does the write */ + LOCK_PREFIX + cmpxchg8b (\reg) +.endm + +SYM_FUNC_START(atomic64_read_cx8) + read64 %ecx + RET +SYM_FUNC_END(atomic64_read_cx8) + +SYM_FUNC_START(atomic64_set_cx8) +1: +/* we don't need LOCK_PREFIX since aligned 64-bit writes + * are atomic on 586 and newer */ + cmpxchg8b (%esi) + jne 1b + + RET +SYM_FUNC_END(atomic64_set_cx8) + +SYM_FUNC_START(atomic64_xchg_cx8) +1: + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + RET +SYM_FUNC_END(atomic64_xchg_cx8) + +.macro addsub_return func ins insc +SYM_FUNC_START(atomic64_\func\()_return_cx8) + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + + movl %eax, %esi + movl %edx, %edi + movl %ecx, %ebp + + read64 %ecx +1: + movl %eax, %ebx + movl %edx, %ecx + \ins\()l %esi, %ebx + \insc\()l %edi, %ecx + LOCK_PREFIX + cmpxchg8b (%ebp) + jne 1b + +10: + movl %ebx, %eax + movl %ecx, %edx + popl %edi + popl %esi + popl %ebx + popl %ebp + RET +SYM_FUNC_END(atomic64_\func\()_return_cx8) +.endm + +addsub_return add add adc +addsub_return sub sub sbb + +.macro incdec_return func ins insc +SYM_FUNC_START(atomic64_\func\()_return_cx8) + pushl %ebx + + read64 %esi +1: + movl %eax, %ebx + movl %edx, %ecx + \ins\()l $1, %ebx + \insc\()l $0, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + +10: + movl %ebx, %eax + movl %ecx, %edx + popl %ebx + RET +SYM_FUNC_END(atomic64_\func\()_return_cx8) +.endm + +incdec_return inc add adc +incdec_return dec sub sbb + +SYM_FUNC_START(atomic64_dec_if_positive_cx8) + pushl %ebx + + read64 %esi +1: + movl %eax, %ebx + movl %edx, %ecx + subl $1, %ebx + sbb $0, %ecx + js 2f + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + +2: + movl %ebx, %eax + movl %ecx, %edx + popl %ebx + RET +SYM_FUNC_END(atomic64_dec_if_positive_cx8) + +SYM_FUNC_START(atomic64_add_unless_cx8) + pushl %ebp + pushl %ebx +/* these just push these two parameters on the stack */ + pushl %edi + pushl %ecx + + movl %eax, %ebp + movl %edx, %edi + + read64 %esi +1: + cmpl %eax, 0(%esp) + je 4f +2: + movl %eax, %ebx + movl %edx, %ecx + addl %ebp, %ebx + adcl %edi, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + movl $1, %eax +3: + addl $8, %esp + popl %ebx + popl %ebp + RET +4: + cmpl %edx, 4(%esp) + jne 2b + xorl %eax, %eax + jmp 3b +SYM_FUNC_END(atomic64_add_unless_cx8) + +SYM_FUNC_START(atomic64_inc_not_zero_cx8) + pushl %ebx + + read64 %esi +1: + movl %eax, %ecx + orl %edx, %ecx + jz 3f + movl %eax, %ebx + xorl %ecx, %ecx + addl $1, %ebx + adcl %edx, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + movl $1, %eax +3: + popl %ebx + RET +SYM_FUNC_END(atomic64_inc_not_zero_cx8) |