18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * forked from parisc asm/atomic.h which was: 48c2ecf20Sopenharmony_ci * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Kyle McMartin <kyle@parisc-linux.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef _ASM_PARISC_CMPXCHG_H_ 98c2ecf20Sopenharmony_ci#define _ASM_PARISC_CMPXCHG_H_ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* This should get optimized out since it's never called. 128c2ecf20Sopenharmony_ci** Or get a link error if xchg is used "wrong". 138c2ecf20Sopenharmony_ci*/ 148c2ecf20Sopenharmony_ciextern void __xchg_called_with_bad_pointer(void); 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* __xchg32/64 defined in arch/parisc/lib/bitops.c */ 178c2ecf20Sopenharmony_ciextern unsigned long __xchg8(char, volatile char *); 188c2ecf20Sopenharmony_ciextern unsigned long __xchg32(int, volatile int *); 198c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 208c2ecf20Sopenharmony_ciextern unsigned long __xchg64(unsigned long, volatile unsigned long *); 218c2ecf20Sopenharmony_ci#endif 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* optimizer better get rid of switch since size is a constant */ 248c2ecf20Sopenharmony_cistatic inline unsigned long 258c2ecf20Sopenharmony_ci__xchg(unsigned long x, volatile void *ptr, int size) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci switch (size) { 288c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 298c2ecf20Sopenharmony_ci case 8: return __xchg64(x, (volatile unsigned long *) ptr); 308c2ecf20Sopenharmony_ci#endif 318c2ecf20Sopenharmony_ci case 4: return __xchg32((int) x, (volatile int *) ptr); 328c2ecf20Sopenharmony_ci case 1: return __xchg8((char) x, (volatile char *) ptr); 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci __xchg_called_with_bad_pointer(); 358c2ecf20Sopenharmony_ci return x; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci** REVISIT - Abandoned use of LDCW in xchg() for now: 408c2ecf20Sopenharmony_ci** o need to test sizeof(*ptr) to avoid clearing adjacent bytes 418c2ecf20Sopenharmony_ci** o and while we are at it, could CONFIG_64BIT code use LDCD too? 428c2ecf20Sopenharmony_ci** 438c2ecf20Sopenharmony_ci** if (__builtin_constant_p(x) && (x == NULL)) 448c2ecf20Sopenharmony_ci** if (((unsigned long)p & 0xf) == 0) 458c2ecf20Sopenharmony_ci** return __ldcw(p); 468c2ecf20Sopenharmony_ci*/ 478c2ecf20Sopenharmony_ci#define xchg(ptr, x) \ 488c2ecf20Sopenharmony_ci({ \ 498c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __ret; \ 508c2ecf20Sopenharmony_ci __typeof__(*(ptr)) _x_ = (x); \ 518c2ecf20Sopenharmony_ci __ret = (__typeof__(*(ptr))) \ 528c2ecf20Sopenharmony_ci __xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \ 538c2ecf20Sopenharmony_ci __ret; \ 548c2ecf20Sopenharmony_ci}) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* bug catcher for when unsupported size is used - won't link */ 578c2ecf20Sopenharmony_ciextern void __cmpxchg_called_with_bad_pointer(void); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */ 608c2ecf20Sopenharmony_ciextern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old, 618c2ecf20Sopenharmony_ci unsigned int new_); 628c2ecf20Sopenharmony_ciextern u64 __cmpxchg_u64(volatile u64 *ptr, u64 old, u64 new_); 638c2ecf20Sopenharmony_ciextern u8 __cmpxchg_u8(volatile u8 *ptr, u8 old, u8 new_); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* don't worry...optimizer will get rid of most of this */ 668c2ecf20Sopenharmony_cistatic inline unsigned long 678c2ecf20Sopenharmony_ci__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci switch (size) { 708c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 718c2ecf20Sopenharmony_ci case 8: return __cmpxchg_u64((u64 *)ptr, old, new_); 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci case 4: return __cmpxchg_u32((unsigned int *)ptr, 748c2ecf20Sopenharmony_ci (unsigned int)old, (unsigned int)new_); 758c2ecf20Sopenharmony_ci case 1: return __cmpxchg_u8((u8 *)ptr, old & 0xff, new_ & 0xff); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci __cmpxchg_called_with_bad_pointer(); 788c2ecf20Sopenharmony_ci return old; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define cmpxchg(ptr, o, n) \ 828c2ecf20Sopenharmony_ci({ \ 838c2ecf20Sopenharmony_ci __typeof__(*(ptr)) _o_ = (o); \ 848c2ecf20Sopenharmony_ci __typeof__(*(ptr)) _n_ = (n); \ 858c2ecf20Sopenharmony_ci (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ 868c2ecf20Sopenharmony_ci (unsigned long)_n_, sizeof(*(ptr))); \ 878c2ecf20Sopenharmony_ci}) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#include <asm-generic/cmpxchg-local.h> 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline unsigned long __cmpxchg_local(volatile void *ptr, 928c2ecf20Sopenharmony_ci unsigned long old, 938c2ecf20Sopenharmony_ci unsigned long new_, int size) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci switch (size) { 968c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 978c2ecf20Sopenharmony_ci case 8: return __cmpxchg_u64((u64 *)ptr, old, new_); 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci case 4: return __cmpxchg_u32(ptr, old, new_); 1008c2ecf20Sopenharmony_ci default: 1018c2ecf20Sopenharmony_ci return __cmpxchg_local_generic(ptr, old, new_, size); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make 1078c2ecf20Sopenharmony_ci * them available. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci#define cmpxchg_local(ptr, o, n) \ 1108c2ecf20Sopenharmony_ci ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ 1118c2ecf20Sopenharmony_ci (unsigned long)(n), sizeof(*(ptr)))) 1128c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 1138c2ecf20Sopenharmony_ci#define cmpxchg64_local(ptr, o, n) \ 1148c2ecf20Sopenharmony_ci({ \ 1158c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 1168c2ecf20Sopenharmony_ci cmpxchg_local((ptr), (o), (n)); \ 1178c2ecf20Sopenharmony_ci}) 1188c2ecf20Sopenharmony_ci#else 1198c2ecf20Sopenharmony_ci#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) 1208c2ecf20Sopenharmony_ci#endif 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define cmpxchg64(ptr, o, n) __cmpxchg_u64(ptr, o, n) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#endif /* _ASM_PARISC_CMPXCHG_H_ */ 125