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