15b0b14e5SHuacai Chen /* SPDX-License-Identifier: GPL-2.0 */ 25b0b14e5SHuacai Chen /* 35b0b14e5SHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 45b0b14e5SHuacai Chen */ 55b0b14e5SHuacai Chen #ifndef _ARCH_LOONGARCH_LOCAL_H 65b0b14e5SHuacai Chen #define _ARCH_LOONGARCH_LOCAL_H 75b0b14e5SHuacai Chen 85b0b14e5SHuacai Chen #include <linux/percpu.h> 95b0b14e5SHuacai Chen #include <linux/bitops.h> 105b0b14e5SHuacai Chen #include <linux/atomic.h> 115b0b14e5SHuacai Chen #include <asm/cmpxchg.h> 125b0b14e5SHuacai Chen 135b0b14e5SHuacai Chen typedef struct { 145b0b14e5SHuacai Chen atomic_long_t a; 155b0b14e5SHuacai Chen } local_t; 165b0b14e5SHuacai Chen 175b0b14e5SHuacai Chen #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } 185b0b14e5SHuacai Chen 195b0b14e5SHuacai Chen #define local_read(l) atomic_long_read(&(l)->a) 205b0b14e5SHuacai Chen #define local_set(l, i) atomic_long_set(&(l)->a, (i)) 215b0b14e5SHuacai Chen 225b0b14e5SHuacai Chen #define local_add(i, l) atomic_long_add((i), (&(l)->a)) 235b0b14e5SHuacai Chen #define local_sub(i, l) atomic_long_sub((i), (&(l)->a)) 245b0b14e5SHuacai Chen #define local_inc(l) atomic_long_inc(&(l)->a) 255b0b14e5SHuacai Chen #define local_dec(l) atomic_long_dec(&(l)->a) 265b0b14e5SHuacai Chen 275b0b14e5SHuacai Chen /* 285b0b14e5SHuacai Chen * Same as above, but return the result value 295b0b14e5SHuacai Chen */ 305b0b14e5SHuacai Chen static inline long local_add_return(long i, local_t *l) 315b0b14e5SHuacai Chen { 325b0b14e5SHuacai Chen unsigned long result; 335b0b14e5SHuacai Chen 345b0b14e5SHuacai Chen __asm__ __volatile__( 355b0b14e5SHuacai Chen " " __AMADD " %1, %2, %0 \n" 365b0b14e5SHuacai Chen : "+ZB" (l->a.counter), "=&r" (result) 375b0b14e5SHuacai Chen : "r" (i) 385b0b14e5SHuacai Chen : "memory"); 395b0b14e5SHuacai Chen result = result + i; 405b0b14e5SHuacai Chen 415b0b14e5SHuacai Chen return result; 425b0b14e5SHuacai Chen } 435b0b14e5SHuacai Chen 445b0b14e5SHuacai Chen static inline long local_sub_return(long i, local_t *l) 455b0b14e5SHuacai Chen { 465b0b14e5SHuacai Chen unsigned long result; 475b0b14e5SHuacai Chen 485b0b14e5SHuacai Chen __asm__ __volatile__( 495b0b14e5SHuacai Chen " " __AMADD "%1, %2, %0 \n" 505b0b14e5SHuacai Chen : "+ZB" (l->a.counter), "=&r" (result) 515b0b14e5SHuacai Chen : "r" (-i) 525b0b14e5SHuacai Chen : "memory"); 535b0b14e5SHuacai Chen 545b0b14e5SHuacai Chen result = result - i; 555b0b14e5SHuacai Chen 565b0b14e5SHuacai Chen return result; 575b0b14e5SHuacai Chen } 585b0b14e5SHuacai Chen 59*d994f2c8SUros Bizjak static inline long local_cmpxchg(local_t *l, long old, long new) 60*d994f2c8SUros Bizjak { 61*d994f2c8SUros Bizjak return cmpxchg_local(&l->a.counter, old, new); 62*d994f2c8SUros Bizjak } 63*d994f2c8SUros Bizjak 64*d994f2c8SUros Bizjak static inline bool local_try_cmpxchg(local_t *l, long *old, long new) 65*d994f2c8SUros Bizjak { 66*d994f2c8SUros Bizjak typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; 67*d994f2c8SUros Bizjak return try_cmpxchg_local(&l->a.counter, __old, new); 68*d994f2c8SUros Bizjak } 69*d994f2c8SUros Bizjak 705b0b14e5SHuacai Chen #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) 715b0b14e5SHuacai Chen 725b0b14e5SHuacai Chen /** 735b0b14e5SHuacai Chen * local_add_unless - add unless the number is a given value 745b0b14e5SHuacai Chen * @l: pointer of type local_t 755b0b14e5SHuacai Chen * @a: the amount to add to l... 765b0b14e5SHuacai Chen * @u: ...unless l is equal to u. 775b0b14e5SHuacai Chen * 785b0b14e5SHuacai Chen * Atomically adds @a to @l, so long as it was not @u. 795b0b14e5SHuacai Chen * Returns non-zero if @l was not @u, and zero otherwise. 805b0b14e5SHuacai Chen */ 815b0b14e5SHuacai Chen #define local_add_unless(l, a, u) \ 825b0b14e5SHuacai Chen ({ \ 835b0b14e5SHuacai Chen long c, old; \ 845b0b14e5SHuacai Chen c = local_read(l); \ 855b0b14e5SHuacai Chen while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \ 865b0b14e5SHuacai Chen c = old; \ 875b0b14e5SHuacai Chen c != (u); \ 885b0b14e5SHuacai Chen }) 895b0b14e5SHuacai Chen #define local_inc_not_zero(l) local_add_unless((l), 1, 0) 905b0b14e5SHuacai Chen 915b0b14e5SHuacai Chen #define local_dec_return(l) local_sub_return(1, (l)) 925b0b14e5SHuacai Chen #define local_inc_return(l) local_add_return(1, (l)) 935b0b14e5SHuacai Chen 945b0b14e5SHuacai Chen /* 955b0b14e5SHuacai Chen * local_sub_and_test - subtract value from variable and test result 965b0b14e5SHuacai Chen * @i: integer value to subtract 975b0b14e5SHuacai Chen * @l: pointer of type local_t 985b0b14e5SHuacai Chen * 995b0b14e5SHuacai Chen * Atomically subtracts @i from @l and returns 1005b0b14e5SHuacai Chen * true if the result is zero, or false for all 1015b0b14e5SHuacai Chen * other cases. 1025b0b14e5SHuacai Chen */ 1035b0b14e5SHuacai Chen #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0) 1045b0b14e5SHuacai Chen 1055b0b14e5SHuacai Chen /* 1065b0b14e5SHuacai Chen * local_inc_and_test - increment and test 1075b0b14e5SHuacai Chen * @l: pointer of type local_t 1085b0b14e5SHuacai Chen * 1095b0b14e5SHuacai Chen * Atomically increments @l by 1 1105b0b14e5SHuacai Chen * and returns true if the result is zero, or false for all 1115b0b14e5SHuacai Chen * other cases. 1125b0b14e5SHuacai Chen */ 1135b0b14e5SHuacai Chen #define local_inc_and_test(l) (local_inc_return(l) == 0) 1145b0b14e5SHuacai Chen 1155b0b14e5SHuacai Chen /* 1165b0b14e5SHuacai Chen * local_dec_and_test - decrement by 1 and test 1175b0b14e5SHuacai Chen * @l: pointer of type local_t 1185b0b14e5SHuacai Chen * 1195b0b14e5SHuacai Chen * Atomically decrements @l by 1 and 1205b0b14e5SHuacai Chen * returns true if the result is 0, or false for all other 1215b0b14e5SHuacai Chen * cases. 1225b0b14e5SHuacai Chen */ 1235b0b14e5SHuacai Chen #define local_dec_and_test(l) (local_sub_return(1, (l)) == 0) 1245b0b14e5SHuacai Chen 1255b0b14e5SHuacai Chen /* 1265b0b14e5SHuacai Chen * local_add_negative - add and test if negative 1275b0b14e5SHuacai Chen * @l: pointer of type local_t 1285b0b14e5SHuacai Chen * @i: integer value to add 1295b0b14e5SHuacai Chen * 1305b0b14e5SHuacai Chen * Atomically adds @i to @l and returns true 1315b0b14e5SHuacai Chen * if the result is negative, or false when 1325b0b14e5SHuacai Chen * result is greater than or equal to zero. 1335b0b14e5SHuacai Chen */ 1345b0b14e5SHuacai Chen #define local_add_negative(i, l) (local_add_return(i, (l)) < 0) 1355b0b14e5SHuacai Chen 1365b0b14e5SHuacai Chen /* Use these for per-cpu local_t variables: on some archs they are 1375b0b14e5SHuacai Chen * much more efficient than these naive implementations. Note they take 1385b0b14e5SHuacai Chen * a variable, not an address. 1395b0b14e5SHuacai Chen */ 1405b0b14e5SHuacai Chen 1415b0b14e5SHuacai Chen #define __local_inc(l) ((l)->a.counter++) 1425b0b14e5SHuacai Chen #define __local_dec(l) ((l)->a.counter++) 1435b0b14e5SHuacai Chen #define __local_add(i, l) ((l)->a.counter += (i)) 1445b0b14e5SHuacai Chen #define __local_sub(i, l) ((l)->a.counter -= (i)) 1455b0b14e5SHuacai Chen 1465b0b14e5SHuacai Chen #endif /* _ARCH_LOONGARCH_LOCAL_H */ 147