Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ARCH_MIPS_LOCAL_H
0003 #define _ARCH_MIPS_LOCAL_H
0004 
0005 #include <linux/percpu.h>
0006 #include <linux/bitops.h>
0007 #include <linux/atomic.h>
0008 #include <asm/asm.h>
0009 #include <asm/cmpxchg.h>
0010 #include <asm/compiler.h>
0011 
0012 typedef struct
0013 {
0014     atomic_long_t a;
0015 } local_t;
0016 
0017 #define LOCAL_INIT(i)   { ATOMIC_LONG_INIT(i) }
0018 
0019 #define local_read(l)   atomic_long_read(&(l)->a)
0020 #define local_set(l, i) atomic_long_set(&(l)->a, (i))
0021 
0022 #define local_add(i, l) atomic_long_add((i), (&(l)->a))
0023 #define local_sub(i, l) atomic_long_sub((i), (&(l)->a))
0024 #define local_inc(l)    atomic_long_inc(&(l)->a)
0025 #define local_dec(l)    atomic_long_dec(&(l)->a)
0026 
0027 /*
0028  * Same as above, but return the result value
0029  */
0030 static __inline__ long local_add_return(long i, local_t * l)
0031 {
0032     unsigned long result;
0033 
0034     if (kernel_uses_llsc) {
0035         unsigned long temp;
0036 
0037         __asm__ __volatile__(
0038         "   .set    push                    \n"
0039         "   .set    "MIPS_ISA_ARCH_LEVEL"           \n"
0040             __SYNC(full, loongson3_war) "                   \n"
0041         "1:"    __stringify(LONG_LL)    "   %1, %2      \n"
0042             __stringify(LONG_ADDU)  "   %0, %1, %3  \n"
0043             __stringify(LONG_SC)    "   %0, %2      \n"
0044             __stringify(SC_BEQZ)    "   %0, 1b      \n"
0045             __stringify(LONG_ADDU)  "   %0, %1, %3  \n"
0046         "   .set    pop                 \n"
0047         : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
0048         : "Ir" (i), "m" (l->a.counter)
0049         : "memory");
0050     } else {
0051         unsigned long flags;
0052 
0053         local_irq_save(flags);
0054         result = l->a.counter;
0055         result += i;
0056         l->a.counter = result;
0057         local_irq_restore(flags);
0058     }
0059 
0060     return result;
0061 }
0062 
0063 static __inline__ long local_sub_return(long i, local_t * l)
0064 {
0065     unsigned long result;
0066 
0067     if (kernel_uses_llsc) {
0068         unsigned long temp;
0069 
0070         __asm__ __volatile__(
0071         "   .set    push                    \n"
0072         "   .set    "MIPS_ISA_ARCH_LEVEL"           \n"
0073             __SYNC(full, loongson3_war) "                   \n"
0074         "1:"    __stringify(LONG_LL)    "   %1, %2      \n"
0075             __stringify(LONG_SUBU)  "   %0, %1, %3  \n"
0076             __stringify(LONG_SUBU)  "   %0, %1, %3  \n"
0077             __stringify(LONG_SC)    "   %0, %2      \n"
0078             __stringify(SC_BEQZ)    "   %0, 1b      \n"
0079             __stringify(LONG_SUBU)  "   %0, %1, %3  \n"
0080         "   .set    pop                 \n"
0081         : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
0082         : "Ir" (i), "m" (l->a.counter)
0083         : "memory");
0084     } else {
0085         unsigned long flags;
0086 
0087         local_irq_save(flags);
0088         result = l->a.counter;
0089         result -= i;
0090         l->a.counter = result;
0091         local_irq_restore(flags);
0092     }
0093 
0094     return result;
0095 }
0096 
0097 #define local_cmpxchg(l, o, n) \
0098     ((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
0099 #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n)))
0100 
0101 /**
0102  * local_add_unless - add unless the number is a given value
0103  * @l: pointer of type local_t
0104  * @a: the amount to add to l...
0105  * @u: ...unless l is equal to u.
0106  *
0107  * Atomically adds @a to @l, so long as it was not @u.
0108  * Returns non-zero if @l was not @u, and zero otherwise.
0109  */
0110 #define local_add_unless(l, a, u)               \
0111 ({                              \
0112     long c, old;                        \
0113     c = local_read(l);                  \
0114     while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
0115         c = old;                    \
0116     c != (u);                       \
0117 })
0118 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
0119 
0120 #define local_dec_return(l) local_sub_return(1, (l))
0121 #define local_inc_return(l) local_add_return(1, (l))
0122 
0123 /*
0124  * local_sub_and_test - subtract value from variable and test result
0125  * @i: integer value to subtract
0126  * @l: pointer of type local_t
0127  *
0128  * Atomically subtracts @i from @l and returns
0129  * true if the result is zero, or false for all
0130  * other cases.
0131  */
0132 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
0133 
0134 /*
0135  * local_inc_and_test - increment and test
0136  * @l: pointer of type local_t
0137  *
0138  * Atomically increments @l by 1
0139  * and returns true if the result is zero, or false for all
0140  * other cases.
0141  */
0142 #define local_inc_and_test(l) (local_inc_return(l) == 0)
0143 
0144 /*
0145  * local_dec_and_test - decrement by 1 and test
0146  * @l: pointer of type local_t
0147  *
0148  * Atomically decrements @l by 1 and
0149  * returns true if the result is 0, or false for all other
0150  * cases.
0151  */
0152 #define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
0153 
0154 /*
0155  * local_add_negative - add and test if negative
0156  * @l: pointer of type local_t
0157  * @i: integer value to add
0158  *
0159  * Atomically adds @i to @l and returns true
0160  * if the result is negative, or false when
0161  * result is greater than or equal to zero.
0162  */
0163 #define local_add_negative(i, l) (local_add_return(i, (l)) < 0)
0164 
0165 /* Use these for per-cpu local_t variables: on some archs they are
0166  * much more efficient than these naive implementations.  Note they take
0167  * a variable, not an address.
0168  */
0169 
0170 #define __local_inc(l)      ((l)->a.counter++)
0171 #define __local_dec(l)      ((l)->a.counter++)
0172 #define __local_add(i, l)   ((l)->a.counter+=(i))
0173 #define __local_sub(i, l)   ((l)->a.counter-=(i))
0174 
0175 #endif /* _ARCH_MIPS_LOCAL_H */