18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Queue read/write lock 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Waiman Long <waiman.long@hp.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#ifndef __ASM_GENERIC_QRWLOCK_H 108c2ecf20Sopenharmony_ci#define __ASM_GENERIC_QRWLOCK_H 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/atomic.h> 138c2ecf20Sopenharmony_ci#include <asm/barrier.h> 148c2ecf20Sopenharmony_ci#include <asm/processor.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm-generic/qrwlock_types.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* 198c2ecf20Sopenharmony_ci * Writer states & reader shift and bias. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci#define _QW_WAITING 0x100 /* A writer is waiting */ 228c2ecf20Sopenharmony_ci#define _QW_LOCKED 0x0ff /* A writer holds the lock */ 238c2ecf20Sopenharmony_ci#define _QW_WMASK 0x1ff /* Writer mask */ 248c2ecf20Sopenharmony_ci#define _QR_SHIFT 9 /* Reader count shift */ 258c2ecf20Sopenharmony_ci#define _QR_BIAS (1U << _QR_SHIFT) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * External function declarations 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ciextern void queued_read_lock_slowpath(struct qrwlock *lock); 318c2ecf20Sopenharmony_ciextern void queued_write_lock_slowpath(struct qrwlock *lock); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/** 348c2ecf20Sopenharmony_ci * queued_read_trylock - try to acquire read lock of a queue rwlock 358c2ecf20Sopenharmony_ci * @lock : Pointer to queue rwlock structure 368c2ecf20Sopenharmony_ci * Return: 1 if lock acquired, 0 if failed 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistatic inline int queued_read_trylock(struct qrwlock *lock) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci u32 cnts; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci cnts = atomic_read(&lock->cnts); 438c2ecf20Sopenharmony_ci if (likely(!(cnts & _QW_WMASK))) { 448c2ecf20Sopenharmony_ci cnts = (u32)atomic_add_return_acquire(_QR_BIAS, &lock->cnts); 458c2ecf20Sopenharmony_ci if (likely(!(cnts & _QW_WMASK))) 468c2ecf20Sopenharmony_ci return 1; 478c2ecf20Sopenharmony_ci atomic_sub(_QR_BIAS, &lock->cnts); 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * queued_write_trylock - try to acquire write lock of a queue rwlock 548c2ecf20Sopenharmony_ci * @lock : Pointer to queue rwlock structure 558c2ecf20Sopenharmony_ci * Return: 1 if lock acquired, 0 if failed 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic inline int queued_write_trylock(struct qrwlock *lock) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci u32 cnts; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci cnts = atomic_read(&lock->cnts); 628c2ecf20Sopenharmony_ci if (unlikely(cnts)) 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return likely(atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, 668c2ecf20Sopenharmony_ci _QW_LOCKED)); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci/** 698c2ecf20Sopenharmony_ci * queued_read_lock - acquire read lock of a queue rwlock 708c2ecf20Sopenharmony_ci * @lock: Pointer to queue rwlock structure 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistatic inline void queued_read_lock(struct qrwlock *lock) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 cnts; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci cnts = atomic_add_return_acquire(_QR_BIAS, &lock->cnts); 778c2ecf20Sopenharmony_ci if (likely(!(cnts & _QW_WMASK))) 788c2ecf20Sopenharmony_ci return; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* The slowpath will decrement the reader count, if necessary. */ 818c2ecf20Sopenharmony_ci queued_read_lock_slowpath(lock); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/** 858c2ecf20Sopenharmony_ci * queued_write_lock - acquire write lock of a queue rwlock 868c2ecf20Sopenharmony_ci * @lock : Pointer to queue rwlock structure 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cistatic inline void queued_write_lock(struct qrwlock *lock) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci u32 cnts = 0; 918c2ecf20Sopenharmony_ci /* Optimize for the unfair lock case where the fair flag is 0. */ 928c2ecf20Sopenharmony_ci if (likely(atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, _QW_LOCKED))) 938c2ecf20Sopenharmony_ci return; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci queued_write_lock_slowpath(lock); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * queued_read_unlock - release read lock of a queue rwlock 1008c2ecf20Sopenharmony_ci * @lock : Pointer to queue rwlock structure 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic inline void queued_read_unlock(struct qrwlock *lock) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Atomically decrement the reader count 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci (void)atomic_sub_return_release(_QR_BIAS, &lock->cnts); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/** 1118c2ecf20Sopenharmony_ci * queued_write_unlock - release write lock of a queue rwlock 1128c2ecf20Sopenharmony_ci * @lock : Pointer to queue rwlock structure 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic inline void queued_write_unlock(struct qrwlock *lock) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci smp_store_release(&lock->wlocked, 0); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Remapping rwlock architecture specific functions to the corresponding 1218c2ecf20Sopenharmony_ci * queue rwlock functions. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci#define arch_read_lock(l) queued_read_lock(l) 1248c2ecf20Sopenharmony_ci#define arch_write_lock(l) queued_write_lock(l) 1258c2ecf20Sopenharmony_ci#define arch_read_trylock(l) queued_read_trylock(l) 1268c2ecf20Sopenharmony_ci#define arch_write_trylock(l) queued_write_trylock(l) 1278c2ecf20Sopenharmony_ci#define arch_read_unlock(l) queued_read_unlock(l) 1288c2ecf20Sopenharmony_ci#define arch_write_unlock(l) queued_write_unlock(l) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#endif /* __ASM_GENERIC_QRWLOCK_H */ 131