162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#ifndef __ASM_CSKY_CMPXCHG_H
462306a36Sopenharmony_ci#define __ASM_CSKY_CMPXCHG_H
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifdef CONFIG_SMP
762306a36Sopenharmony_ci#include <linux/bug.h>
862306a36Sopenharmony_ci#include <asm/barrier.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define __xchg_relaxed(new, ptr, size)				\
1162306a36Sopenharmony_ci({								\
1262306a36Sopenharmony_ci	__typeof__(ptr) __ptr = (ptr);				\
1362306a36Sopenharmony_ci	__typeof__(new) __new = (new);				\
1462306a36Sopenharmony_ci	__typeof__(*(ptr)) __ret;				\
1562306a36Sopenharmony_ci	unsigned long tmp;					\
1662306a36Sopenharmony_ci	switch (size) {						\
1762306a36Sopenharmony_ci	case 2: {						\
1862306a36Sopenharmony_ci		u32 ret;					\
1962306a36Sopenharmony_ci		u32 shif = ((ulong)__ptr & 2) ? 16 : 0;		\
2062306a36Sopenharmony_ci		u32 mask = 0xffff << shif;			\
2162306a36Sopenharmony_ci		__ptr = (__typeof__(ptr))((ulong)__ptr & ~2);	\
2262306a36Sopenharmony_ci		__asm__ __volatile__ (				\
2362306a36Sopenharmony_ci			"1:	ldex.w %0, (%4)\n"		\
2462306a36Sopenharmony_ci			"	and    %1, %0, %2\n"		\
2562306a36Sopenharmony_ci			"	or     %1, %1, %3\n"		\
2662306a36Sopenharmony_ci			"	stex.w %1, (%4)\n"		\
2762306a36Sopenharmony_ci			"	bez    %1, 1b\n"		\
2862306a36Sopenharmony_ci			: "=&r" (ret), "=&r" (tmp)		\
2962306a36Sopenharmony_ci			: "r" (~mask),				\
3062306a36Sopenharmony_ci			  "r" ((u32)__new << shif),		\
3162306a36Sopenharmony_ci			  "r" (__ptr)				\
3262306a36Sopenharmony_ci			: "memory");				\
3362306a36Sopenharmony_ci		__ret = (__typeof__(*(ptr)))			\
3462306a36Sopenharmony_ci			((ret & mask) >> shif);			\
3562306a36Sopenharmony_ci		break;						\
3662306a36Sopenharmony_ci	}							\
3762306a36Sopenharmony_ci	case 4:							\
3862306a36Sopenharmony_ci		asm volatile (					\
3962306a36Sopenharmony_ci		"1:	ldex.w		%0, (%3) \n"		\
4062306a36Sopenharmony_ci		"	mov		%1, %2   \n"		\
4162306a36Sopenharmony_ci		"	stex.w		%1, (%3) \n"		\
4262306a36Sopenharmony_ci		"	bez		%1, 1b   \n"		\
4362306a36Sopenharmony_ci			: "=&r" (__ret), "=&r" (tmp)		\
4462306a36Sopenharmony_ci			: "r" (__new), "r"(__ptr)		\
4562306a36Sopenharmony_ci			:);					\
4662306a36Sopenharmony_ci		break;						\
4762306a36Sopenharmony_ci	default:						\
4862306a36Sopenharmony_ci		BUILD_BUG();					\
4962306a36Sopenharmony_ci	}							\
5062306a36Sopenharmony_ci	__ret;							\
5162306a36Sopenharmony_ci})
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define arch_xchg_relaxed(ptr, x) \
5462306a36Sopenharmony_ci		(__xchg_relaxed((x), (ptr), sizeof(*(ptr))))
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define __cmpxchg_relaxed(ptr, old, new, size)			\
5762306a36Sopenharmony_ci({								\
5862306a36Sopenharmony_ci	__typeof__(ptr) __ptr = (ptr);				\
5962306a36Sopenharmony_ci	__typeof__(new) __new = (new);				\
6062306a36Sopenharmony_ci	__typeof__(new) __tmp;					\
6162306a36Sopenharmony_ci	__typeof__(old) __old = (old);				\
6262306a36Sopenharmony_ci	__typeof__(*(ptr)) __ret;				\
6362306a36Sopenharmony_ci	switch (size) {						\
6462306a36Sopenharmony_ci	case 4:							\
6562306a36Sopenharmony_ci		asm volatile (					\
6662306a36Sopenharmony_ci		"1:	ldex.w		%0, (%3) \n"		\
6762306a36Sopenharmony_ci		"	cmpne		%0, %4   \n"		\
6862306a36Sopenharmony_ci		"	bt		2f       \n"		\
6962306a36Sopenharmony_ci		"	mov		%1, %2   \n"		\
7062306a36Sopenharmony_ci		"	stex.w		%1, (%3) \n"		\
7162306a36Sopenharmony_ci		"	bez		%1, 1b   \n"		\
7262306a36Sopenharmony_ci		"2:				 \n"		\
7362306a36Sopenharmony_ci			: "=&r" (__ret), "=&r" (__tmp)		\
7462306a36Sopenharmony_ci			: "r" (__new), "r"(__ptr), "r"(__old)	\
7562306a36Sopenharmony_ci			:);					\
7662306a36Sopenharmony_ci		break;						\
7762306a36Sopenharmony_ci	default:						\
7862306a36Sopenharmony_ci		BUILD_BUG();					\
7962306a36Sopenharmony_ci	}							\
8062306a36Sopenharmony_ci	__ret;							\
8162306a36Sopenharmony_ci})
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define arch_cmpxchg_relaxed(ptr, o, n) \
8462306a36Sopenharmony_ci	(__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr))))
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define __cmpxchg_acquire(ptr, old, new, size)			\
8762306a36Sopenharmony_ci({								\
8862306a36Sopenharmony_ci	__typeof__(ptr) __ptr = (ptr);				\
8962306a36Sopenharmony_ci	__typeof__(new) __new = (new);				\
9062306a36Sopenharmony_ci	__typeof__(new) __tmp;					\
9162306a36Sopenharmony_ci	__typeof__(old) __old = (old);				\
9262306a36Sopenharmony_ci	__typeof__(*(ptr)) __ret;				\
9362306a36Sopenharmony_ci	switch (size) {						\
9462306a36Sopenharmony_ci	case 4:							\
9562306a36Sopenharmony_ci		asm volatile (					\
9662306a36Sopenharmony_ci		"1:	ldex.w		%0, (%3) \n"		\
9762306a36Sopenharmony_ci		"	cmpne		%0, %4   \n"		\
9862306a36Sopenharmony_ci		"	bt		2f       \n"		\
9962306a36Sopenharmony_ci		"	mov		%1, %2   \n"		\
10062306a36Sopenharmony_ci		"	stex.w		%1, (%3) \n"		\
10162306a36Sopenharmony_ci		"	bez		%1, 1b   \n"		\
10262306a36Sopenharmony_ci		ACQUIRE_FENCE					\
10362306a36Sopenharmony_ci		"2:				 \n"		\
10462306a36Sopenharmony_ci			: "=&r" (__ret), "=&r" (__tmp)		\
10562306a36Sopenharmony_ci			: "r" (__new), "r"(__ptr), "r"(__old)	\
10662306a36Sopenharmony_ci			:);					\
10762306a36Sopenharmony_ci		break;						\
10862306a36Sopenharmony_ci	default:						\
10962306a36Sopenharmony_ci		BUILD_BUG();					\
11062306a36Sopenharmony_ci	}							\
11162306a36Sopenharmony_ci	__ret;							\
11262306a36Sopenharmony_ci})
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define arch_cmpxchg_acquire(ptr, o, n) \
11562306a36Sopenharmony_ci	(__cmpxchg_acquire((ptr), (o), (n), sizeof(*(ptr))))
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define __cmpxchg(ptr, old, new, size)				\
11862306a36Sopenharmony_ci({								\
11962306a36Sopenharmony_ci	__typeof__(ptr) __ptr = (ptr);				\
12062306a36Sopenharmony_ci	__typeof__(new) __new = (new);				\
12162306a36Sopenharmony_ci	__typeof__(new) __tmp;					\
12262306a36Sopenharmony_ci	__typeof__(old) __old = (old);				\
12362306a36Sopenharmony_ci	__typeof__(*(ptr)) __ret;				\
12462306a36Sopenharmony_ci	switch (size) {						\
12562306a36Sopenharmony_ci	case 4:							\
12662306a36Sopenharmony_ci		asm volatile (					\
12762306a36Sopenharmony_ci		RELEASE_FENCE					\
12862306a36Sopenharmony_ci		"1:	ldex.w		%0, (%3) \n"		\
12962306a36Sopenharmony_ci		"	cmpne		%0, %4   \n"		\
13062306a36Sopenharmony_ci		"	bt		2f       \n"		\
13162306a36Sopenharmony_ci		"	mov		%1, %2   \n"		\
13262306a36Sopenharmony_ci		"	stex.w		%1, (%3) \n"		\
13362306a36Sopenharmony_ci		"	bez		%1, 1b   \n"		\
13462306a36Sopenharmony_ci		FULL_FENCE					\
13562306a36Sopenharmony_ci		"2:				 \n"		\
13662306a36Sopenharmony_ci			: "=&r" (__ret), "=&r" (__tmp)		\
13762306a36Sopenharmony_ci			: "r" (__new), "r"(__ptr), "r"(__old)	\
13862306a36Sopenharmony_ci			:);					\
13962306a36Sopenharmony_ci		break;						\
14062306a36Sopenharmony_ci	default:						\
14162306a36Sopenharmony_ci		BUILD_BUG();					\
14262306a36Sopenharmony_ci	}							\
14362306a36Sopenharmony_ci	__ret;							\
14462306a36Sopenharmony_ci})
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define arch_cmpxchg(ptr, o, n)					\
14762306a36Sopenharmony_ci	(__cmpxchg((ptr), (o), (n), sizeof(*(ptr))))
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define arch_cmpxchg_local(ptr, o, n)				\
15062306a36Sopenharmony_ci	(__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr))))
15162306a36Sopenharmony_ci#else
15262306a36Sopenharmony_ci#include <asm-generic/cmpxchg.h>
15362306a36Sopenharmony_ci#endif
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#endif /* __ASM_CSKY_CMPXCHG_H */
156