Merge tag 'stream_open-5.2' of https://lab.nexedi.com/kirr/linux
[sfrench/cifs-2.6.git] / arch / sh / include / asm / spinlock-llsc.h
1 /* SPDX-License-Identifier: GPL-2.0
2  *
3  * include/asm-sh/spinlock-llsc.h
4  *
5  * Copyright (C) 2002, 2003 Paul Mundt
6  * Copyright (C) 2006, 2007 Akio Idehara
7  */
8 #ifndef __ASM_SH_SPINLOCK_LLSC_H
9 #define __ASM_SH_SPINLOCK_LLSC_H
10
11 #include <asm/barrier.h>
12 #include <asm/processor.h>
13
14 /*
15  * Your basic SMP spinlocks, allowing only a single CPU anywhere
16  */
17
18 #define arch_spin_is_locked(x)          ((x)->lock <= 0)
19
20 /*
21  * Simple spin lock operations.  There are two variants, one clears IRQ's
22  * on the local processor, one does not.
23  *
24  * We make no fairness assumptions.  They have a cost.
25  */
26 static inline void arch_spin_lock(arch_spinlock_t *lock)
27 {
28         unsigned long tmp;
29         unsigned long oldval;
30
31         __asm__ __volatile__ (
32                 "1:                                             \n\t"
33                 "movli.l        @%2, %0 ! arch_spin_lock        \n\t"
34                 "mov            %0, %1                          \n\t"
35                 "mov            #0, %0                          \n\t"
36                 "movco.l        %0, @%2                         \n\t"
37                 "bf             1b                              \n\t"
38                 "cmp/pl         %1                              \n\t"
39                 "bf             1b                              \n\t"
40                 : "=&z" (tmp), "=&r" (oldval)
41                 : "r" (&lock->lock)
42                 : "t", "memory"
43         );
44 }
45
46 static inline void arch_spin_unlock(arch_spinlock_t *lock)
47 {
48         unsigned long tmp;
49
50         /* This could be optimised with ARCH_HAS_MMIOWB */
51         mmiowb();
52         __asm__ __volatile__ (
53                 "mov            #1, %0 ! arch_spin_unlock       \n\t"
54                 "mov.l          %0, @%1                         \n\t"
55                 : "=&z" (tmp)
56                 : "r" (&lock->lock)
57                 : "t", "memory"
58         );
59 }
60
61 static inline int arch_spin_trylock(arch_spinlock_t *lock)
62 {
63         unsigned long tmp, oldval;
64
65         __asm__ __volatile__ (
66                 "1:                                             \n\t"
67                 "movli.l        @%2, %0 ! arch_spin_trylock     \n\t"
68                 "mov            %0, %1                          \n\t"
69                 "mov            #0, %0                          \n\t"
70                 "movco.l        %0, @%2                         \n\t"
71                 "bf             1b                              \n\t"
72                 "synco                                          \n\t"
73                 : "=&z" (tmp), "=&r" (oldval)
74                 : "r" (&lock->lock)
75                 : "t", "memory"
76         );
77
78         return oldval;
79 }
80
81 /*
82  * Read-write spinlocks, allowing multiple readers but only one writer.
83  *
84  * NOTE! it is quite common to have readers in interrupts but no interrupt
85  * writers. For those circumstances we can "mix" irq-safe locks - any writer
86  * needs to get a irq-safe write-lock, but readers can get non-irqsafe
87  * read-locks.
88  */
89
90 static inline void arch_read_lock(arch_rwlock_t *rw)
91 {
92         unsigned long tmp;
93
94         __asm__ __volatile__ (
95                 "1:                                             \n\t"
96                 "movli.l        @%1, %0 ! arch_read_lock        \n\t"
97                 "cmp/pl         %0                              \n\t"
98                 "bf             1b                              \n\t"
99                 "add            #-1, %0                         \n\t"
100                 "movco.l        %0, @%1                         \n\t"
101                 "bf             1b                              \n\t"
102                 : "=&z" (tmp)
103                 : "r" (&rw->lock)
104                 : "t", "memory"
105         );
106 }
107
108 static inline void arch_read_unlock(arch_rwlock_t *rw)
109 {
110         unsigned long tmp;
111
112         __asm__ __volatile__ (
113                 "1:                                             \n\t"
114                 "movli.l        @%1, %0 ! arch_read_unlock      \n\t"
115                 "add            #1, %0                          \n\t"
116                 "movco.l        %0, @%1                         \n\t"
117                 "bf             1b                              \n\t"
118                 : "=&z" (tmp)
119                 : "r" (&rw->lock)
120                 : "t", "memory"
121         );
122 }
123
124 static inline void arch_write_lock(arch_rwlock_t *rw)
125 {
126         unsigned long tmp;
127
128         __asm__ __volatile__ (
129                 "1:                                             \n\t"
130                 "movli.l        @%1, %0 ! arch_write_lock       \n\t"
131                 "cmp/hs         %2, %0                          \n\t"
132                 "bf             1b                              \n\t"
133                 "sub            %2, %0                          \n\t"
134                 "movco.l        %0, @%1                         \n\t"
135                 "bf             1b                              \n\t"
136                 : "=&z" (tmp)
137                 : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
138                 : "t", "memory"
139         );
140 }
141
142 static inline void arch_write_unlock(arch_rwlock_t *rw)
143 {
144         __asm__ __volatile__ (
145                 "mov.l          %1, @%0 ! arch_write_unlock     \n\t"
146                 :
147                 : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
148                 : "t", "memory"
149         );
150 }
151
152 static inline int arch_read_trylock(arch_rwlock_t *rw)
153 {
154         unsigned long tmp, oldval;
155
156         __asm__ __volatile__ (
157                 "1:                                             \n\t"
158                 "movli.l        @%2, %0 ! arch_read_trylock     \n\t"
159                 "mov            %0, %1                          \n\t"
160                 "cmp/pl         %0                              \n\t"
161                 "bf             2f                              \n\t"
162                 "add            #-1, %0                         \n\t"
163                 "movco.l        %0, @%2                         \n\t"
164                 "bf             1b                              \n\t"
165                 "2:                                             \n\t"
166                 "synco                                          \n\t"
167                 : "=&z" (tmp), "=&r" (oldval)
168                 : "r" (&rw->lock)
169                 : "t", "memory"
170         );
171
172         return (oldval > 0);
173 }
174
175 static inline int arch_write_trylock(arch_rwlock_t *rw)
176 {
177         unsigned long tmp, oldval;
178
179         __asm__ __volatile__ (
180                 "1:                                             \n\t"
181                 "movli.l        @%2, %0 ! arch_write_trylock    \n\t"
182                 "mov            %0, %1                          \n\t"
183                 "cmp/hs         %3, %0                          \n\t"
184                 "bf             2f                              \n\t"
185                 "sub            %3, %0                          \n\t"
186                 "2:                                             \n\t"
187                 "movco.l        %0, @%2                         \n\t"
188                 "bf             1b                              \n\t"
189                 "synco                                          \n\t"
190                 : "=&z" (tmp), "=&r" (oldval)
191                 : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
192                 : "t", "memory"
193         );
194
195         return (oldval > (RW_LOCK_BIAS - 1));
196 }
197
198 #endif /* __ASM_SH_SPINLOCK_LLSC_H */