1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 23337e682SArnaldo Carvalho de Melo #ifndef TOOLS_ASM_X86_CMPXCHG_H 33337e682SArnaldo Carvalho de Melo #define TOOLS_ASM_X86_CMPXCHG_H 43337e682SArnaldo Carvalho de Melo 53337e682SArnaldo Carvalho de Melo #include <linux/compiler.h> 63337e682SArnaldo Carvalho de Melo 73337e682SArnaldo Carvalho de Melo /* 83337e682SArnaldo Carvalho de Melo * Non-existant functions to indicate usage errors at link time 93337e682SArnaldo Carvalho de Melo * (or compile-time if the compiler implements __compiletime_error(). 103337e682SArnaldo Carvalho de Melo */ 113337e682SArnaldo Carvalho de Melo extern void __cmpxchg_wrong_size(void) 123337e682SArnaldo Carvalho de Melo __compiletime_error("Bad argument size for cmpxchg"); 133337e682SArnaldo Carvalho de Melo 143337e682SArnaldo Carvalho de Melo /* 153337e682SArnaldo Carvalho de Melo * Constants for operation sizes. On 32-bit, the 64-bit size it set to 163337e682SArnaldo Carvalho de Melo * -1 because sizeof will never return -1, thereby making those switch 173337e682SArnaldo Carvalho de Melo * case statements guaranteeed dead code which the compiler will 183337e682SArnaldo Carvalho de Melo * eliminate, and allowing the "missing symbol in the default case" to 193337e682SArnaldo Carvalho de Melo * indicate a usage error. 203337e682SArnaldo Carvalho de Melo */ 213337e682SArnaldo Carvalho de Melo #define __X86_CASE_B 1 223337e682SArnaldo Carvalho de Melo #define __X86_CASE_W 2 233337e682SArnaldo Carvalho de Melo #define __X86_CASE_L 4 243337e682SArnaldo Carvalho de Melo #ifdef __x86_64__ 253337e682SArnaldo Carvalho de Melo #define __X86_CASE_Q 8 263337e682SArnaldo Carvalho de Melo #else 273337e682SArnaldo Carvalho de Melo #define __X86_CASE_Q -1 /* sizeof will never return -1 */ 283337e682SArnaldo Carvalho de Melo #endif 293337e682SArnaldo Carvalho de Melo 303337e682SArnaldo Carvalho de Melo /* 313337e682SArnaldo Carvalho de Melo * Atomic compare and exchange. Compare OLD with MEM, if identical, 323337e682SArnaldo Carvalho de Melo * store NEW in MEM. Return the initial value in MEM. Success is 333337e682SArnaldo Carvalho de Melo * indicated by comparing RETURN with OLD. 343337e682SArnaldo Carvalho de Melo */ 353337e682SArnaldo Carvalho de Melo #define __raw_cmpxchg(ptr, old, new, size, lock) \ 363337e682SArnaldo Carvalho de Melo ({ \ 373337e682SArnaldo Carvalho de Melo __typeof__(*(ptr)) __ret; \ 383337e682SArnaldo Carvalho de Melo __typeof__(*(ptr)) __old = (old); \ 393337e682SArnaldo Carvalho de Melo __typeof__(*(ptr)) __new = (new); \ 403337e682SArnaldo Carvalho de Melo switch (size) { \ 413337e682SArnaldo Carvalho de Melo case __X86_CASE_B: \ 423337e682SArnaldo Carvalho de Melo { \ 433337e682SArnaldo Carvalho de Melo volatile u8 *__ptr = (volatile u8 *)(ptr); \ 443337e682SArnaldo Carvalho de Melo asm volatile(lock "cmpxchgb %2,%1" \ 453337e682SArnaldo Carvalho de Melo : "=a" (__ret), "+m" (*__ptr) \ 463337e682SArnaldo Carvalho de Melo : "q" (__new), "0" (__old) \ 473337e682SArnaldo Carvalho de Melo : "memory"); \ 483337e682SArnaldo Carvalho de Melo break; \ 493337e682SArnaldo Carvalho de Melo } \ 503337e682SArnaldo Carvalho de Melo case __X86_CASE_W: \ 513337e682SArnaldo Carvalho de Melo { \ 523337e682SArnaldo Carvalho de Melo volatile u16 *__ptr = (volatile u16 *)(ptr); \ 533337e682SArnaldo Carvalho de Melo asm volatile(lock "cmpxchgw %2,%1" \ 543337e682SArnaldo Carvalho de Melo : "=a" (__ret), "+m" (*__ptr) \ 553337e682SArnaldo Carvalho de Melo : "r" (__new), "0" (__old) \ 563337e682SArnaldo Carvalho de Melo : "memory"); \ 573337e682SArnaldo Carvalho de Melo break; \ 583337e682SArnaldo Carvalho de Melo } \ 593337e682SArnaldo Carvalho de Melo case __X86_CASE_L: \ 603337e682SArnaldo Carvalho de Melo { \ 613337e682SArnaldo Carvalho de Melo volatile u32 *__ptr = (volatile u32 *)(ptr); \ 623337e682SArnaldo Carvalho de Melo asm volatile(lock "cmpxchgl %2,%1" \ 633337e682SArnaldo Carvalho de Melo : "=a" (__ret), "+m" (*__ptr) \ 643337e682SArnaldo Carvalho de Melo : "r" (__new), "0" (__old) \ 653337e682SArnaldo Carvalho de Melo : "memory"); \ 663337e682SArnaldo Carvalho de Melo break; \ 673337e682SArnaldo Carvalho de Melo } \ 683337e682SArnaldo Carvalho de Melo case __X86_CASE_Q: \ 693337e682SArnaldo Carvalho de Melo { \ 703337e682SArnaldo Carvalho de Melo volatile u64 *__ptr = (volatile u64 *)(ptr); \ 713337e682SArnaldo Carvalho de Melo asm volatile(lock "cmpxchgq %2,%1" \ 723337e682SArnaldo Carvalho de Melo : "=a" (__ret), "+m" (*__ptr) \ 733337e682SArnaldo Carvalho de Melo : "r" (__new), "0" (__old) \ 743337e682SArnaldo Carvalho de Melo : "memory"); \ 753337e682SArnaldo Carvalho de Melo break; \ 763337e682SArnaldo Carvalho de Melo } \ 773337e682SArnaldo Carvalho de Melo default: \ 783337e682SArnaldo Carvalho de Melo __cmpxchg_wrong_size(); \ 793337e682SArnaldo Carvalho de Melo } \ 803337e682SArnaldo Carvalho de Melo __ret; \ 813337e682SArnaldo Carvalho de Melo }) 823337e682SArnaldo Carvalho de Melo 833337e682SArnaldo Carvalho de Melo #define __cmpxchg(ptr, old, new, size) \ 843337e682SArnaldo Carvalho de Melo __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX) 853337e682SArnaldo Carvalho de Melo 863337e682SArnaldo Carvalho de Melo #define cmpxchg(ptr, old, new) \ 873337e682SArnaldo Carvalho de Melo __cmpxchg(ptr, old, new, sizeof(*(ptr))) 883337e682SArnaldo Carvalho de Melo 893337e682SArnaldo Carvalho de Melo 903337e682SArnaldo Carvalho de Melo #endif /* TOOLS_ASM_X86_CMPXCHG_H */ 91