forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
2.6 KiB
90 lines
2.6 KiB
/* SPDX-License-Identifier: GPL-2.0 */ |
|
#ifndef TOOLS_ASM_X86_CMPXCHG_H |
|
#define TOOLS_ASM_X86_CMPXCHG_H |
|
|
|
#include <linux/compiler.h> |
|
|
|
/* |
|
* Non-existant functions to indicate usage errors at link time |
|
* (or compile-time if the compiler implements __compiletime_error(). |
|
*/ |
|
extern void __cmpxchg_wrong_size(void) |
|
__compiletime_error("Bad argument size for cmpxchg"); |
|
|
|
/* |
|
* Constants for operation sizes. On 32-bit, the 64-bit size it set to |
|
* -1 because sizeof will never return -1, thereby making those switch |
|
* case statements guaranteeed dead code which the compiler will |
|
* eliminate, and allowing the "missing symbol in the default case" to |
|
* indicate a usage error. |
|
*/ |
|
#define __X86_CASE_B 1 |
|
#define __X86_CASE_W 2 |
|
#define __X86_CASE_L 4 |
|
#ifdef __x86_64__ |
|
#define __X86_CASE_Q 8 |
|
#else |
|
#define __X86_CASE_Q -1 /* sizeof will never return -1 */ |
|
#endif |
|
|
|
/* |
|
* Atomic compare and exchange. Compare OLD with MEM, if identical, |
|
* store NEW in MEM. Return the initial value in MEM. Success is |
|
* indicated by comparing RETURN with OLD. |
|
*/ |
|
#define __raw_cmpxchg(ptr, old, new, size, lock) \ |
|
({ \ |
|
__typeof__(*(ptr)) __ret; \ |
|
__typeof__(*(ptr)) __old = (old); \ |
|
__typeof__(*(ptr)) __new = (new); \ |
|
switch (size) { \ |
|
case __X86_CASE_B: \ |
|
{ \ |
|
volatile u8 *__ptr = (volatile u8 *)(ptr); \ |
|
asm volatile(lock "cmpxchgb %2,%1" \ |
|
: "=a" (__ret), "+m" (*__ptr) \ |
|
: "q" (__new), "0" (__old) \ |
|
: "memory"); \ |
|
break; \ |
|
} \ |
|
case __X86_CASE_W: \ |
|
{ \ |
|
volatile u16 *__ptr = (volatile u16 *)(ptr); \ |
|
asm volatile(lock "cmpxchgw %2,%1" \ |
|
: "=a" (__ret), "+m" (*__ptr) \ |
|
: "r" (__new), "0" (__old) \ |
|
: "memory"); \ |
|
break; \ |
|
} \ |
|
case __X86_CASE_L: \ |
|
{ \ |
|
volatile u32 *__ptr = (volatile u32 *)(ptr); \ |
|
asm volatile(lock "cmpxchgl %2,%1" \ |
|
: "=a" (__ret), "+m" (*__ptr) \ |
|
: "r" (__new), "0" (__old) \ |
|
: "memory"); \ |
|
break; \ |
|
} \ |
|
case __X86_CASE_Q: \ |
|
{ \ |
|
volatile u64 *__ptr = (volatile u64 *)(ptr); \ |
|
asm volatile(lock "cmpxchgq %2,%1" \ |
|
: "=a" (__ret), "+m" (*__ptr) \ |
|
: "r" (__new), "0" (__old) \ |
|
: "memory"); \ |
|
break; \ |
|
} \ |
|
default: \ |
|
__cmpxchg_wrong_size(); \ |
|
} \ |
|
__ret; \ |
|
}) |
|
|
|
#define __cmpxchg(ptr, old, new, size) \ |
|
__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX) |
|
|
|
#define cmpxchg(ptr, old, new) \ |
|
__cmpxchg(ptr, old, new, sizeof(*(ptr))) |
|
|
|
|
|
#endif /* TOOLS_ASM_X86_CMPXCHG_H */
|
|
|