18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_QSPINLOCK_H
38c2ecf20Sopenharmony_ci#define _ASM_POWERPC_QSPINLOCK_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <asm-generic/qspinlock_types.h>
68c2ecf20Sopenharmony_ci#include <asm/paravirt.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define _Q_PENDING_LOOPS	(1 << 9) /* not tuned */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_SPINLOCKS
118c2ecf20Sopenharmony_ciextern void native_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
128c2ecf20Sopenharmony_ciextern void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
138c2ecf20Sopenharmony_ciextern void __pv_queued_spin_unlock(struct qspinlock *lock);
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic __always_inline void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	if (!is_shared_processor())
188c2ecf20Sopenharmony_ci		native_queued_spin_lock_slowpath(lock, val);
198c2ecf20Sopenharmony_ci	else
208c2ecf20Sopenharmony_ci		__pv_queued_spin_lock_slowpath(lock, val);
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define queued_spin_unlock queued_spin_unlock
248c2ecf20Sopenharmony_cistatic inline void queued_spin_unlock(struct qspinlock *lock)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	if (!is_shared_processor())
278c2ecf20Sopenharmony_ci		smp_store_release(&lock->locked, 0);
288c2ecf20Sopenharmony_ci	else
298c2ecf20Sopenharmony_ci		__pv_queued_spin_unlock(lock);
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#else
338c2ecf20Sopenharmony_ciextern void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
348c2ecf20Sopenharmony_ci#endif
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic __always_inline void queued_spin_lock(struct qspinlock *lock)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	u32 val = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (likely(atomic_try_cmpxchg_lock(&lock->val, &val, _Q_LOCKED_VAL)))
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	queued_spin_lock_slowpath(lock, val);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci#define queued_spin_lock queued_spin_lock
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define smp_mb__after_spinlock()   smp_mb()
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic __always_inline int queued_spin_is_locked(struct qspinlock *lock)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	/*
528c2ecf20Sopenharmony_ci	 * This barrier was added to simple spinlocks by commit 51d7d5205d338,
538c2ecf20Sopenharmony_ci	 * but it should now be possible to remove it, asm arm64 has done with
548c2ecf20Sopenharmony_ci	 * commit c6f5d02b6a0f.
558c2ecf20Sopenharmony_ci	 */
568c2ecf20Sopenharmony_ci	smp_mb();
578c2ecf20Sopenharmony_ci	return atomic_read(&lock->val);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci#define queued_spin_is_locked queued_spin_is_locked
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_SPINLOCKS
628c2ecf20Sopenharmony_ci#define SPIN_THRESHOLD (1<<15) /* not tuned */
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic __always_inline void pv_wait(u8 *ptr, u8 val)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	if (*ptr != val)
678c2ecf20Sopenharmony_ci		return;
688c2ecf20Sopenharmony_ci	yield_to_any();
698c2ecf20Sopenharmony_ci	/*
708c2ecf20Sopenharmony_ci	 * We could pass in a CPU here if waiting in the queue and yield to
718c2ecf20Sopenharmony_ci	 * the previous CPU in the queue.
728c2ecf20Sopenharmony_ci	 */
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic __always_inline void pv_kick(int cpu)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	prod_cpu(cpu);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciextern void __pv_init_lock_hash(void);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic inline void pv_spinlocks_init(void)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	__pv_init_lock_hash();
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#endif
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#include <asm-generic/qspinlock.h>
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#endif /* _ASM_POWERPC_QSPINLOCK_H */
92