91 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2#ifndef TOOLS_ASM_X86_CMPXCHG_H3#define TOOLS_ASM_X86_CMPXCHG_H4 5#include <linux/compiler.h>6 7/*8 * Non-existant functions to indicate usage errors at link time9 * (or compile-time if the compiler implements __compiletime_error().10 */11extern void __cmpxchg_wrong_size(void)12 __compiletime_error("Bad argument size for cmpxchg");13 14/*15 * Constants for operation sizes. On 32-bit, the 64-bit size it set to16 * -1 because sizeof will never return -1, thereby making those switch17 * case statements guaranteeed dead code which the compiler will18 * eliminate, and allowing the "missing symbol in the default case" to19 * indicate a usage error.20 */21#define __X86_CASE_B 122#define __X86_CASE_W 223#define __X86_CASE_L 424#ifdef __x86_64__25#define __X86_CASE_Q 826#else27#define __X86_CASE_Q -1 /* sizeof will never return -1 */28#endif29 30/*31 * Atomic compare and exchange. Compare OLD with MEM, if identical,32 * store NEW in MEM. Return the initial value in MEM. Success is33 * indicated by comparing RETURN with OLD.34 */35#define __raw_cmpxchg(ptr, old, new, size, lock) \36({ \37 __typeof__(*(ptr)) __ret; \38 __typeof__(*(ptr)) __old = (old); \39 __typeof__(*(ptr)) __new = (new); \40 switch (size) { \41 case __X86_CASE_B: \42 { \43 volatile u8 *__ptr = (volatile u8 *)(ptr); \44 asm volatile(lock "cmpxchgb %2,%1" \45 : "=a" (__ret), "+m" (*__ptr) \46 : "q" (__new), "0" (__old) \47 : "memory"); \48 break; \49 } \50 case __X86_CASE_W: \51 { \52 volatile u16 *__ptr = (volatile u16 *)(ptr); \53 asm volatile(lock "cmpxchgw %2,%1" \54 : "=a" (__ret), "+m" (*__ptr) \55 : "r" (__new), "0" (__old) \56 : "memory"); \57 break; \58 } \59 case __X86_CASE_L: \60 { \61 volatile u32 *__ptr = (volatile u32 *)(ptr); \62 asm volatile(lock "cmpxchgl %2,%1" \63 : "=a" (__ret), "+m" (*__ptr) \64 : "r" (__new), "0" (__old) \65 : "memory"); \66 break; \67 } \68 case __X86_CASE_Q: \69 { \70 volatile u64 *__ptr = (volatile u64 *)(ptr); \71 asm volatile(lock "cmpxchgq %2,%1" \72 : "=a" (__ret), "+m" (*__ptr) \73 : "r" (__new), "0" (__old) \74 : "memory"); \75 break; \76 } \77 default: \78 __cmpxchg_wrong_size(); \79 } \80 __ret; \81})82 83#define __cmpxchg(ptr, old, new, size) \84 __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)85 86#define cmpxchg(ptr, old, new) \87 __cmpxchg(ptr, old, new, sizeof(*(ptr)))88 89 90#endif /* TOOLS_ASM_X86_CMPXCHG_H */91