1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Generic UP xchg and cmpxchg using interrupt disablement. Does not 4 * support SMP. 5 */ 6 7#ifndef __ASM_GENERIC_CMPXCHG_H 8#define __ASM_GENERIC_CMPXCHG_H 9 10#ifdef CONFIG_SMP 11#error "Cannot use generic cmpxchg on SMP" 12#endif 13 14#include <linux/types.h> 15#include <linux/irqflags.h> 16 17#ifndef xchg 18 19/* 20 * This function doesn't exist, so you'll get a linker error if 21 * something tries to do an invalidly-sized xchg(). 22 */ 23extern void __xchg_called_with_bad_pointer(void); 24 25static inline 26unsigned long __xchg(unsigned long x, volatile void *ptr, int size) 27{ 28 unsigned long ret, flags; 29 30 switch (size) { 31 case 1: 32#ifdef __xchg_u8 33 return __xchg_u8(x, ptr); 34#else 35 local_irq_save(flags); 36 ret = *(volatile u8 *)ptr; 37 *(volatile u8 *)ptr = x; 38 local_irq_restore(flags); 39 return ret; 40#endif /* __xchg_u8 */ 41 42 case 2: 43#ifdef __xchg_u16 44 return __xchg_u16(x, ptr); 45#else 46 local_irq_save(flags); 47 ret = *(volatile u16 *)ptr; 48 *(volatile u16 *)ptr = x; 49 local_irq_restore(flags); 50 return ret; 51#endif /* __xchg_u16 */ 52 53 case 4: 54#ifdef __xchg_u32 55 return __xchg_u32(x, ptr); 56#else 57 local_irq_save(flags); 58 ret = *(volatile u32 *)ptr; 59 *(volatile u32 *)ptr = x; 60 local_irq_restore(flags); 61 return ret; 62#endif /* __xchg_u32 */ 63 64#ifdef CONFIG_64BIT 65 case 8: 66#ifdef __xchg_u64 67 return __xchg_u64(x, ptr); 68#else 69 local_irq_save(flags); 70 ret = *(volatile u64 *)ptr; 71 *(volatile u64 *)ptr = x; 72 local_irq_restore(flags); 73 return ret; 74#endif /* __xchg_u64 */ 75#endif /* CONFIG_64BIT */ 76 77 default: 78 __xchg_called_with_bad_pointer(); 79 return x; 80 } 81} 82 83#define xchg(ptr, x) ({ \ 84 ((__typeof__(*(ptr))) \ 85 __xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))); \ 86}) 87 88#endif /* xchg */ 89 90/* 91 * Atomic compare and exchange. 92 */ 93#include <asm-generic/cmpxchg-local.h> 94 95#ifndef cmpxchg_local 96#define cmpxchg_local(ptr, o, n) ({ \ 97 ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ 98 (unsigned long)(n), sizeof(*(ptr)))); \ 99}) 100#endif 101 102#ifndef cmpxchg64_local 103#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) 104#endif 105 106#define cmpxchg(ptr, o, n) cmpxchg_local((ptr), (o), (n)) 107#define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) 108 109#endif /* __ASM_GENERIC_CMPXCHG_H */ 110