162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef TOOLS_ASM_X86_CMPXCHG_H 362306a36Sopenharmony_ci#define TOOLS_ASM_X86_CMPXCHG_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/compiler.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * Non-existant functions to indicate usage errors at link time 962306a36Sopenharmony_ci * (or compile-time if the compiler implements __compiletime_error(). 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ciextern void __cmpxchg_wrong_size(void) 1262306a36Sopenharmony_ci __compiletime_error("Bad argument size for cmpxchg"); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Constants for operation sizes. On 32-bit, the 64-bit size it set to 1662306a36Sopenharmony_ci * -1 because sizeof will never return -1, thereby making those switch 1762306a36Sopenharmony_ci * case statements guaranteeed dead code which the compiler will 1862306a36Sopenharmony_ci * eliminate, and allowing the "missing symbol in the default case" to 1962306a36Sopenharmony_ci * indicate a usage error. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci#define __X86_CASE_B 1 2262306a36Sopenharmony_ci#define __X86_CASE_W 2 2362306a36Sopenharmony_ci#define __X86_CASE_L 4 2462306a36Sopenharmony_ci#ifdef __x86_64__ 2562306a36Sopenharmony_ci#define __X86_CASE_Q 8 2662306a36Sopenharmony_ci#else 2762306a36Sopenharmony_ci#define __X86_CASE_Q -1 /* sizeof will never return -1 */ 2862306a36Sopenharmony_ci#endif 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Atomic compare and exchange. Compare OLD with MEM, if identical, 3262306a36Sopenharmony_ci * store NEW in MEM. Return the initial value in MEM. Success is 3362306a36Sopenharmony_ci * indicated by comparing RETURN with OLD. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci#define __raw_cmpxchg(ptr, old, new, size, lock) \ 3662306a36Sopenharmony_ci({ \ 3762306a36Sopenharmony_ci __typeof__(*(ptr)) __ret; \ 3862306a36Sopenharmony_ci __typeof__(*(ptr)) __old = (old); \ 3962306a36Sopenharmony_ci __typeof__(*(ptr)) __new = (new); \ 4062306a36Sopenharmony_ci switch (size) { \ 4162306a36Sopenharmony_ci case __X86_CASE_B: \ 4262306a36Sopenharmony_ci { \ 4362306a36Sopenharmony_ci volatile u8 *__ptr = (volatile u8 *)(ptr); \ 4462306a36Sopenharmony_ci asm volatile(lock "cmpxchgb %2,%1" \ 4562306a36Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 4662306a36Sopenharmony_ci : "q" (__new), "0" (__old) \ 4762306a36Sopenharmony_ci : "memory"); \ 4862306a36Sopenharmony_ci break; \ 4962306a36Sopenharmony_ci } \ 5062306a36Sopenharmony_ci case __X86_CASE_W: \ 5162306a36Sopenharmony_ci { \ 5262306a36Sopenharmony_ci volatile u16 *__ptr = (volatile u16 *)(ptr); \ 5362306a36Sopenharmony_ci asm volatile(lock "cmpxchgw %2,%1" \ 5462306a36Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 5562306a36Sopenharmony_ci : "r" (__new), "0" (__old) \ 5662306a36Sopenharmony_ci : "memory"); \ 5762306a36Sopenharmony_ci break; \ 5862306a36Sopenharmony_ci } \ 5962306a36Sopenharmony_ci case __X86_CASE_L: \ 6062306a36Sopenharmony_ci { \ 6162306a36Sopenharmony_ci volatile u32 *__ptr = (volatile u32 *)(ptr); \ 6262306a36Sopenharmony_ci asm volatile(lock "cmpxchgl %2,%1" \ 6362306a36Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 6462306a36Sopenharmony_ci : "r" (__new), "0" (__old) \ 6562306a36Sopenharmony_ci : "memory"); \ 6662306a36Sopenharmony_ci break; \ 6762306a36Sopenharmony_ci } \ 6862306a36Sopenharmony_ci case __X86_CASE_Q: \ 6962306a36Sopenharmony_ci { \ 7062306a36Sopenharmony_ci volatile u64 *__ptr = (volatile u64 *)(ptr); \ 7162306a36Sopenharmony_ci asm volatile(lock "cmpxchgq %2,%1" \ 7262306a36Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 7362306a36Sopenharmony_ci : "r" (__new), "0" (__old) \ 7462306a36Sopenharmony_ci : "memory"); \ 7562306a36Sopenharmony_ci break; \ 7662306a36Sopenharmony_ci } \ 7762306a36Sopenharmony_ci default: \ 7862306a36Sopenharmony_ci __cmpxchg_wrong_size(); \ 7962306a36Sopenharmony_ci } \ 8062306a36Sopenharmony_ci __ret; \ 8162306a36Sopenharmony_ci}) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define __cmpxchg(ptr, old, new, size) \ 8462306a36Sopenharmony_ci __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define cmpxchg(ptr, old, new) \ 8762306a36Sopenharmony_ci __cmpxchg(ptr, old, new, sizeof(*(ptr))) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#endif /* TOOLS_ASM_X86_CMPXCHG_H */ 91