18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * include/asm-sh/spinlock-cas.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 SEI
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#ifndef __ASM_SH_SPINLOCK_CAS_H
88c2ecf20Sopenharmony_ci#define __ASM_SH_SPINLOCK_CAS_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/barrier.h>
118c2ecf20Sopenharmony_ci#include <asm/processor.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	__asm__ __volatile__("cas.l %1,%0,@r0"
168c2ecf20Sopenharmony_ci		: "+r"(new)
178c2ecf20Sopenharmony_ci		: "r"(old), "z"(p)
188c2ecf20Sopenharmony_ci		: "t", "memory" );
198c2ecf20Sopenharmony_ci	return new;
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * Your basic SMP spinlocks, allowing only a single CPU anywhere
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define arch_spin_is_locked(x)		((x)->lock <= 0)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic inline void arch_spin_lock(arch_spinlock_t *lock)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	while (!__sl_cas(&lock->lock, 1, 0));
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic inline void arch_spin_unlock(arch_spinlock_t *lock)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	__sl_cas(&lock->lock, 0, 1);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic inline int arch_spin_trylock(arch_spinlock_t *lock)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return __sl_cas(&lock->lock, 1, 0);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * Read-write spinlocks, allowing multiple readers but only one writer.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * NOTE! it is quite common to have readers in interrupts but no interrupt
478c2ecf20Sopenharmony_ci * writers. For those circumstances we can "mix" irq-safe locks - any writer
488c2ecf20Sopenharmony_ci * needs to get a irq-safe write-lock, but readers can get non-irqsafe
498c2ecf20Sopenharmony_ci * read-locks.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline void arch_read_lock(arch_rwlock_t *rw)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	unsigned old;
558c2ecf20Sopenharmony_ci	do old = rw->lock;
568c2ecf20Sopenharmony_ci	while (!old || __sl_cas(&rw->lock, old, old-1) != old);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline void arch_read_unlock(arch_rwlock_t *rw)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned old;
628c2ecf20Sopenharmony_ci	do old = rw->lock;
638c2ecf20Sopenharmony_ci	while (__sl_cas(&rw->lock, old, old+1) != old);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic inline void arch_write_lock(arch_rwlock_t *rw)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	while (__sl_cas(&rw->lock, RW_LOCK_BIAS, 0) != RW_LOCK_BIAS);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic inline void arch_write_unlock(arch_rwlock_t *rw)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	__sl_cas(&rw->lock, 0, RW_LOCK_BIAS);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic inline int arch_read_trylock(arch_rwlock_t *rw)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	unsigned old;
798c2ecf20Sopenharmony_ci	do old = rw->lock;
808c2ecf20Sopenharmony_ci	while (old && __sl_cas(&rw->lock, old, old-1) != old);
818c2ecf20Sopenharmony_ci	return !!old;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic inline int arch_write_trylock(arch_rwlock_t *rw)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#endif /* __ASM_SH_SPINLOCK_CAS_H */
90