FILE
local.h
File preview with syntax highlighting.
linux-6.19.14/arch/loongarch/include/asm/local.h
1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 */ 5#ifndef _ARCH_LOONGARCH_LOCAL_H 6#define _ARCH_LOONGARCH_LOCAL_H 7 8#include <linux/percpu.h> 9#include <linux/bitops.h> 10#include <linux/atomic.h> 11#include <asm/asm.h> 12#include <asm/cmpxchg.h> 13 14typedef struct { 15 atomic_long_t a; 16} local_t; 17 18#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } 19 20#define local_read(l) atomic_long_read(&(l)->a) 21#define local_set(l, i) atomic_long_set(&(l)->a, (i)) 22 23#define local_add(i, l) atomic_long_add((i), (&(l)->a)) 24#define local_sub(i, l) atomic_long_sub((i), (&(l)->a)) 25#define local_inc(l) atomic_long_inc(&(l)->a) 26#define local_dec(l) atomic_long_dec(&(l)->a) 27 28/* 29 * Same as above, but return the result value 30 */ 31#ifdef CONFIG_CPU_HAS_AMO 32static inline long local_add_return(long i, local_t *l) 33{ 34 unsigned long result; 35 36 __asm__ __volatile__( 37 " " __AMADD " %1, %2, %0 \n" 38 : "+ZB" (l->a.counter), "=&r" (result) 39 : "r" (i) 40 : "memory"); 41 result = result + i; 42 43 return result; 44} 45 46static inline long local_sub_return(long i, local_t *l) 47{ 48 unsigned long result; 49 50 __asm__ __volatile__( 51 " " __AMADD "%1, %2, %0 \n" 52 : "+ZB" (l->a.counter), "=&r" (result) 53 : "r" (-i) 54 : "memory"); 55 56 result = result - i; 57 58 return result; 59} 60#else 61static inline long local_add_return(long i, local_t *l) 62{ 63 unsigned long result, temp; 64 65 __asm__ __volatile__( 66 "1:" __LL "%1, %2 # local_add_return \n" 67 __stringify(LONG_ADD) " %0, %1, %3 \n" 68 __SC "%0, %2 \n" 69 " beq %0, $r0, 1b \n" 70 __stringify(LONG_ADD) " %0, %1, %3 \n" 71 : "=&r" (result), "=&r" (temp), "=ZC" (l->a.counter) 72 : "r" (i), "ZC" (l->a.counter) 73 : "memory"); 74 75 return result; 76} 77 78static inline long local_sub_return(long i, local_t *l) 79{ 80 unsigned long result, temp; 81 82 __asm__ __volatile__( 83 "1:" __LL "%1, %2 # local_sub_return \n" 84 __stringify(LONG_SUB) " %0, %1, %3 \n" 85 __SC "%0, %2 \n" 86 " beq %0, $r0, 1b \n" 87 __stringify(LONG_SUB) " %0, %1, %3 \n" 88 : "=&r" (result), "=&r" (temp), "=ZC" (l->a.counter) 89 : "r" (i), "ZC" (l->a.counter) 90 : "memory"); 91 92 return result; 93} 94#endif 95 96static inline long local_cmpxchg(local_t *l, long old, long new) 97{ 98 return cmpxchg_local(&l->a.counter, old, new); 99} 100 101static inline bool local_try_cmpxchg(local_t *l, long *old, long new) 102{ 103 return try_cmpxchg_local(&l->a.counter, 104 (typeof(l->a.counter) *) old, new); 105} 106 107#define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) 108 109/** 110 * local_add_unless - add unless the number is already a given value 111 * @l: pointer of type local_t 112 * @a: the amount to add to l... 113 * @u: ...unless l is equal to u. 114 * 115 * Atomically adds @a to @l, if @v was not already @u. 116 * Returns true if the addition was done. 117 */ 118static inline bool 119local_add_unless(local_t *l, long a, long u) 120{ 121 long c = local_read(l); 122 123 do { 124 if (unlikely(c == u)) 125 return false; 126 } while (!local_try_cmpxchg(l, &c, c + a)); 127 128 return true; 129} 130 131#define local_inc_not_zero(l) local_add_unless((l), 1, 0) 132 133#define local_dec_return(l) local_sub_return(1, (l)) 134#define local_inc_return(l) local_add_return(1, (l)) 135 136/* 137 * local_sub_and_test - subtract value from variable and test result 138 * @i: integer value to subtract 139 * @l: pointer of type local_t 140 * 141 * Atomically subtracts @i from @l and returns 142 * true if the result is zero, or false for all 143 * other cases. 144 */ 145#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0) 146 147/* 148 * local_inc_and_test - increment and test 149 * @l: pointer of type local_t 150 * 151 * Atomically increments @l by 1 152 * and returns true if the result is zero, or false for all 153 * other cases. 154 */ 155#define local_inc_and_test(l) (local_inc_return(l) == 0) 156 157/* 158 * local_dec_and_test - decrement by 1 and test 159 * @l: pointer of type local_t 160 * 161 * Atomically decrements @l by 1 and 162 * returns true if the result is 0, or false for all other 163 * cases. 164 */ 165#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0) 166 167/* 168 * local_add_negative - add and test if negative 169 * @l: pointer of type local_t 170 * @i: integer value to add 171 * 172 * Atomically adds @i to @l and returns true 173 * if the result is negative, or false when 174 * result is greater than or equal to zero. 175 */ 176#define local_add_negative(i, l) (local_add_return(i, (l)) < 0) 177 178/* Use these for per-cpu local_t variables: on some archs they are 179 * much more efficient than these naive implementations. Note they take 180 * a variable, not an address. 181 */ 182 183#define __local_inc(l) ((l)->a.counter++) 184#define __local_dec(l) ((l)->a.counter++) 185#define __local_add(i, l) ((l)->a.counter += (i)) 186#define __local_sub(i, l) ((l)->a.counter -= (i)) 187 188#endif /* _ARCH_LOONGARCH_LOCAL_H */
~/
Read-only file preview.