Merge tag 'for-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power...
[sfrench/cifs-2.6.git] / arch / alpha / include / asm / rwsem.h
1 #ifndef _ALPHA_RWSEM_H
2 #define _ALPHA_RWSEM_H
3
4 /*
5  * Written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
6  * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
7  */
8
9 #ifndef _LINUX_RWSEM_H
10 #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
11 #endif
12
13 #ifdef __KERNEL__
14
15 #include <linux/compiler.h>
16
17 #define RWSEM_UNLOCKED_VALUE            0x0000000000000000L
18 #define RWSEM_ACTIVE_BIAS               0x0000000000000001L
19 #define RWSEM_ACTIVE_MASK               0x00000000ffffffffL
20 #define RWSEM_WAITING_BIAS              (-0x0000000100000000L)
21 #define RWSEM_ACTIVE_READ_BIAS          RWSEM_ACTIVE_BIAS
22 #define RWSEM_ACTIVE_WRITE_BIAS         (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
23
24 static inline void __down_read(struct rw_semaphore *sem)
25 {
26         long oldcount;
27 #ifndef CONFIG_SMP
28         oldcount = sem->count.counter;
29         sem->count.counter += RWSEM_ACTIVE_READ_BIAS;
30 #else
31         long temp;
32         __asm__ __volatile__(
33         "1:     ldq_l   %0,%1\n"
34         "       addq    %0,%3,%2\n"
35         "       stq_c   %2,%1\n"
36         "       beq     %2,2f\n"
37         "       mb\n"
38         ".subsection 2\n"
39         "2:     br      1b\n"
40         ".previous"
41         :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
42         :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
43 #endif
44         if (unlikely(oldcount < 0))
45                 rwsem_down_read_failed(sem);
46 }
47
48 /*
49  * trylock for reading -- returns 1 if successful, 0 if contention
50  */
51 static inline int __down_read_trylock(struct rw_semaphore *sem)
52 {
53         long old, new, res;
54
55         res = atomic_long_read(&sem->count);
56         do {
57                 new = res + RWSEM_ACTIVE_READ_BIAS;
58                 if (new <= 0)
59                         break;
60                 old = res;
61                 res = atomic_long_cmpxchg(&sem->count, old, new);
62         } while (res != old);
63         return res >= 0 ? 1 : 0;
64 }
65
66 static inline long ___down_write(struct rw_semaphore *sem)
67 {
68         long oldcount;
69 #ifndef CONFIG_SMP
70         oldcount = sem->count.counter;
71         sem->count.counter += RWSEM_ACTIVE_WRITE_BIAS;
72 #else
73         long temp;
74         __asm__ __volatile__(
75         "1:     ldq_l   %0,%1\n"
76         "       addq    %0,%3,%2\n"
77         "       stq_c   %2,%1\n"
78         "       beq     %2,2f\n"
79         "       mb\n"
80         ".subsection 2\n"
81         "2:     br      1b\n"
82         ".previous"
83         :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
84         :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
85 #endif
86         return oldcount;
87 }
88
89 static inline void __down_write(struct rw_semaphore *sem)
90 {
91         if (unlikely(___down_write(sem)))
92                 rwsem_down_write_failed(sem);
93 }
94
95 static inline int __down_write_killable(struct rw_semaphore *sem)
96 {
97         if (unlikely(___down_write(sem)))
98                 if (IS_ERR(rwsem_down_write_failed_killable(sem)))
99                         return -EINTR;
100
101         return 0;
102 }
103
104 /*
105  * trylock for writing -- returns 1 if successful, 0 if contention
106  */
107 static inline int __down_write_trylock(struct rw_semaphore *sem)
108 {
109         long ret = atomic_long_cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
110                            RWSEM_ACTIVE_WRITE_BIAS);
111         if (ret == RWSEM_UNLOCKED_VALUE)
112                 return 1;
113         return 0;
114 }
115
116 static inline void __up_read(struct rw_semaphore *sem)
117 {
118         long oldcount;
119 #ifndef CONFIG_SMP
120         oldcount = sem->count.counter;
121         sem->count.counter -= RWSEM_ACTIVE_READ_BIAS;
122 #else
123         long temp;
124         __asm__ __volatile__(
125         "       mb\n"
126         "1:     ldq_l   %0,%1\n"
127         "       subq    %0,%3,%2\n"
128         "       stq_c   %2,%1\n"
129         "       beq     %2,2f\n"
130         ".subsection 2\n"
131         "2:     br      1b\n"
132         ".previous"
133         :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
134         :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
135 #endif
136         if (unlikely(oldcount < 0))
137                 if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
138                         rwsem_wake(sem);
139 }
140
141 static inline void __up_write(struct rw_semaphore *sem)
142 {
143         long count;
144 #ifndef CONFIG_SMP
145         sem->count.counter -= RWSEM_ACTIVE_WRITE_BIAS;
146         count = sem->count.counter;
147 #else
148         long temp;
149         __asm__ __volatile__(
150         "       mb\n"
151         "1:     ldq_l   %0,%1\n"
152         "       subq    %0,%3,%2\n"
153         "       stq_c   %2,%1\n"
154         "       beq     %2,2f\n"
155         "       subq    %0,%3,%0\n"
156         ".subsection 2\n"
157         "2:     br      1b\n"
158         ".previous"
159         :"=&r" (count), "=m" (sem->count), "=&r" (temp)
160         :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
161 #endif
162         if (unlikely(count))
163                 if ((int)count == 0)
164                         rwsem_wake(sem);
165 }
166
167 /*
168  * downgrade write lock to read lock
169  */
170 static inline void __downgrade_write(struct rw_semaphore *sem)
171 {
172         long oldcount;
173 #ifndef CONFIG_SMP
174         oldcount = sem->count.counter;
175         sem->count.counter -= RWSEM_WAITING_BIAS;
176 #else
177         long temp;
178         __asm__ __volatile__(
179         "1:     ldq_l   %0,%1\n"
180         "       addq    %0,%3,%2\n"
181         "       stq_c   %2,%1\n"
182         "       beq     %2,2f\n"
183         "       mb\n"
184         ".subsection 2\n"
185         "2:     br      1b\n"
186         ".previous"
187         :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
188         :"Ir" (-RWSEM_WAITING_BIAS), "m" (sem->count) : "memory");
189 #endif
190         if (unlikely(oldcount < 0))
191                 rwsem_downgrade_wake(sem);
192 }
193
194 #endif /* __KERNEL__ */
195 #endif /* _ALPHA_RWSEM_H */