GNU Linux-libre 6.1.90-gnu
[releases.git] / arch / parisc / include / asm / spinlock.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __ASM_SPINLOCK_H
3 #define __ASM_SPINLOCK_H
4
5 #include <asm/barrier.h>
6 #include <asm/ldcw.h>
7 #include <asm/processor.h>
8 #include <asm/spinlock_types.h>
9
10 static inline int arch_spin_is_locked(arch_spinlock_t *x)
11 {
12         volatile unsigned int *a = __ldcw_align(x);
13         return READ_ONCE(*a) == 0;
14 }
15
16 static inline void arch_spin_lock(arch_spinlock_t *x)
17 {
18         volatile unsigned int *a;
19
20         a = __ldcw_align(x);
21         while (__ldcw(a) == 0)
22                 while (*a == 0)
23                         continue;
24 }
25
26 static inline void arch_spin_unlock(arch_spinlock_t *x)
27 {
28         volatile unsigned int *a;
29
30         a = __ldcw_align(x);
31         /* Release with ordered store. */
32         __asm__ __volatile__("stw,ma %0,0(%1)" : : "r"(1), "r"(a) : "memory");
33 }
34
35 static inline int arch_spin_trylock(arch_spinlock_t *x)
36 {
37         volatile unsigned int *a;
38
39         a = __ldcw_align(x);
40         return __ldcw(a) != 0;
41 }
42
43 /*
44  * Read-write spinlocks, allowing multiple readers but only one writer.
45  * Unfair locking as Writers could be starved indefinitely by Reader(s)
46  *
47  * The spinlock itself is contained in @counter and access to it is
48  * serialized with @lock_mutex.
49  */
50
51 /* 1 - lock taken successfully */
52 static inline int arch_read_trylock(arch_rwlock_t *rw)
53 {
54         int ret = 0;
55         unsigned long flags;
56
57         local_irq_save(flags);
58         arch_spin_lock(&(rw->lock_mutex));
59
60         /*
61          * zero means writer holds the lock exclusively, deny Reader.
62          * Otherwise grant lock to first/subseq reader
63          */
64         if (rw->counter > 0) {
65                 rw->counter--;
66                 ret = 1;
67         }
68
69         arch_spin_unlock(&(rw->lock_mutex));
70         local_irq_restore(flags);
71
72         return ret;
73 }
74
75 /* 1 - lock taken successfully */
76 static inline int arch_write_trylock(arch_rwlock_t *rw)
77 {
78         int ret = 0;
79         unsigned long flags;
80
81         local_irq_save(flags);
82         arch_spin_lock(&(rw->lock_mutex));
83
84         /*
85          * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
86          * deny writer. Otherwise if unlocked grant to writer
87          * Hence the claim that Linux rwlocks are unfair to writers.
88          * (can be starved for an indefinite time by readers).
89          */
90         if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
91                 rw->counter = 0;
92                 ret = 1;
93         }
94         arch_spin_unlock(&(rw->lock_mutex));
95         local_irq_restore(flags);
96
97         return ret;
98 }
99
100 static inline void arch_read_lock(arch_rwlock_t *rw)
101 {
102         while (!arch_read_trylock(rw))
103                 cpu_relax();
104 }
105
106 static inline void arch_write_lock(arch_rwlock_t *rw)
107 {
108         while (!arch_write_trylock(rw))
109                 cpu_relax();
110 }
111
112 static inline void arch_read_unlock(arch_rwlock_t *rw)
113 {
114         unsigned long flags;
115
116         local_irq_save(flags);
117         arch_spin_lock(&(rw->lock_mutex));
118         rw->counter++;
119         arch_spin_unlock(&(rw->lock_mutex));
120         local_irq_restore(flags);
121 }
122
123 static inline void arch_write_unlock(arch_rwlock_t *rw)
124 {
125         unsigned long flags;
126
127         local_irq_save(flags);
128         arch_spin_lock(&(rw->lock_mutex));
129         rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
130         arch_spin_unlock(&(rw->lock_mutex));
131         local_irq_restore(flags);
132 }
133
134 #endif /* __ASM_SPINLOCK_H */