0001
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
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
0103
0104
0105
0106
0107
0108
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
0125
0126
0127
0128
0129
0130
0131
0132 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142 #define local_inc_and_test(l) (local_inc_return(l) == 0)
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 #define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 #define local_add_negative(i, l) (local_add_return(i, (l)) < 0)
0164
0165
0166
0167
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