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
arch_spin_unlock(arch_spinlock_t * lock)22 static inline void arch_spin_unlock(arch_spinlock_t *lock)
23 {
24 smp_store_release(&lock->lock, 0);
25 }
26
arch_spin_trylock(arch_spinlock_t * lock)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
arch_spin_lock(arch_spinlock_t * lock)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
arch_read_lock(arch_rwlock_t * lock)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
arch_write_lock(arch_rwlock_t * lock)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
arch_read_trylock(arch_rwlock_t * lock)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
arch_write_trylock(arch_rwlock_t * lock)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
arch_read_unlock(arch_rwlock_t * lock)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
arch_write_unlock(arch_rwlock_t * lock)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 */
136