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