xref: /openbmc/linux/arch/sparc/lib/atomic32.c (revision e69eb9c4)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * atomic32.c: 32-bit atomic_t implementation
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2004 Keith M Wesolowski
66197fe4dSKyle McMartin  * Copyright (C) 2007 Kyle McMartin
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Based on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
1160063497SArun Sharma #include <linux/atomic.h>
121da177e4SLinus Torvalds #include <linux/spinlock.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #ifdef CONFIG_SMP
161da177e4SLinus Torvalds #define ATOMIC_HASH_SIZE	4
171da177e4SLinus Torvalds #define ATOMIC_HASH(a)	(&__atomic_hash[(((unsigned long)a)>>8) & (ATOMIC_HASH_SIZE-1)])
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = {
2024774fbdSThomas Gleixner 	[0 ... (ATOMIC_HASH_SIZE-1)] = __SPIN_LOCK_UNLOCKED(__atomic_hash)
211da177e4SLinus Torvalds };
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #else /* SMP */
241da177e4SLinus Torvalds 
25a9f6a0ddSIngo Molnar static DEFINE_SPINLOCK(dummy);
261da177e4SLinus Torvalds #define ATOMIC_HASH_SIZE	1
271da177e4SLinus Torvalds #define ATOMIC_HASH(a)		(&dummy)
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #endif /* SMP */
301da177e4SLinus Torvalds 
313a1adb23SPeter Zijlstra #define ATOMIC_FETCH_OP(op, c_op)					\
32ff5b4f1eSMark Rutland int arch_atomic_fetch_##op(int i, atomic_t *v)				\
333a1adb23SPeter Zijlstra {									\
343a1adb23SPeter Zijlstra 	int ret;							\
353a1adb23SPeter Zijlstra 	unsigned long flags;						\
363a1adb23SPeter Zijlstra 	spin_lock_irqsave(ATOMIC_HASH(v), flags);			\
373a1adb23SPeter Zijlstra 									\
383a1adb23SPeter Zijlstra 	ret = v->counter;						\
393a1adb23SPeter Zijlstra 	v->counter c_op i;						\
403a1adb23SPeter Zijlstra 									\
413a1adb23SPeter Zijlstra 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);			\
423a1adb23SPeter Zijlstra 	return ret;							\
433a1adb23SPeter Zijlstra }									\
44ff5b4f1eSMark Rutland EXPORT_SYMBOL(arch_atomic_fetch_##op);
453a1adb23SPeter Zijlstra 
46304a0d69SPeter Zijlstra #define ATOMIC_OP_RETURN(op, c_op)					\
47ff5b4f1eSMark Rutland int arch_atomic_##op##_return(int i, atomic_t *v)			\
484f3316c2SPeter Zijlstra {									\
494f3316c2SPeter Zijlstra 	int ret;							\
504f3316c2SPeter Zijlstra 	unsigned long flags;						\
514f3316c2SPeter Zijlstra 	spin_lock_irqsave(ATOMIC_HASH(v), flags);			\
524f3316c2SPeter Zijlstra 									\
53304a0d69SPeter Zijlstra 	ret = (v->counter c_op i);					\
544f3316c2SPeter Zijlstra 									\
554f3316c2SPeter Zijlstra 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);			\
564f3316c2SPeter Zijlstra 	return ret;							\
574f3316c2SPeter Zijlstra }									\
58ff5b4f1eSMark Rutland EXPORT_SYMBOL(arch_atomic_##op##_return);
591da177e4SLinus Torvalds 
60304a0d69SPeter Zijlstra ATOMIC_OP_RETURN(add, +=)
61304a0d69SPeter Zijlstra 
623a1adb23SPeter Zijlstra ATOMIC_FETCH_OP(add, +=)
633a1adb23SPeter Zijlstra ATOMIC_FETCH_OP(and, &=)
643a1adb23SPeter Zijlstra ATOMIC_FETCH_OP(or, |=)
653a1adb23SPeter Zijlstra ATOMIC_FETCH_OP(xor, ^=)
663a1adb23SPeter Zijlstra 
673a1adb23SPeter Zijlstra #undef ATOMIC_FETCH_OP
68304a0d69SPeter Zijlstra #undef ATOMIC_OP_RETURN
694a6dae6dSNick Piggin 
arch_atomic_xchg(atomic_t * v,int new)70ff5b4f1eSMark Rutland int arch_atomic_xchg(atomic_t *v, int new)
711a17fdc4SAndreas Larsson {
721a17fdc4SAndreas Larsson 	int ret;
731a17fdc4SAndreas Larsson 	unsigned long flags;
741a17fdc4SAndreas Larsson 
751a17fdc4SAndreas Larsson 	spin_lock_irqsave(ATOMIC_HASH(v), flags);
761a17fdc4SAndreas Larsson 	ret = v->counter;
771a17fdc4SAndreas Larsson 	v->counter = new;
781a17fdc4SAndreas Larsson 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
791a17fdc4SAndreas Larsson 	return ret;
801a17fdc4SAndreas Larsson }
81ff5b4f1eSMark Rutland EXPORT_SYMBOL(arch_atomic_xchg);
821a17fdc4SAndreas Larsson 
arch_atomic_cmpxchg(atomic_t * v,int old,int new)83ff5b4f1eSMark Rutland int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
844a6dae6dSNick Piggin {
854a6dae6dSNick Piggin 	int ret;
864a6dae6dSNick Piggin 	unsigned long flags;
874a6dae6dSNick Piggin 
884a6dae6dSNick Piggin 	spin_lock_irqsave(ATOMIC_HASH(v), flags);
894a6dae6dSNick Piggin 	ret = v->counter;
904a6dae6dSNick Piggin 	if (likely(ret == old))
914a6dae6dSNick Piggin 		v->counter = new;
924a6dae6dSNick Piggin 
934a6dae6dSNick Piggin 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
944a6dae6dSNick Piggin 	return ret;
954a6dae6dSNick Piggin }
96ff5b4f1eSMark Rutland EXPORT_SYMBOL(arch_atomic_cmpxchg);
971da177e4SLinus Torvalds 
arch_atomic_fetch_add_unless(atomic_t * v,int a,int u)98ff5b4f1eSMark Rutland int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
998426e1f6SNick Piggin {
1008426e1f6SNick Piggin 	int ret;
1018426e1f6SNick Piggin 	unsigned long flags;
1028426e1f6SNick Piggin 
1038426e1f6SNick Piggin 	spin_lock_irqsave(ATOMIC_HASH(v), flags);
1048426e1f6SNick Piggin 	ret = v->counter;
1058426e1f6SNick Piggin 	if (ret != u)
1068426e1f6SNick Piggin 		v->counter += a;
1078426e1f6SNick Piggin 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
108a61b5829SJosip Rodin 	return ret;
1098426e1f6SNick Piggin }
110ff5b4f1eSMark Rutland EXPORT_SYMBOL(arch_atomic_fetch_add_unless);
1118426e1f6SNick Piggin 
1128426e1f6SNick Piggin /* Atomic operations are already serializing */
arch_atomic_set(atomic_t * v,int i)113ff5b4f1eSMark Rutland void arch_atomic_set(atomic_t *v, int i)
1141da177e4SLinus Torvalds {
1151da177e4SLinus Torvalds 	unsigned long flags;
1164a6dae6dSNick Piggin 
1171da177e4SLinus Torvalds 	spin_lock_irqsave(ATOMIC_HASH(v), flags);
1181da177e4SLinus Torvalds 	v->counter = i;
1191da177e4SLinus Torvalds 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
1201da177e4SLinus Torvalds }
121ff5b4f1eSMark Rutland EXPORT_SYMBOL(arch_atomic_set);
1228a8b836bSDavid S. Miller 
sp32___set_bit(unsigned long * addr,unsigned long mask)123*e69eb9c4SAlexander Lobakin unsigned long sp32___set_bit(unsigned long *addr, unsigned long mask)
1248a8b836bSDavid S. Miller {
1258a8b836bSDavid S. Miller 	unsigned long old, flags;
1268a8b836bSDavid S. Miller 
1278a8b836bSDavid S. Miller 	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
1288a8b836bSDavid S. Miller 	old = *addr;
1298a8b836bSDavid S. Miller 	*addr = old | mask;
1308a8b836bSDavid S. Miller 	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
1318a8b836bSDavid S. Miller 
1328a8b836bSDavid S. Miller 	return old & mask;
1338a8b836bSDavid S. Miller }
134*e69eb9c4SAlexander Lobakin EXPORT_SYMBOL(sp32___set_bit);
1358a8b836bSDavid S. Miller 
sp32___clear_bit(unsigned long * addr,unsigned long mask)136*e69eb9c4SAlexander Lobakin unsigned long sp32___clear_bit(unsigned long *addr, unsigned long mask)
1378a8b836bSDavid S. Miller {
1388a8b836bSDavid S. Miller 	unsigned long old, flags;
1398a8b836bSDavid S. Miller 
1408a8b836bSDavid S. Miller 	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
1418a8b836bSDavid S. Miller 	old = *addr;
1428a8b836bSDavid S. Miller 	*addr = old & ~mask;
1438a8b836bSDavid S. Miller 	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
1448a8b836bSDavid S. Miller 
1458a8b836bSDavid S. Miller 	return old & mask;
1468a8b836bSDavid S. Miller }
147*e69eb9c4SAlexander Lobakin EXPORT_SYMBOL(sp32___clear_bit);
1488a8b836bSDavid S. Miller 
sp32___change_bit(unsigned long * addr,unsigned long mask)149*e69eb9c4SAlexander Lobakin unsigned long sp32___change_bit(unsigned long *addr, unsigned long mask)
1508a8b836bSDavid S. Miller {
1518a8b836bSDavid S. Miller 	unsigned long old, flags;
1528a8b836bSDavid S. Miller 
1538a8b836bSDavid S. Miller 	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
1548a8b836bSDavid S. Miller 	old = *addr;
1558a8b836bSDavid S. Miller 	*addr = old ^ mask;
1568a8b836bSDavid S. Miller 	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
1578a8b836bSDavid S. Miller 
1588a8b836bSDavid S. Miller 	return old & mask;
1598a8b836bSDavid S. Miller }
160*e69eb9c4SAlexander Lobakin EXPORT_SYMBOL(sp32___change_bit);
1616197fe4dSKyle McMartin 
__cmpxchg_u32(volatile u32 * ptr,u32 old,u32 new)1626197fe4dSKyle McMartin unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new)
1636197fe4dSKyle McMartin {
1646197fe4dSKyle McMartin 	unsigned long flags;
1656197fe4dSKyle McMartin 	u32 prev;
1666197fe4dSKyle McMartin 
1671fb8812bSAndrew Morton 	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
1686197fe4dSKyle McMartin 	if ((prev = *ptr) == old)
1696197fe4dSKyle McMartin 		*ptr = new;
1701fb8812bSAndrew Morton 	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
1716197fe4dSKyle McMartin 
1726197fe4dSKyle McMartin 	return (unsigned long)prev;
1736197fe4dSKyle McMartin }
1746197fe4dSKyle McMartin EXPORT_SYMBOL(__cmpxchg_u32);
1751a17fdc4SAndreas Larsson 
__cmpxchg_u64(u64 * ptr,u64 old,u64 new)17623198ddfSDavid S. Miller u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new)
17723198ddfSDavid S. Miller {
17823198ddfSDavid S. Miller 	unsigned long flags;
17923198ddfSDavid S. Miller 	u64 prev;
18023198ddfSDavid S. Miller 
18123198ddfSDavid S. Miller 	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
18223198ddfSDavid S. Miller 	if ((prev = *ptr) == old)
18323198ddfSDavid S. Miller 		*ptr = new;
18423198ddfSDavid S. Miller 	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
18523198ddfSDavid S. Miller 
18623198ddfSDavid S. Miller 	return prev;
18723198ddfSDavid S. Miller }
18823198ddfSDavid S. Miller EXPORT_SYMBOL(__cmpxchg_u64);
18923198ddfSDavid S. Miller 
__xchg_u32(volatile u32 * ptr,u32 new)1901a17fdc4SAndreas Larsson unsigned long __xchg_u32(volatile u32 *ptr, u32 new)
1911a17fdc4SAndreas Larsson {
1921a17fdc4SAndreas Larsson 	unsigned long flags;
1931a17fdc4SAndreas Larsson 	u32 prev;
1941a17fdc4SAndreas Larsson 
1951a17fdc4SAndreas Larsson 	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
1961a17fdc4SAndreas Larsson 	prev = *ptr;
1971a17fdc4SAndreas Larsson 	*ptr = new;
1981a17fdc4SAndreas Larsson 	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
1991a17fdc4SAndreas Larsson 
2001a17fdc4SAndreas Larsson 	return (unsigned long)prev;
2011a17fdc4SAndreas Larsson }
2021a17fdc4SAndreas Larsson EXPORT_SYMBOL(__xchg_u32);
203