18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ARCH_POWERPC_LOCAL_H
38c2ecf20Sopenharmony_ci#define _ARCH_POWERPC_LOCAL_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/percpu.h>
88c2ecf20Sopenharmony_ci#include <linux/atomic.h>
98c2ecf20Sopenharmony_ci#include <linux/irqflags.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/hw_irq.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_citypedef struct
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	long v;
168c2ecf20Sopenharmony_ci} local_t;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define LOCAL_INIT(i)	{ (i) }
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic __inline__ long local_read(const local_t *l)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	return READ_ONCE(l->v);
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic __inline__ void local_set(local_t *l, long i)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	WRITE_ONCE(l->v, i);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define LOCAL_OP(op, c_op)						\
318c2ecf20Sopenharmony_cistatic __inline__ void local_##op(long i, local_t *l)			\
328c2ecf20Sopenharmony_ci{									\
338c2ecf20Sopenharmony_ci	unsigned long flags;						\
348c2ecf20Sopenharmony_ci									\
358c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_save(flags);				\
368c2ecf20Sopenharmony_ci	l->v c_op i;						\
378c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_restore(flags);				\
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define LOCAL_OP_RETURN(op, c_op)					\
418c2ecf20Sopenharmony_cistatic __inline__ long local_##op##_return(long a, local_t *l)		\
428c2ecf20Sopenharmony_ci{									\
438c2ecf20Sopenharmony_ci	long t;								\
448c2ecf20Sopenharmony_ci	unsigned long flags;						\
458c2ecf20Sopenharmony_ci									\
468c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_save(flags);				\
478c2ecf20Sopenharmony_ci	t = (l->v c_op a);						\
488c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_restore(flags);				\
498c2ecf20Sopenharmony_ci									\
508c2ecf20Sopenharmony_ci	return t;							\
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define LOCAL_OPS(op, c_op)		\
548c2ecf20Sopenharmony_ci	LOCAL_OP(op, c_op)		\
558c2ecf20Sopenharmony_ci	LOCAL_OP_RETURN(op, c_op)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ciLOCAL_OPS(add, +=)
588c2ecf20Sopenharmony_ciLOCAL_OPS(sub, -=)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define local_add_negative(a, l)	(local_add_return((a), (l)) < 0)
618c2ecf20Sopenharmony_ci#define local_inc_return(l)		local_add_return(1LL, l)
628c2ecf20Sopenharmony_ci#define local_inc(l)			local_inc_return(l)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * local_inc_and_test - increment and test
668c2ecf20Sopenharmony_ci * @l: pointer of type local_t
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * Atomically increments @l by 1
698c2ecf20Sopenharmony_ci * and returns true if the result is zero, or false for all
708c2ecf20Sopenharmony_ci * other cases.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ci#define local_inc_and_test(l)		(local_inc_return(l) == 0)
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define local_dec_return(l)		local_sub_return(1LL, l)
758c2ecf20Sopenharmony_ci#define local_dec(l)			local_dec_return(l)
768c2ecf20Sopenharmony_ci#define local_sub_and_test(a, l)	(local_sub_return((a), (l)) == 0)
778c2ecf20Sopenharmony_ci#define local_dec_and_test(l)		(local_dec_return((l)) == 0)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic __inline__ long local_cmpxchg(local_t *l, long o, long n)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	long t;
828c2ecf20Sopenharmony_ci	unsigned long flags;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_save(flags);
858c2ecf20Sopenharmony_ci	t = l->v;
868c2ecf20Sopenharmony_ci	if (t == o)
878c2ecf20Sopenharmony_ci		l->v = n;
888c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_restore(flags);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return t;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic __inline__ long local_xchg(local_t *l, long n)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	long t;
968c2ecf20Sopenharmony_ci	unsigned long flags;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_save(flags);
998c2ecf20Sopenharmony_ci	t = l->v;
1008c2ecf20Sopenharmony_ci	l->v = n;
1018c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_restore(flags);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return t;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/**
1078c2ecf20Sopenharmony_ci * local_add_unless - add unless the number is a given value
1088c2ecf20Sopenharmony_ci * @l: pointer of type local_t
1098c2ecf20Sopenharmony_ci * @a: the amount to add to v...
1108c2ecf20Sopenharmony_ci * @u: ...unless v is equal to u.
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci * Atomically adds @a to @l, so long as it was not @u.
1138c2ecf20Sopenharmony_ci * Returns non-zero if @l was not @u, and zero otherwise.
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_cistatic __inline__ int local_add_unless(local_t *l, long a, long u)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	unsigned long flags;
1188c2ecf20Sopenharmony_ci	int ret = 0;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_save(flags);
1218c2ecf20Sopenharmony_ci	if (l->v != u) {
1228c2ecf20Sopenharmony_ci		l->v += a;
1238c2ecf20Sopenharmony_ci		ret = 1;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci	powerpc_local_irq_pmu_restore(flags);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return ret;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#define local_inc_not_zero(l)		local_add_unless((l), 1, 0)
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* Use these for per-cpu local_t variables: on some archs they are
1338c2ecf20Sopenharmony_ci * much more efficient than these naive implementations.  Note they take
1348c2ecf20Sopenharmony_ci * a variable, not an address.
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define __local_inc(l)		((l)->v++)
1388c2ecf20Sopenharmony_ci#define __local_dec(l)		((l)->v++)
1398c2ecf20Sopenharmony_ci#define __local_add(i,l)	((l)->v+=(i))
1408c2ecf20Sopenharmony_ci#define __local_sub(i,l)	((l)->v-=(i))
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci#else /* CONFIG_PPC64 */
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci#include <asm-generic/local.h>
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#endif /* _ARCH_POWERPC_LOCAL_H */
149