| /* 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 |
| |
| .macro read64_nonatomic reg |
| movl (\reg), %eax |
| movl 4(\reg), %edx |
| .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_nonatomic %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_nonatomic %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) |