18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef __ASM_SPINLOCK_H
78c2ecf20Sopenharmony_ci#define __ASM_SPINLOCK_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <asm/spinlock_types.h>
108c2ecf20Sopenharmony_ci#include <asm/processor.h>
118c2ecf20Sopenharmony_ci#include <asm/barrier.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define arch_spin_is_locked(x)	((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#ifdef CONFIG_ARC_HAS_LLSC
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic inline void arch_spin_lock(arch_spinlock_t *lock)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	unsigned int val;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	__asm__ __volatile__(
228c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[slock]]	\n"
238c2ecf20Sopenharmony_ci	"	breq	%[val], %[LOCKED], 1b	\n"	/* spin while LOCKED */
248c2ecf20Sopenharmony_ci	"	scond	%[LOCKED], [%[slock]]	\n"	/* acquire */
258c2ecf20Sopenharmony_ci	"	bnz	1b			\n"
268c2ecf20Sopenharmony_ci	"					\n"
278c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val)
288c2ecf20Sopenharmony_ci	: [slock]	"r"	(&(lock->slock)),
298c2ecf20Sopenharmony_ci	  [LOCKED]	"r"	(__ARCH_SPIN_LOCK_LOCKED__)
308c2ecf20Sopenharmony_ci	: "memory", "cc");
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	/*
338c2ecf20Sopenharmony_ci	 * ACQUIRE barrier to ensure load/store after taking the lock
348c2ecf20Sopenharmony_ci	 * don't "bleed-up" out of the critical section (leak-in is allowed)
358c2ecf20Sopenharmony_ci	 * http://www.spinics.net/lists/kernel/msg2010409.html
368c2ecf20Sopenharmony_ci	 *
378c2ecf20Sopenharmony_ci	 * ARCv2 only has load-load, store-store and all-all barrier
388c2ecf20Sopenharmony_ci	 * thus need the full all-all barrier
398c2ecf20Sopenharmony_ci	 */
408c2ecf20Sopenharmony_ci	smp_mb();
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* 1 - lock taken successfully */
448c2ecf20Sopenharmony_cistatic inline int arch_spin_trylock(arch_spinlock_t *lock)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	unsigned int val, got_it = 0;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	__asm__ __volatile__(
498c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[slock]]	\n"
508c2ecf20Sopenharmony_ci	"	breq	%[val], %[LOCKED], 4f	\n"	/* already LOCKED, just bail */
518c2ecf20Sopenharmony_ci	"	scond	%[LOCKED], [%[slock]]	\n"	/* acquire */
528c2ecf20Sopenharmony_ci	"	bnz	1b			\n"
538c2ecf20Sopenharmony_ci	"	mov	%[got_it], 1		\n"
548c2ecf20Sopenharmony_ci	"4:					\n"
558c2ecf20Sopenharmony_ci	"					\n"
568c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val),
578c2ecf20Sopenharmony_ci	  [got_it]	"+&r"	(got_it)
588c2ecf20Sopenharmony_ci	: [slock]	"r"	(&(lock->slock)),
598c2ecf20Sopenharmony_ci	  [LOCKED]	"r"	(__ARCH_SPIN_LOCK_LOCKED__)
608c2ecf20Sopenharmony_ci	: "memory", "cc");
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	smp_mb();
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return got_it;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic inline void arch_spin_unlock(arch_spinlock_t *lock)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	smp_mb();
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	WRITE_ONCE(lock->slock, __ARCH_SPIN_LOCK_UNLOCKED__);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/*
758c2ecf20Sopenharmony_ci * Read-write spinlocks, allowing multiple readers but only one writer.
768c2ecf20Sopenharmony_ci * Unfair locking as Writers could be starved indefinitely by Reader(s)
778c2ecf20Sopenharmony_ci */
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic inline void arch_read_lock(arch_rwlock_t *rw)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	unsigned int val;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/*
848c2ecf20Sopenharmony_ci	 * zero means writer holds the lock exclusively, deny Reader.
858c2ecf20Sopenharmony_ci	 * Otherwise grant lock to first/subseq reader
868c2ecf20Sopenharmony_ci	 *
878c2ecf20Sopenharmony_ci	 * 	if (rw->counter > 0) {
888c2ecf20Sopenharmony_ci	 *		rw->counter--;
898c2ecf20Sopenharmony_ci	 *		ret = 1;
908c2ecf20Sopenharmony_ci	 *	}
918c2ecf20Sopenharmony_ci	 */
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	__asm__ __volatile__(
948c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[rwlock]]	\n"
958c2ecf20Sopenharmony_ci	"	brls	%[val], %[WR_LOCKED], 1b\n"	/* <= 0: spin while write locked */
968c2ecf20Sopenharmony_ci	"	sub	%[val], %[val], 1	\n"	/* reader lock */
978c2ecf20Sopenharmony_ci	"	scond	%[val], [%[rwlock]]	\n"
988c2ecf20Sopenharmony_ci	"	bnz	1b			\n"
998c2ecf20Sopenharmony_ci	"					\n"
1008c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val)
1018c2ecf20Sopenharmony_ci	: [rwlock]	"r"	(&(rw->counter)),
1028c2ecf20Sopenharmony_ci	  [WR_LOCKED]	"ir"	(0)
1038c2ecf20Sopenharmony_ci	: "memory", "cc");
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	smp_mb();
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/* 1 - lock taken successfully */
1098c2ecf20Sopenharmony_cistatic inline int arch_read_trylock(arch_rwlock_t *rw)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	unsigned int val, got_it = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1148c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[rwlock]]	\n"
1158c2ecf20Sopenharmony_ci	"	brls	%[val], %[WR_LOCKED], 4f\n"	/* <= 0: already write locked, bail */
1168c2ecf20Sopenharmony_ci	"	sub	%[val], %[val], 1	\n"	/* counter-- */
1178c2ecf20Sopenharmony_ci	"	scond	%[val], [%[rwlock]]	\n"
1188c2ecf20Sopenharmony_ci	"	bnz	1b			\n"	/* retry if collided with someone */
1198c2ecf20Sopenharmony_ci	"	mov	%[got_it], 1		\n"
1208c2ecf20Sopenharmony_ci	"					\n"
1218c2ecf20Sopenharmony_ci	"4: ; --- done ---			\n"
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val),
1248c2ecf20Sopenharmony_ci	  [got_it]	"+&r"	(got_it)
1258c2ecf20Sopenharmony_ci	: [rwlock]	"r"	(&(rw->counter)),
1268c2ecf20Sopenharmony_ci	  [WR_LOCKED]	"ir"	(0)
1278c2ecf20Sopenharmony_ci	: "memory", "cc");
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	smp_mb();
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return got_it;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic inline void arch_write_lock(arch_rwlock_t *rw)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	unsigned int val;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/*
1398c2ecf20Sopenharmony_ci	 * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
1408c2ecf20Sopenharmony_ci	 * deny writer. Otherwise if unlocked grant to writer
1418c2ecf20Sopenharmony_ci	 * Hence the claim that Linux rwlocks are unfair to writers.
1428c2ecf20Sopenharmony_ci	 * (can be starved for an indefinite time by readers).
1438c2ecf20Sopenharmony_ci	 *
1448c2ecf20Sopenharmony_ci	 *	if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
1458c2ecf20Sopenharmony_ci	 *		rw->counter = 0;
1468c2ecf20Sopenharmony_ci	 *		ret = 1;
1478c2ecf20Sopenharmony_ci	 *	}
1488c2ecf20Sopenharmony_ci	 */
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1518c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[rwlock]]	\n"
1528c2ecf20Sopenharmony_ci	"	brne	%[val], %[UNLOCKED], 1b	\n"	/* while !UNLOCKED spin */
1538c2ecf20Sopenharmony_ci	"	mov	%[val], %[WR_LOCKED]	\n"
1548c2ecf20Sopenharmony_ci	"	scond	%[val], [%[rwlock]]	\n"
1558c2ecf20Sopenharmony_ci	"	bnz	1b			\n"
1568c2ecf20Sopenharmony_ci	"					\n"
1578c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val)
1588c2ecf20Sopenharmony_ci	: [rwlock]	"r"	(&(rw->counter)),
1598c2ecf20Sopenharmony_ci	  [UNLOCKED]	"ir"	(__ARCH_RW_LOCK_UNLOCKED__),
1608c2ecf20Sopenharmony_ci	  [WR_LOCKED]	"ir"	(0)
1618c2ecf20Sopenharmony_ci	: "memory", "cc");
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	smp_mb();
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/* 1 - lock taken successfully */
1678c2ecf20Sopenharmony_cistatic inline int arch_write_trylock(arch_rwlock_t *rw)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	unsigned int val, got_it = 0;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1728c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[rwlock]]	\n"
1738c2ecf20Sopenharmony_ci	"	brne	%[val], %[UNLOCKED], 4f	\n"	/* !UNLOCKED, bail */
1748c2ecf20Sopenharmony_ci	"	mov	%[val], %[WR_LOCKED]	\n"
1758c2ecf20Sopenharmony_ci	"	scond	%[val], [%[rwlock]]	\n"
1768c2ecf20Sopenharmony_ci	"	bnz	1b			\n"	/* retry if collided with someone */
1778c2ecf20Sopenharmony_ci	"	mov	%[got_it], 1		\n"
1788c2ecf20Sopenharmony_ci	"					\n"
1798c2ecf20Sopenharmony_ci	"4: ; --- done ---			\n"
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val),
1828c2ecf20Sopenharmony_ci	  [got_it]	"+&r"	(got_it)
1838c2ecf20Sopenharmony_ci	: [rwlock]	"r"	(&(rw->counter)),
1848c2ecf20Sopenharmony_ci	  [UNLOCKED]	"ir"	(__ARCH_RW_LOCK_UNLOCKED__),
1858c2ecf20Sopenharmony_ci	  [WR_LOCKED]	"ir"	(0)
1868c2ecf20Sopenharmony_ci	: "memory", "cc");
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	smp_mb();
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	return got_it;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic inline void arch_read_unlock(arch_rwlock_t *rw)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	unsigned int val;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	smp_mb();
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/*
2008c2ecf20Sopenharmony_ci	 * rw->counter++;
2018c2ecf20Sopenharmony_ci	 */
2028c2ecf20Sopenharmony_ci	__asm__ __volatile__(
2038c2ecf20Sopenharmony_ci	"1:	llock	%[val], [%[rwlock]]	\n"
2048c2ecf20Sopenharmony_ci	"	add	%[val], %[val], 1	\n"
2058c2ecf20Sopenharmony_ci	"	scond	%[val], [%[rwlock]]	\n"
2068c2ecf20Sopenharmony_ci	"	bnz	1b			\n"
2078c2ecf20Sopenharmony_ci	"					\n"
2088c2ecf20Sopenharmony_ci	: [val]		"=&r"	(val)
2098c2ecf20Sopenharmony_ci	: [rwlock]	"r"	(&(rw->counter))
2108c2ecf20Sopenharmony_ci	: "memory", "cc");
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic inline void arch_write_unlock(arch_rwlock_t *rw)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	smp_mb();
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	WRITE_ONCE(rw->counter, __ARCH_RW_LOCK_UNLOCKED__);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#else	/* !CONFIG_ARC_HAS_LLSC */
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic inline void arch_spin_lock(arch_spinlock_t *lock)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/*
2278c2ecf20Sopenharmony_ci	 * Per lkmm, smp_mb() is only required after _lock (and before_unlock)
2288c2ecf20Sopenharmony_ci	 * for ACQ and REL semantics respectively. However EX based spinlocks
2298c2ecf20Sopenharmony_ci	 * need the extra smp_mb to workaround a hardware quirk.
2308c2ecf20Sopenharmony_ci	 */
2318c2ecf20Sopenharmony_ci	smp_mb();
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	__asm__ __volatile__(
2348c2ecf20Sopenharmony_ci	"1:	ex  %0, [%1]		\n"
2358c2ecf20Sopenharmony_ci	"	breq  %0, %2, 1b	\n"
2368c2ecf20Sopenharmony_ci	: "+&r" (val)
2378c2ecf20Sopenharmony_ci	: "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
2388c2ecf20Sopenharmony_ci	: "memory");
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	smp_mb();
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/* 1 - lock taken successfully */
2448c2ecf20Sopenharmony_cistatic inline int arch_spin_trylock(arch_spinlock_t *lock)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	smp_mb();
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	__asm__ __volatile__(
2518c2ecf20Sopenharmony_ci	"1:	ex  %0, [%1]		\n"
2528c2ecf20Sopenharmony_ci	: "+r" (val)
2538c2ecf20Sopenharmony_ci	: "r"(&(lock->slock))
2548c2ecf20Sopenharmony_ci	: "memory");
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	smp_mb();
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return (val == __ARCH_SPIN_LOCK_UNLOCKED__);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic inline void arch_spin_unlock(arch_spinlock_t *lock)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/*
2668c2ecf20Sopenharmony_ci	 * RELEASE barrier: given the instructions avail on ARCv2, full barrier
2678c2ecf20Sopenharmony_ci	 * is the only option
2688c2ecf20Sopenharmony_ci	 */
2698c2ecf20Sopenharmony_ci	smp_mb();
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/*
2728c2ecf20Sopenharmony_ci	 * EX is not really required here, a simple STore of 0 suffices.
2738c2ecf20Sopenharmony_ci	 * However this causes tasklist livelocks in SystemC based SMP virtual
2748c2ecf20Sopenharmony_ci	 * platforms where the systemc core scheduler uses EX as a cue for
2758c2ecf20Sopenharmony_ci	 * moving to next core. Do a git log of this file for details
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	__asm__ __volatile__(
2788c2ecf20Sopenharmony_ci	"	ex  %0, [%1]		\n"
2798c2ecf20Sopenharmony_ci	: "+r" (val)
2808c2ecf20Sopenharmony_ci	: "r"(&(lock->slock))
2818c2ecf20Sopenharmony_ci	: "memory");
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/*
2848c2ecf20Sopenharmony_ci	 * see pairing version/comment in arch_spin_lock above
2858c2ecf20Sopenharmony_ci	 */
2868c2ecf20Sopenharmony_ci	smp_mb();
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/*
2908c2ecf20Sopenharmony_ci * Read-write spinlocks, allowing multiple readers but only one writer.
2918c2ecf20Sopenharmony_ci * Unfair locking as Writers could be starved indefinitely by Reader(s)
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci * The spinlock itself is contained in @counter and access to it is
2948c2ecf20Sopenharmony_ci * serialized with @lock_mutex.
2958c2ecf20Sopenharmony_ci */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/* 1 - lock taken successfully */
2988c2ecf20Sopenharmony_cistatic inline int arch_read_trylock(arch_rwlock_t *rw)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	int ret = 0;
3018c2ecf20Sopenharmony_ci	unsigned long flags;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	local_irq_save(flags);
3048c2ecf20Sopenharmony_ci	arch_spin_lock(&(rw->lock_mutex));
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/*
3078c2ecf20Sopenharmony_ci	 * zero means writer holds the lock exclusively, deny Reader.
3088c2ecf20Sopenharmony_ci	 * Otherwise grant lock to first/subseq reader
3098c2ecf20Sopenharmony_ci	 */
3108c2ecf20Sopenharmony_ci	if (rw->counter > 0) {
3118c2ecf20Sopenharmony_ci		rw->counter--;
3128c2ecf20Sopenharmony_ci		ret = 1;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	arch_spin_unlock(&(rw->lock_mutex));
3168c2ecf20Sopenharmony_ci	local_irq_restore(flags);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return ret;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/* 1 - lock taken successfully */
3228c2ecf20Sopenharmony_cistatic inline int arch_write_trylock(arch_rwlock_t *rw)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	int ret = 0;
3258c2ecf20Sopenharmony_ci	unsigned long flags;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	local_irq_save(flags);
3288c2ecf20Sopenharmony_ci	arch_spin_lock(&(rw->lock_mutex));
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/*
3318c2ecf20Sopenharmony_ci	 * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
3328c2ecf20Sopenharmony_ci	 * deny writer. Otherwise if unlocked grant to writer
3338c2ecf20Sopenharmony_ci	 * Hence the claim that Linux rwlocks are unfair to writers.
3348c2ecf20Sopenharmony_ci	 * (can be starved for an indefinite time by readers).
3358c2ecf20Sopenharmony_ci	 */
3368c2ecf20Sopenharmony_ci	if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
3378c2ecf20Sopenharmony_ci		rw->counter = 0;
3388c2ecf20Sopenharmony_ci		ret = 1;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci	arch_spin_unlock(&(rw->lock_mutex));
3418c2ecf20Sopenharmony_ci	local_irq_restore(flags);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return ret;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic inline void arch_read_lock(arch_rwlock_t *rw)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	while (!arch_read_trylock(rw))
3498c2ecf20Sopenharmony_ci		cpu_relax();
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic inline void arch_write_lock(arch_rwlock_t *rw)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	while (!arch_write_trylock(rw))
3558c2ecf20Sopenharmony_ci		cpu_relax();
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic inline void arch_read_unlock(arch_rwlock_t *rw)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	unsigned long flags;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	local_irq_save(flags);
3638c2ecf20Sopenharmony_ci	arch_spin_lock(&(rw->lock_mutex));
3648c2ecf20Sopenharmony_ci	rw->counter++;
3658c2ecf20Sopenharmony_ci	arch_spin_unlock(&(rw->lock_mutex));
3668c2ecf20Sopenharmony_ci	local_irq_restore(flags);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic inline void arch_write_unlock(arch_rwlock_t *rw)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	unsigned long flags;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	local_irq_save(flags);
3748c2ecf20Sopenharmony_ci	arch_spin_lock(&(rw->lock_mutex));
3758c2ecf20Sopenharmony_ci	rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
3768c2ecf20Sopenharmony_ci	arch_spin_unlock(&(rw->lock_mutex));
3778c2ecf20Sopenharmony_ci	local_irq_restore(flags);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci#endif
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci#endif /* __ASM_SPINLOCK_H */
383