162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_ATOMIC_H_ 362306a36Sopenharmony_ci#define _ASM_POWERPC_ATOMIC_H_ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * PowerPC atomic operations 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifdef __KERNEL__ 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <asm/cmpxchg.h> 1262306a36Sopenharmony_ci#include <asm/barrier.h> 1362306a36Sopenharmony_ci#include <asm/asm-const.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with 1762306a36Sopenharmony_ci * a "bne-" instruction at the end, so an isync is enough as a acquire barrier 1862306a36Sopenharmony_ci * on the platform without lwsync. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci#define __atomic_acquire_fence() \ 2162306a36Sopenharmony_ci __asm__ __volatile__(PPC_ACQUIRE_BARRIER "" : : : "memory") 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define __atomic_release_fence() \ 2462306a36Sopenharmony_ci __asm__ __volatile__(PPC_RELEASE_BARRIER "" : : : "memory") 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic __inline__ int arch_atomic_read(const atomic_t *v) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci int t; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* -mprefixed can generate offsets beyond range, fall back hack */ 3162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) 3262306a36Sopenharmony_ci __asm__ __volatile__("lwz %0,0(%1)" : "=r"(t) : "b"(&v->counter)); 3362306a36Sopenharmony_ci else 3462306a36Sopenharmony_ci __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return t; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic __inline__ void arch_atomic_set(atomic_t *v, int i) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci /* -mprefixed can generate offsets beyond range, fall back hack */ 4262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) 4362306a36Sopenharmony_ci __asm__ __volatile__("stw %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter)); 4462306a36Sopenharmony_ci else 4562306a36Sopenharmony_ci __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define ATOMIC_OP(op, asm_op, suffix, sign, ...) \ 4962306a36Sopenharmony_cistatic __inline__ void arch_atomic_##op(int a, atomic_t *v) \ 5062306a36Sopenharmony_ci{ \ 5162306a36Sopenharmony_ci int t; \ 5262306a36Sopenharmony_ci \ 5362306a36Sopenharmony_ci __asm__ __volatile__( \ 5462306a36Sopenharmony_ci"1: lwarx %0,0,%3 # atomic_" #op "\n" \ 5562306a36Sopenharmony_ci #asm_op "%I2" suffix " %0,%0,%2\n" \ 5662306a36Sopenharmony_ci" stwcx. %0,0,%3 \n" \ 5762306a36Sopenharmony_ci" bne- 1b\n" \ 5862306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) \ 5962306a36Sopenharmony_ci : "r"#sign (a), "r" (&v->counter) \ 6062306a36Sopenharmony_ci : "cc", ##__VA_ARGS__); \ 6162306a36Sopenharmony_ci} \ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define ATOMIC_OP_RETURN_RELAXED(op, asm_op, suffix, sign, ...) \ 6462306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return_relaxed(int a, atomic_t *v) \ 6562306a36Sopenharmony_ci{ \ 6662306a36Sopenharmony_ci int t; \ 6762306a36Sopenharmony_ci \ 6862306a36Sopenharmony_ci __asm__ __volatile__( \ 6962306a36Sopenharmony_ci"1: lwarx %0,0,%3 # atomic_" #op "_return_relaxed\n" \ 7062306a36Sopenharmony_ci #asm_op "%I2" suffix " %0,%0,%2\n" \ 7162306a36Sopenharmony_ci" stwcx. %0,0,%3\n" \ 7262306a36Sopenharmony_ci" bne- 1b\n" \ 7362306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) \ 7462306a36Sopenharmony_ci : "r"#sign (a), "r" (&v->counter) \ 7562306a36Sopenharmony_ci : "cc", ##__VA_ARGS__); \ 7662306a36Sopenharmony_ci \ 7762306a36Sopenharmony_ci return t; \ 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define ATOMIC_FETCH_OP_RELAXED(op, asm_op, suffix, sign, ...) \ 8162306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op##_relaxed(int a, atomic_t *v) \ 8262306a36Sopenharmony_ci{ \ 8362306a36Sopenharmony_ci int res, t; \ 8462306a36Sopenharmony_ci \ 8562306a36Sopenharmony_ci __asm__ __volatile__( \ 8662306a36Sopenharmony_ci"1: lwarx %0,0,%4 # atomic_fetch_" #op "_relaxed\n" \ 8762306a36Sopenharmony_ci #asm_op "%I3" suffix " %1,%0,%3\n" \ 8862306a36Sopenharmony_ci" stwcx. %1,0,%4\n" \ 8962306a36Sopenharmony_ci" bne- 1b\n" \ 9062306a36Sopenharmony_ci : "=&r" (res), "=&r" (t), "+m" (v->counter) \ 9162306a36Sopenharmony_ci : "r"#sign (a), "r" (&v->counter) \ 9262306a36Sopenharmony_ci : "cc", ##__VA_ARGS__); \ 9362306a36Sopenharmony_ci \ 9462306a36Sopenharmony_ci return res; \ 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define ATOMIC_OPS(op, asm_op, suffix, sign, ...) \ 9862306a36Sopenharmony_ci ATOMIC_OP(op, asm_op, suffix, sign, ##__VA_ARGS__) \ 9962306a36Sopenharmony_ci ATOMIC_OP_RETURN_RELAXED(op, asm_op, suffix, sign, ##__VA_ARGS__)\ 10062306a36Sopenharmony_ci ATOMIC_FETCH_OP_RELAXED(op, asm_op, suffix, sign, ##__VA_ARGS__) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciATOMIC_OPS(add, add, "c", I, "xer") 10362306a36Sopenharmony_ciATOMIC_OPS(sub, sub, "c", I, "xer") 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed 10662306a36Sopenharmony_ci#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed 10962306a36Sopenharmony_ci#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#undef ATOMIC_OPS 11262306a36Sopenharmony_ci#define ATOMIC_OPS(op, asm_op, suffix, sign) \ 11362306a36Sopenharmony_ci ATOMIC_OP(op, asm_op, suffix, sign) \ 11462306a36Sopenharmony_ci ATOMIC_FETCH_OP_RELAXED(op, asm_op, suffix, sign) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciATOMIC_OPS(and, and, ".", K) 11762306a36Sopenharmony_ciATOMIC_OPS(or, or, "", K) 11862306a36Sopenharmony_ciATOMIC_OPS(xor, xor, "", K) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed 12162306a36Sopenharmony_ci#define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed 12262306a36Sopenharmony_ci#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#undef ATOMIC_OPS 12562306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP_RELAXED 12662306a36Sopenharmony_ci#undef ATOMIC_OP_RETURN_RELAXED 12762306a36Sopenharmony_ci#undef ATOMIC_OP 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/** 13062306a36Sopenharmony_ci * atomic_fetch_add_unless - add unless the number is a given value 13162306a36Sopenharmony_ci * @v: pointer of type atomic_t 13262306a36Sopenharmony_ci * @a: the amount to add to v... 13362306a36Sopenharmony_ci * @u: ...unless v is equal to u. 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u. 13662306a36Sopenharmony_ci * Returns the old value of @v. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_cistatic __inline__ int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci int t; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci __asm__ __volatile__ ( 14362306a36Sopenharmony_ci PPC_ATOMIC_ENTRY_BARRIER 14462306a36Sopenharmony_ci"1: lwarx %0,0,%1 # atomic_fetch_add_unless\n\ 14562306a36Sopenharmony_ci cmpw 0,%0,%3 \n\ 14662306a36Sopenharmony_ci beq 2f \n\ 14762306a36Sopenharmony_ci add%I2c %0,%0,%2 \n" 14862306a36Sopenharmony_ci" stwcx. %0,0,%1 \n\ 14962306a36Sopenharmony_ci bne- 1b \n" 15062306a36Sopenharmony_ci PPC_ATOMIC_EXIT_BARRIER 15162306a36Sopenharmony_ci" sub%I2c %0,%0,%2 \n\ 15262306a36Sopenharmony_ci2:" 15362306a36Sopenharmony_ci : "=&r" (t) 15462306a36Sopenharmony_ci : "r" (&v->counter), "rI" (a), "r" (u) 15562306a36Sopenharmony_ci : "cc", "memory", "xer"); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return t; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * Atomically test *v and decrement if it is greater than 0. 16362306a36Sopenharmony_ci * The function returns the old value of *v minus 1, even if 16462306a36Sopenharmony_ci * the atomic variable, v, was not decremented. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic __inline__ int arch_atomic_dec_if_positive(atomic_t *v) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int t; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci __asm__ __volatile__( 17162306a36Sopenharmony_ci PPC_ATOMIC_ENTRY_BARRIER 17262306a36Sopenharmony_ci"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\ 17362306a36Sopenharmony_ci cmpwi %0,1\n\ 17462306a36Sopenharmony_ci addi %0,%0,-1\n\ 17562306a36Sopenharmony_ci blt- 2f\n" 17662306a36Sopenharmony_ci" stwcx. %0,0,%1\n\ 17762306a36Sopenharmony_ci bne- 1b" 17862306a36Sopenharmony_ci PPC_ATOMIC_EXIT_BARRIER 17962306a36Sopenharmony_ci "\n\ 18062306a36Sopenharmony_ci2:" : "=&b" (t) 18162306a36Sopenharmony_ci : "r" (&v->counter) 18262306a36Sopenharmony_ci : "cc", "memory"); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return t; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci#define arch_atomic_dec_if_positive arch_atomic_dec_if_positive 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#ifdef __powerpc64__ 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci#define ATOMIC64_INIT(i) { (i) } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_read(const atomic64_t *v) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci s64 t; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* -mprefixed can generate offsets beyond range, fall back hack */ 19762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) 19862306a36Sopenharmony_ci __asm__ __volatile__("ld %0,0(%1)" : "=r"(t) : "b"(&v->counter)); 19962306a36Sopenharmony_ci else 20062306a36Sopenharmony_ci __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return t; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic __inline__ void arch_atomic64_set(atomic64_t *v, s64 i) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci /* -mprefixed can generate offsets beyond range, fall back hack */ 20862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) 20962306a36Sopenharmony_ci __asm__ __volatile__("std %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter)); 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci#define ATOMIC64_OP(op, asm_op) \ 21562306a36Sopenharmony_cistatic __inline__ void arch_atomic64_##op(s64 a, atomic64_t *v) \ 21662306a36Sopenharmony_ci{ \ 21762306a36Sopenharmony_ci s64 t; \ 21862306a36Sopenharmony_ci \ 21962306a36Sopenharmony_ci __asm__ __volatile__( \ 22062306a36Sopenharmony_ci"1: ldarx %0,0,%3 # atomic64_" #op "\n" \ 22162306a36Sopenharmony_ci #asm_op " %0,%2,%0\n" \ 22262306a36Sopenharmony_ci" stdcx. %0,0,%3 \n" \ 22362306a36Sopenharmony_ci" bne- 1b\n" \ 22462306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) \ 22562306a36Sopenharmony_ci : "r" (a), "r" (&v->counter) \ 22662306a36Sopenharmony_ci : "cc"); \ 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define ATOMIC64_OP_RETURN_RELAXED(op, asm_op) \ 23062306a36Sopenharmony_cistatic inline s64 \ 23162306a36Sopenharmony_ciarch_atomic64_##op##_return_relaxed(s64 a, atomic64_t *v) \ 23262306a36Sopenharmony_ci{ \ 23362306a36Sopenharmony_ci s64 t; \ 23462306a36Sopenharmony_ci \ 23562306a36Sopenharmony_ci __asm__ __volatile__( \ 23662306a36Sopenharmony_ci"1: ldarx %0,0,%3 # atomic64_" #op "_return_relaxed\n" \ 23762306a36Sopenharmony_ci #asm_op " %0,%2,%0\n" \ 23862306a36Sopenharmony_ci" stdcx. %0,0,%3\n" \ 23962306a36Sopenharmony_ci" bne- 1b\n" \ 24062306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) \ 24162306a36Sopenharmony_ci : "r" (a), "r" (&v->counter) \ 24262306a36Sopenharmony_ci : "cc"); \ 24362306a36Sopenharmony_ci \ 24462306a36Sopenharmony_ci return t; \ 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci#define ATOMIC64_FETCH_OP_RELAXED(op, asm_op) \ 24862306a36Sopenharmony_cistatic inline s64 \ 24962306a36Sopenharmony_ciarch_atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v) \ 25062306a36Sopenharmony_ci{ \ 25162306a36Sopenharmony_ci s64 res, t; \ 25262306a36Sopenharmony_ci \ 25362306a36Sopenharmony_ci __asm__ __volatile__( \ 25462306a36Sopenharmony_ci"1: ldarx %0,0,%4 # atomic64_fetch_" #op "_relaxed\n" \ 25562306a36Sopenharmony_ci #asm_op " %1,%3,%0\n" \ 25662306a36Sopenharmony_ci" stdcx. %1,0,%4\n" \ 25762306a36Sopenharmony_ci" bne- 1b\n" \ 25862306a36Sopenharmony_ci : "=&r" (res), "=&r" (t), "+m" (v->counter) \ 25962306a36Sopenharmony_ci : "r" (a), "r" (&v->counter) \ 26062306a36Sopenharmony_ci : "cc"); \ 26162306a36Sopenharmony_ci \ 26262306a36Sopenharmony_ci return res; \ 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#define ATOMIC64_OPS(op, asm_op) \ 26662306a36Sopenharmony_ci ATOMIC64_OP(op, asm_op) \ 26762306a36Sopenharmony_ci ATOMIC64_OP_RETURN_RELAXED(op, asm_op) \ 26862306a36Sopenharmony_ci ATOMIC64_FETCH_OP_RELAXED(op, asm_op) 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciATOMIC64_OPS(add, add) 27162306a36Sopenharmony_ciATOMIC64_OPS(sub, subf) 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed 27462306a36Sopenharmony_ci#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed 27762306a36Sopenharmony_ci#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci#undef ATOMIC64_OPS 28062306a36Sopenharmony_ci#define ATOMIC64_OPS(op, asm_op) \ 28162306a36Sopenharmony_ci ATOMIC64_OP(op, asm_op) \ 28262306a36Sopenharmony_ci ATOMIC64_FETCH_OP_RELAXED(op, asm_op) 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciATOMIC64_OPS(and, and) 28562306a36Sopenharmony_ciATOMIC64_OPS(or, or) 28662306a36Sopenharmony_ciATOMIC64_OPS(xor, xor) 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed 28962306a36Sopenharmony_ci#define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed 29062306a36Sopenharmony_ci#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci#undef ATOPIC64_OPS 29362306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OP_RELAXED 29462306a36Sopenharmony_ci#undef ATOMIC64_OP_RETURN_RELAXED 29562306a36Sopenharmony_ci#undef ATOMIC64_OP 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic __inline__ void arch_atomic64_inc(atomic64_t *v) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci s64 t; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci __asm__ __volatile__( 30262306a36Sopenharmony_ci"1: ldarx %0,0,%2 # atomic64_inc\n\ 30362306a36Sopenharmony_ci addic %0,%0,1\n\ 30462306a36Sopenharmony_ci stdcx. %0,0,%2 \n\ 30562306a36Sopenharmony_ci bne- 1b" 30662306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) 30762306a36Sopenharmony_ci : "r" (&v->counter) 30862306a36Sopenharmony_ci : "cc", "xer"); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci#define arch_atomic64_inc arch_atomic64_inc 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_inc_return_relaxed(atomic64_t *v) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci s64 t; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci __asm__ __volatile__( 31762306a36Sopenharmony_ci"1: ldarx %0,0,%2 # atomic64_inc_return_relaxed\n" 31862306a36Sopenharmony_ci" addic %0,%0,1\n" 31962306a36Sopenharmony_ci" stdcx. %0,0,%2\n" 32062306a36Sopenharmony_ci" bne- 1b" 32162306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) 32262306a36Sopenharmony_ci : "r" (&v->counter) 32362306a36Sopenharmony_ci : "cc", "xer"); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return t; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic __inline__ void arch_atomic64_dec(atomic64_t *v) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci s64 t; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci __asm__ __volatile__( 33362306a36Sopenharmony_ci"1: ldarx %0,0,%2 # atomic64_dec\n\ 33462306a36Sopenharmony_ci addic %0,%0,-1\n\ 33562306a36Sopenharmony_ci stdcx. %0,0,%2\n\ 33662306a36Sopenharmony_ci bne- 1b" 33762306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) 33862306a36Sopenharmony_ci : "r" (&v->counter) 33962306a36Sopenharmony_ci : "cc", "xer"); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci#define arch_atomic64_dec arch_atomic64_dec 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_dec_return_relaxed(atomic64_t *v) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci s64 t; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci __asm__ __volatile__( 34862306a36Sopenharmony_ci"1: ldarx %0,0,%2 # atomic64_dec_return_relaxed\n" 34962306a36Sopenharmony_ci" addic %0,%0,-1\n" 35062306a36Sopenharmony_ci" stdcx. %0,0,%2\n" 35162306a36Sopenharmony_ci" bne- 1b" 35262306a36Sopenharmony_ci : "=&r" (t), "+m" (v->counter) 35362306a36Sopenharmony_ci : "r" (&v->counter) 35462306a36Sopenharmony_ci : "cc", "xer"); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return t; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci#define arch_atomic64_inc_return_relaxed arch_atomic64_inc_return_relaxed 36062306a36Sopenharmony_ci#define arch_atomic64_dec_return_relaxed arch_atomic64_dec_return_relaxed 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* 36362306a36Sopenharmony_ci * Atomically test *v and decrement if it is greater than 0. 36462306a36Sopenharmony_ci * The function returns the old value of *v minus 1. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_dec_if_positive(atomic64_t *v) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci s64 t; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci __asm__ __volatile__( 37162306a36Sopenharmony_ci PPC_ATOMIC_ENTRY_BARRIER 37262306a36Sopenharmony_ci"1: ldarx %0,0,%1 # atomic64_dec_if_positive\n\ 37362306a36Sopenharmony_ci addic. %0,%0,-1\n\ 37462306a36Sopenharmony_ci blt- 2f\n\ 37562306a36Sopenharmony_ci stdcx. %0,0,%1\n\ 37662306a36Sopenharmony_ci bne- 1b" 37762306a36Sopenharmony_ci PPC_ATOMIC_EXIT_BARRIER 37862306a36Sopenharmony_ci "\n\ 37962306a36Sopenharmony_ci2:" : "=&r" (t) 38062306a36Sopenharmony_ci : "r" (&v->counter) 38162306a36Sopenharmony_ci : "cc", "xer", "memory"); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return t; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * atomic64_fetch_add_unless - add unless the number is a given value 38962306a36Sopenharmony_ci * @v: pointer of type atomic64_t 39062306a36Sopenharmony_ci * @a: the amount to add to v... 39162306a36Sopenharmony_ci * @u: ...unless v is equal to u. 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u. 39462306a36Sopenharmony_ci * Returns the old value of @v. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci s64 t; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci __asm__ __volatile__ ( 40162306a36Sopenharmony_ci PPC_ATOMIC_ENTRY_BARRIER 40262306a36Sopenharmony_ci"1: ldarx %0,0,%1 # atomic64_fetch_add_unless\n\ 40362306a36Sopenharmony_ci cmpd 0,%0,%3 \n\ 40462306a36Sopenharmony_ci beq 2f \n\ 40562306a36Sopenharmony_ci add %0,%2,%0 \n" 40662306a36Sopenharmony_ci" stdcx. %0,0,%1 \n\ 40762306a36Sopenharmony_ci bne- 1b \n" 40862306a36Sopenharmony_ci PPC_ATOMIC_EXIT_BARRIER 40962306a36Sopenharmony_ci" subf %0,%2,%0 \n\ 41062306a36Sopenharmony_ci2:" 41162306a36Sopenharmony_ci : "=&r" (t) 41262306a36Sopenharmony_ci : "r" (&v->counter), "r" (a), "r" (u) 41362306a36Sopenharmony_ci : "cc", "memory"); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return t; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/** 42062306a36Sopenharmony_ci * atomic_inc64_not_zero - increment unless the number is zero 42162306a36Sopenharmony_ci * @v: pointer of type atomic64_t 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * Atomically increments @v by 1, so long as @v is non-zero. 42462306a36Sopenharmony_ci * Returns non-zero if @v was non-zero, and zero otherwise. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_cistatic __inline__ int arch_atomic64_inc_not_zero(atomic64_t *v) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci s64 t1, t2; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci __asm__ __volatile__ ( 43162306a36Sopenharmony_ci PPC_ATOMIC_ENTRY_BARRIER 43262306a36Sopenharmony_ci"1: ldarx %0,0,%2 # atomic64_inc_not_zero\n\ 43362306a36Sopenharmony_ci cmpdi 0,%0,0\n\ 43462306a36Sopenharmony_ci beq- 2f\n\ 43562306a36Sopenharmony_ci addic %1,%0,1\n\ 43662306a36Sopenharmony_ci stdcx. %1,0,%2\n\ 43762306a36Sopenharmony_ci bne- 1b\n" 43862306a36Sopenharmony_ci PPC_ATOMIC_EXIT_BARRIER 43962306a36Sopenharmony_ci "\n\ 44062306a36Sopenharmony_ci2:" 44162306a36Sopenharmony_ci : "=&r" (t1), "=&r" (t2) 44262306a36Sopenharmony_ci : "r" (&v->counter) 44362306a36Sopenharmony_ci : "cc", "xer", "memory"); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return t1 != 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci#define arch_atomic64_inc_not_zero(v) arch_atomic64_inc_not_zero((v)) 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci#endif /* __powerpc64__ */ 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci#endif /* __KERNEL__ */ 45262306a36Sopenharmony_ci#endif /* _ASM_POWERPC_ATOMIC_H_ */ 453