1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ALPHA_SPINLOCK_H
3#define _ALPHA_SPINLOCK_H
4
5#include <linux/kernel.h>
6#include <asm/current.h>
7#include <asm/barrier.h>
8#include <asm/processor.h>
9
10/*
11 * Simple spin lock operations.  There are two variants, one clears IRQ's
12 * on the local processor, one does not.
13 *
14 * We make no fairness assumptions. They have a cost.
15 */
16
17#define arch_spin_is_locked(x)	((x)->lock != 0)
18
19static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
20{
21        return lock.lock == 0;
22}
23
24static inline void arch_spin_unlock(arch_spinlock_t * lock)
25{
26	mb();
27	lock->lock = 0;
28}
29
30static inline void arch_spin_lock(arch_spinlock_t * lock)
31{
32	long tmp;
33
34	__asm__ __volatile__(
35	"1:	ldl_l	%0,%1\n"
36	"	bne	%0,2f\n"
37	"	lda	%0,1\n"
38	"	stl_c	%0,%1\n"
39	"	beq	%0,2f\n"
40	"	mb\n"
41	".subsection 2\n"
42	"2:	ldl	%0,%1\n"
43	"	bne	%0,2b\n"
44	"	br	1b\n"
45	".previous"
46	: "=&r" (tmp), "=m" (lock->lock)
47	: "m"(lock->lock) : "memory");
48}
49
50static inline int arch_spin_trylock(arch_spinlock_t *lock)
51{
52	return !test_and_set_bit(0, &lock->lock);
53}
54
55/***********************************************************/
56
57static inline void arch_read_lock(arch_rwlock_t *lock)
58{
59	long regx;
60
61	__asm__ __volatile__(
62	"1:	ldl_l	%1,%0\n"
63	"	blbs	%1,6f\n"
64	"	subl	%1,2,%1\n"
65	"	stl_c	%1,%0\n"
66	"	beq	%1,6f\n"
67	"	mb\n"
68	".subsection 2\n"
69	"6:	ldl	%1,%0\n"
70	"	blbs	%1,6b\n"
71	"	br	1b\n"
72	".previous"
73	: "=m" (*lock), "=&r" (regx)
74	: "m" (*lock) : "memory");
75}
76
77static inline void arch_write_lock(arch_rwlock_t *lock)
78{
79	long regx;
80
81	__asm__ __volatile__(
82	"1:	ldl_l	%1,%0\n"
83	"	bne	%1,6f\n"
84	"	lda	%1,1\n"
85	"	stl_c	%1,%0\n"
86	"	beq	%1,6f\n"
87	"	mb\n"
88	".subsection 2\n"
89	"6:	ldl	%1,%0\n"
90	"	bne	%1,6b\n"
91	"	br	1b\n"
92	".previous"
93	: "=m" (*lock), "=&r" (regx)
94	: "m" (*lock) : "memory");
95}
96
97static inline int arch_read_trylock(arch_rwlock_t * lock)
98{
99	long regx;
100	int success;
101
102	__asm__ __volatile__(
103	"1:	ldl_l	%1,%0\n"
104	"	lda	%2,0\n"
105	"	blbs	%1,2f\n"
106	"	subl	%1,2,%2\n"
107	"	stl_c	%2,%0\n"
108	"	beq	%2,6f\n"
109	"2:	mb\n"
110	".subsection 2\n"
111	"6:	br	1b\n"
112	".previous"
113	: "=m" (*lock), "=&r" (regx), "=&r" (success)
114	: "m" (*lock) : "memory");
115
116	return success;
117}
118
119static inline int arch_write_trylock(arch_rwlock_t * lock)
120{
121	long regx;
122	int success;
123
124	__asm__ __volatile__(
125	"1:	ldl_l	%1,%0\n"
126	"	lda	%2,0\n"
127	"	bne	%1,2f\n"
128	"	lda	%2,1\n"
129	"	stl_c	%2,%0\n"
130	"	beq	%2,6f\n"
131	"2:	mb\n"
132	".subsection 2\n"
133	"6:	br	1b\n"
134	".previous"
135	: "=m" (*lock), "=&r" (regx), "=&r" (success)
136	: "m" (*lock) : "memory");
137
138	return success;
139}
140
141static inline void arch_read_unlock(arch_rwlock_t * lock)
142{
143	long regx;
144	__asm__ __volatile__(
145	"	mb\n"
146	"1:	ldl_l	%1,%0\n"
147	"	addl	%1,2,%1\n"
148	"	stl_c	%1,%0\n"
149	"	beq	%1,6f\n"
150	".subsection 2\n"
151	"6:	br	1b\n"
152	".previous"
153	: "=m" (*lock), "=&r" (regx)
154	: "m" (*lock) : "memory");
155}
156
157static inline void arch_write_unlock(arch_rwlock_t * lock)
158{
159	mb();
160	lock->lock = 0;
161}
162
163#endif /* _ALPHA_SPINLOCK_H */
164