Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / riscv / include / asm / spinlock.h
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2015 Regents of the University of California
4  * Copyright (C) 2017 SiFive
5  */
6
7 #ifndef _ASM_RISCV_SPINLOCK_H
8 #define _ASM_RISCV_SPINLOCK_H
9
10 #include <linux/kernel.h>
11 #include <asm/current.h>
12 #include <asm/fence.h>
13
14 /*
15  * Simple spin lock operations.  These provide no fairness guarantees.
16  */
17
18 /* FIXME: Replace this with a ticket lock, like MIPS. */
19
20 #define arch_spin_is_locked(x)  (READ_ONCE((x)->lock) != 0)
21
22 static inline void arch_spin_unlock(arch_spinlock_t *lock)
23 {
24         smp_store_release(&lock->lock, 0);
25 }
26
27 static inline int arch_spin_trylock(arch_spinlock_t *lock)
28 {
29         int tmp = 1, busy;
30
31         __asm__ __volatile__ (
32                 "       amoswap.w %0, %2, %1\n"
33                 RISCV_ACQUIRE_BARRIER
34                 : "=r" (busy), "+A" (lock->lock)
35                 : "r" (tmp)
36                 : "memory");
37
38         return !busy;
39 }
40
41 static inline void arch_spin_lock(arch_spinlock_t *lock)
42 {
43         while (1) {
44                 if (arch_spin_is_locked(lock))
45                         continue;
46
47                 if (arch_spin_trylock(lock))
48                         break;
49         }
50 }
51
52 /***********************************************************/
53
54 static inline void arch_read_lock(arch_rwlock_t *lock)
55 {
56         int tmp;
57
58         __asm__ __volatile__(
59                 "1:     lr.w    %1, %0\n"
60                 "       bltz    %1, 1b\n"
61                 "       addi    %1, %1, 1\n"
62                 "       sc.w    %1, %1, %0\n"
63                 "       bnez    %1, 1b\n"
64                 RISCV_ACQUIRE_BARRIER
65                 : "+A" (lock->lock), "=&r" (tmp)
66                 :: "memory");
67 }
68
69 static inline void arch_write_lock(arch_rwlock_t *lock)
70 {
71         int tmp;
72
73         __asm__ __volatile__(
74                 "1:     lr.w    %1, %0\n"
75                 "       bnez    %1, 1b\n"
76                 "       li      %1, -1\n"
77                 "       sc.w    %1, %1, %0\n"
78                 "       bnez    %1, 1b\n"
79                 RISCV_ACQUIRE_BARRIER
80                 : "+A" (lock->lock), "=&r" (tmp)
81                 :: "memory");
82 }
83
84 static inline int arch_read_trylock(arch_rwlock_t *lock)
85 {
86         int busy;
87
88         __asm__ __volatile__(
89                 "1:     lr.w    %1, %0\n"
90                 "       bltz    %1, 1f\n"
91                 "       addi    %1, %1, 1\n"
92                 "       sc.w    %1, %1, %0\n"
93                 "       bnez    %1, 1b\n"
94                 RISCV_ACQUIRE_BARRIER
95                 "1:\n"
96                 : "+A" (lock->lock), "=&r" (busy)
97                 :: "memory");
98
99         return !busy;
100 }
101
102 static inline int arch_write_trylock(arch_rwlock_t *lock)
103 {
104         int busy;
105
106         __asm__ __volatile__(
107                 "1:     lr.w    %1, %0\n"
108                 "       bnez    %1, 1f\n"
109                 "       li      %1, -1\n"
110                 "       sc.w    %1, %1, %0\n"
111                 "       bnez    %1, 1b\n"
112                 RISCV_ACQUIRE_BARRIER
113                 "1:\n"
114                 : "+A" (lock->lock), "=&r" (busy)
115                 :: "memory");
116
117         return !busy;
118 }
119
120 static inline void arch_read_unlock(arch_rwlock_t *lock)
121 {
122         __asm__ __volatile__(
123                 RISCV_RELEASE_BARRIER
124                 "       amoadd.w x0, %1, %0\n"
125                 : "+A" (lock->lock)
126                 : "r" (-1)
127                 : "memory");
128 }
129
130 static inline void arch_write_unlock(arch_rwlock_t *lock)
131 {
132         smp_store_release(&lock->lock, 0);
133 }
134
135 #endif /* _ASM_RISCV_SPINLOCK_H */