// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Queued read/write locks3*4* (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.5*6* Authors: Waiman Long <[email protected]>7*/8#include <linux/smp.h>9#include <linux/bug.h>10#include <linux/cpumask.h>11#include <linux/percpu.h>12#include <linux/hardirq.h>13#include <linux/spinlock.h>14#include <trace/events/lock.h>1516/**17* queued_read_lock_slowpath - acquire read lock of a queued rwlock18* @lock: Pointer to queued rwlock structure19*/20void __lockfunc queued_read_lock_slowpath(struct qrwlock *lock)21{22/*23* Readers come here when they cannot get the lock without waiting24*/25if (unlikely(in_interrupt())) {26/*27* Readers in interrupt context will get the lock immediately28* if the writer is just waiting (not holding the lock yet),29* so spin with ACQUIRE semantics until the lock is available30* without waiting in the queue.31*/32atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED));33return;34}35atomic_sub(_QR_BIAS, &lock->cnts);3637trace_contention_begin(lock, LCB_F_SPIN | LCB_F_READ);3839/*40* Put the reader into the wait queue41*/42arch_spin_lock(&lock->wait_lock);43atomic_add(_QR_BIAS, &lock->cnts);4445/*46* The ACQUIRE semantics of the following spinning code ensure47* that accesses can't leak upwards out of our subsequent critical48* section in the case that the lock is currently held for write.49*/50atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED));5152/*53* Signal the next one in queue to become queue head54*/55arch_spin_unlock(&lock->wait_lock);5657trace_contention_end(lock, 0);58}59EXPORT_SYMBOL(queued_read_lock_slowpath);6061/**62* queued_write_lock_slowpath - acquire write lock of a queued rwlock63* @lock : Pointer to queued rwlock structure64*/65void __lockfunc queued_write_lock_slowpath(struct qrwlock *lock)66{67int cnts;6869trace_contention_begin(lock, LCB_F_SPIN | LCB_F_WRITE);7071/* Put the writer into the wait queue */72arch_spin_lock(&lock->wait_lock);7374/* Try to acquire the lock directly if no reader is present */75if (!(cnts = atomic_read(&lock->cnts)) &&76atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, _QW_LOCKED))77goto unlock;7879/* Set the waiting flag to notify readers that a writer is pending */80atomic_or(_QW_WAITING, &lock->cnts);8182/* When no more readers or writers, set the locked flag */83do {84cnts = atomic_cond_read_relaxed(&lock->cnts, VAL == _QW_WAITING);85} while (!atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, _QW_LOCKED));86unlock:87arch_spin_unlock(&lock->wait_lock);8889trace_contention_end(lock, 0);90}91EXPORT_SYMBOL(queued_write_lock_slowpath);929394