18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef TOOLS_ASM_X86_CMPXCHG_H 38c2ecf20Sopenharmony_ci#define TOOLS_ASM_X86_CMPXCHG_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/compiler.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * Non-existant functions to indicate usage errors at link time 98c2ecf20Sopenharmony_ci * (or compile-time if the compiler implements __compiletime_error(). 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ciextern void __cmpxchg_wrong_size(void) 128c2ecf20Sopenharmony_ci __compiletime_error("Bad argument size for cmpxchg"); 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Constants for operation sizes. On 32-bit, the 64-bit size it set to 168c2ecf20Sopenharmony_ci * -1 because sizeof will never return -1, thereby making those switch 178c2ecf20Sopenharmony_ci * case statements guaranteeed dead code which the compiler will 188c2ecf20Sopenharmony_ci * eliminate, and allowing the "missing symbol in the default case" to 198c2ecf20Sopenharmony_ci * indicate a usage error. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci#define __X86_CASE_B 1 228c2ecf20Sopenharmony_ci#define __X86_CASE_W 2 238c2ecf20Sopenharmony_ci#define __X86_CASE_L 4 248c2ecf20Sopenharmony_ci#ifdef __x86_64__ 258c2ecf20Sopenharmony_ci#define __X86_CASE_Q 8 268c2ecf20Sopenharmony_ci#else 278c2ecf20Sopenharmony_ci#define __X86_CASE_Q -1 /* sizeof will never return -1 */ 288c2ecf20Sopenharmony_ci#endif 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Atomic compare and exchange. Compare OLD with MEM, if identical, 328c2ecf20Sopenharmony_ci * store NEW in MEM. Return the initial value in MEM. Success is 338c2ecf20Sopenharmony_ci * indicated by comparing RETURN with OLD. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci#define __raw_cmpxchg(ptr, old, new, size, lock) \ 368c2ecf20Sopenharmony_ci({ \ 378c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __ret; \ 388c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __old = (old); \ 398c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __new = (new); \ 408c2ecf20Sopenharmony_ci switch (size) { \ 418c2ecf20Sopenharmony_ci case __X86_CASE_B: \ 428c2ecf20Sopenharmony_ci { \ 438c2ecf20Sopenharmony_ci volatile u8 *__ptr = (volatile u8 *)(ptr); \ 448c2ecf20Sopenharmony_ci asm volatile(lock "cmpxchgb %2,%1" \ 458c2ecf20Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 468c2ecf20Sopenharmony_ci : "q" (__new), "0" (__old) \ 478c2ecf20Sopenharmony_ci : "memory"); \ 488c2ecf20Sopenharmony_ci break; \ 498c2ecf20Sopenharmony_ci } \ 508c2ecf20Sopenharmony_ci case __X86_CASE_W: \ 518c2ecf20Sopenharmony_ci { \ 528c2ecf20Sopenharmony_ci volatile u16 *__ptr = (volatile u16 *)(ptr); \ 538c2ecf20Sopenharmony_ci asm volatile(lock "cmpxchgw %2,%1" \ 548c2ecf20Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 558c2ecf20Sopenharmony_ci : "r" (__new), "0" (__old) \ 568c2ecf20Sopenharmony_ci : "memory"); \ 578c2ecf20Sopenharmony_ci break; \ 588c2ecf20Sopenharmony_ci } \ 598c2ecf20Sopenharmony_ci case __X86_CASE_L: \ 608c2ecf20Sopenharmony_ci { \ 618c2ecf20Sopenharmony_ci volatile u32 *__ptr = (volatile u32 *)(ptr); \ 628c2ecf20Sopenharmony_ci asm volatile(lock "cmpxchgl %2,%1" \ 638c2ecf20Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 648c2ecf20Sopenharmony_ci : "r" (__new), "0" (__old) \ 658c2ecf20Sopenharmony_ci : "memory"); \ 668c2ecf20Sopenharmony_ci break; \ 678c2ecf20Sopenharmony_ci } \ 688c2ecf20Sopenharmony_ci case __X86_CASE_Q: \ 698c2ecf20Sopenharmony_ci { \ 708c2ecf20Sopenharmony_ci volatile u64 *__ptr = (volatile u64 *)(ptr); \ 718c2ecf20Sopenharmony_ci asm volatile(lock "cmpxchgq %2,%1" \ 728c2ecf20Sopenharmony_ci : "=a" (__ret), "+m" (*__ptr) \ 738c2ecf20Sopenharmony_ci : "r" (__new), "0" (__old) \ 748c2ecf20Sopenharmony_ci : "memory"); \ 758c2ecf20Sopenharmony_ci break; \ 768c2ecf20Sopenharmony_ci } \ 778c2ecf20Sopenharmony_ci default: \ 788c2ecf20Sopenharmony_ci __cmpxchg_wrong_size(); \ 798c2ecf20Sopenharmony_ci } \ 808c2ecf20Sopenharmony_ci __ret; \ 818c2ecf20Sopenharmony_ci}) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define __cmpxchg(ptr, old, new, size) \ 848c2ecf20Sopenharmony_ci __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define cmpxchg(ptr, old, new) \ 878c2ecf20Sopenharmony_ci __cmpxchg(ptr, old, new, sizeof(*(ptr))) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#endif /* TOOLS_ASM_X86_CMPXCHG_H */ 91