162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __ASM_SH_CMPXCHG_H
362306a36Sopenharmony_ci#define __ASM_SH_CMPXCHG_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for
762306a36Sopenharmony_ci * resource counting etc..
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/compiler.h>
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#if defined(CONFIG_GUSA_RB)
1462306a36Sopenharmony_ci#include <asm/cmpxchg-grb.h>
1562306a36Sopenharmony_ci#elif defined(CONFIG_CPU_SH4A)
1662306a36Sopenharmony_ci#include <asm/cmpxchg-llsc.h>
1762306a36Sopenharmony_ci#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
1862306a36Sopenharmony_ci#include <asm/cmpxchg-cas.h>
1962306a36Sopenharmony_ci#else
2062306a36Sopenharmony_ci#include <asm/cmpxchg-irq.h>
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ciextern void __xchg_called_with_bad_pointer(void);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define __arch_xchg(ptr, x, size)				\
2662306a36Sopenharmony_ci({							\
2762306a36Sopenharmony_ci	unsigned long __xchg__res;			\
2862306a36Sopenharmony_ci	volatile void *__xchg_ptr = (ptr);		\
2962306a36Sopenharmony_ci	switch (size) {					\
3062306a36Sopenharmony_ci	case 4:						\
3162306a36Sopenharmony_ci		__xchg__res = xchg_u32(__xchg_ptr, x);	\
3262306a36Sopenharmony_ci		break;					\
3362306a36Sopenharmony_ci	case 2:						\
3462306a36Sopenharmony_ci		__xchg__res = xchg_u16(__xchg_ptr, x);	\
3562306a36Sopenharmony_ci		break;					\
3662306a36Sopenharmony_ci	case 1:						\
3762306a36Sopenharmony_ci		__xchg__res = xchg_u8(__xchg_ptr, x);	\
3862306a36Sopenharmony_ci		break;					\
3962306a36Sopenharmony_ci	default:					\
4062306a36Sopenharmony_ci		__xchg_called_with_bad_pointer();	\
4162306a36Sopenharmony_ci		__xchg__res = x;			\
4262306a36Sopenharmony_ci		break;					\
4362306a36Sopenharmony_ci	}						\
4462306a36Sopenharmony_ci							\
4562306a36Sopenharmony_ci	__xchg__res;					\
4662306a36Sopenharmony_ci})
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define arch_xchg(ptr,x)	\
4962306a36Sopenharmony_ci	((__typeof__(*(ptr)))__arch_xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* This function doesn't exist, so you'll get a linker error
5262306a36Sopenharmony_ci * if something tries to do an invalid cmpxchg(). */
5362306a36Sopenharmony_ciextern void __cmpxchg_called_with_bad_pointer(void);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
5662306a36Sopenharmony_ci		unsigned long new, int size)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	switch (size) {
5962306a36Sopenharmony_ci	case 4:
6062306a36Sopenharmony_ci		return __cmpxchg_u32(ptr, old, new);
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	__cmpxchg_called_with_bad_pointer();
6362306a36Sopenharmony_ci	return old;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define arch_cmpxchg(ptr,o,n)						 \
6762306a36Sopenharmony_ci  ({									 \
6862306a36Sopenharmony_ci     __typeof__(*(ptr)) _o_ = (o);					 \
6962306a36Sopenharmony_ci     __typeof__(*(ptr)) _n_ = (n);					 \
7062306a36Sopenharmony_ci     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
7162306a36Sopenharmony_ci				    (unsigned long)_n_, sizeof(*(ptr))); \
7262306a36Sopenharmony_ci  })
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#endif /* __ASM_SH_CMPXCHG_H */
75