diff options
author | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2020-05-01 17:37:54 +0200 |
---|---|---|
committer | Jonathan Corbet <corbet@lwn.net> | 2020-05-15 12:05:07 -0600 |
commit | 95ca6d73a8a97ba343082746dbf935863b76375a (patch) | |
tree | 5c7514627a4f4fa5d1b34783cf35b83354f4f2d6 /Documentation/hwspinlock.txt | |
parent | 9184027f0aaf6c95856bb57d04d0fa0b16fd9981 (diff) | |
download | lwn-95ca6d73a8a97ba343082746dbf935863b76375a.tar.gz lwn-95ca6d73a8a97ba343082746dbf935863b76375a.zip |
docs: move locking-specific documents to locking/
Several files under Documentation/*.txt describe some type of
locking API. Move them to locking/ subdir and add to the
locking/index.rst index file.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Link: https://lore.kernel.org/r/dd833a10bbd0b2c1461d78913f5ec28a7e27f00b.1588345503.git.mchehab+huawei@kernel.org
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Diffstat (limited to 'Documentation/hwspinlock.txt')
-rw-r--r-- | Documentation/hwspinlock.txt | 485 |
1 files changed, 0 insertions, 485 deletions
diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt deleted file mode 100644 index 6f03713b7003..000000000000 --- a/Documentation/hwspinlock.txt +++ /dev/null @@ -1,485 +0,0 @@ -=========================== -Hardware Spinlock Framework -=========================== - -Introduction -============ - -Hardware spinlock modules provide hardware assistance for synchronization -and mutual exclusion between heterogeneous processors and those not operating -under a single, shared operating system. - -For example, OMAP4 has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP, -each of which is running a different Operating System (the master, A9, -is usually running Linux and the slave processors, the M3 and the DSP, -are running some flavor of RTOS). - -A generic hwspinlock framework allows platform-independent drivers to use -the hwspinlock device in order to access data structures that are shared -between remote processors, that otherwise have no alternative mechanism -to accomplish synchronization and mutual exclusion operations. - -This is necessary, for example, for Inter-processor communications: -on OMAP4, cpu-intensive multimedia tasks are offloaded by the host to the -remote M3 and/or C64x+ slave processors (by an IPC subsystem called Syslink). - -To achieve fast message-based communications, a minimal kernel support -is needed to deliver messages arriving from a remote processor to the -appropriate user process. - -This communication is based on simple data structures that is shared between -the remote processors, and access to it is synchronized using the hwspinlock -module (remote processor directly places new messages in this shared data -structure). - -A common hwspinlock interface makes it possible to have generic, platform- -independent, drivers. - -User API -======== - -:: - - struct hwspinlock *hwspin_lock_request(void); - -Dynamically assign an hwspinlock and return its address, or NULL -in case an unused hwspinlock isn't available. Users of this -API will usually want to communicate the lock's id to the remote core -before it can be used to achieve synchronization. - -Should be called from a process context (might sleep). - -:: - - struct hwspinlock *hwspin_lock_request_specific(unsigned int id); - -Assign a specific hwspinlock id and return its address, or NULL -if that hwspinlock is already in use. Usually board code will -be calling this function in order to reserve specific hwspinlock -ids for predefined purposes. - -Should be called from a process context (might sleep). - -:: - - int of_hwspin_lock_get_id(struct device_node *np, int index); - -Retrieve the global lock id for an OF phandle-based specific lock. -This function provides a means for DT users of a hwspinlock module -to get the global lock id of a specific hwspinlock, so that it can -be requested using the normal hwspin_lock_request_specific() API. - -The function returns a lock id number on success, -EPROBE_DEFER if -the hwspinlock device is not yet registered with the core, or other -error values. - -Should be called from a process context (might sleep). - -:: - - int hwspin_lock_free(struct hwspinlock *hwlock); - -Free a previously-assigned hwspinlock; returns 0 on success, or an -appropriate error code on failure (e.g. -EINVAL if the hwspinlock -is already free). - -Should be called from a process context (might sleep). - -:: - - int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); - -Lock a previously-assigned hwspinlock with a timeout limit (specified in -msecs). If the hwspinlock is already taken, the function will busy loop -waiting for it to be released, but give up when the timeout elapses. -Upon a successful return from this function, preemption is disabled so -the caller must not sleep, and is advised to release the hwspinlock as -soon as possible, in order to minimize remote cores polling on the -hardware interconnect. - -Returns 0 when successful and an appropriate error code otherwise (most -notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). -The function will never sleep. - -:: - - int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int timeout); - -Lock a previously-assigned hwspinlock with a timeout limit (specified in -msecs). If the hwspinlock is already taken, the function will busy loop -waiting for it to be released, but give up when the timeout elapses. -Upon a successful return from this function, preemption and the local -interrupts are disabled, so the caller must not sleep, and is advised to -release the hwspinlock as soon as possible. - -Returns 0 when successful and an appropriate error code otherwise (most -notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). -The function will never sleep. - -:: - - int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock, unsigned int to, - unsigned long *flags); - -Lock a previously-assigned hwspinlock with a timeout limit (specified in -msecs). If the hwspinlock is already taken, the function will busy loop -waiting for it to be released, but give up when the timeout elapses. -Upon a successful return from this function, preemption is disabled, -local interrupts are disabled and their previous state is saved at the -given flags placeholder. The caller must not sleep, and is advised to -release the hwspinlock as soon as possible. - -Returns 0 when successful and an appropriate error code otherwise (most -notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). - -The function will never sleep. - -:: - - int hwspin_lock_timeout_raw(struct hwspinlock *hwlock, unsigned int timeout); - -Lock a previously-assigned hwspinlock with a timeout limit (specified in -msecs). If the hwspinlock is already taken, the function will busy loop -waiting for it to be released, but give up when the timeout elapses. - -Caution: User must protect the routine of getting hardware lock with mutex -or spinlock to avoid dead-lock, that will let user can do some time-consuming -or sleepable operations under the hardware lock. - -Returns 0 when successful and an appropriate error code otherwise (most -notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). - -The function will never sleep. - -:: - - int hwspin_lock_timeout_in_atomic(struct hwspinlock *hwlock, unsigned int to); - -Lock a previously-assigned hwspinlock with a timeout limit (specified in -msecs). If the hwspinlock is already taken, the function will busy loop -waiting for it to be released, but give up when the timeout elapses. - -This function shall be called only from an atomic context and the timeout -value shall not exceed a few msecs. - -Returns 0 when successful and an appropriate error code otherwise (most -notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). - -The function will never sleep. - -:: - - int hwspin_trylock(struct hwspinlock *hwlock); - - -Attempt to lock a previously-assigned hwspinlock, but immediately fail if -it is already taken. - -Upon a successful return from this function, preemption is disabled so -caller must not sleep, and is advised to release the hwspinlock as soon as -possible, in order to minimize remote cores polling on the hardware -interconnect. - -Returns 0 on success and an appropriate error code otherwise (most -notably -EBUSY if the hwspinlock was already taken). -The function will never sleep. - -:: - - int hwspin_trylock_irq(struct hwspinlock *hwlock); - - -Attempt to lock a previously-assigned hwspinlock, but immediately fail if -it is already taken. - -Upon a successful return from this function, preemption and the local -interrupts are disabled so caller must not sleep, and is advised to -release the hwspinlock as soon as possible. - -Returns 0 on success and an appropriate error code otherwise (most -notably -EBUSY if the hwspinlock was already taken). - -The function will never sleep. - -:: - - int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags); - -Attempt to lock a previously-assigned hwspinlock, but immediately fail if -it is already taken. - -Upon a successful return from this function, preemption is disabled, -the local interrupts are disabled and their previous state is saved -at the given flags placeholder. The caller must not sleep, and is advised -to release the hwspinlock as soon as possible. - -Returns 0 on success and an appropriate error code otherwise (most -notably -EBUSY if the hwspinlock was already taken). -The function will never sleep. - -:: - - int hwspin_trylock_raw(struct hwspinlock *hwlock); - -Attempt to lock a previously-assigned hwspinlock, but immediately fail if -it is already taken. - -Caution: User must protect the routine of getting hardware lock with mutex -or spinlock to avoid dead-lock, that will let user can do some time-consuming -or sleepable operations under the hardware lock. - -Returns 0 on success and an appropriate error code otherwise (most -notably -EBUSY if the hwspinlock was already taken). -The function will never sleep. - -:: - - int hwspin_trylock_in_atomic(struct hwspinlock *hwlock); - -Attempt to lock a previously-assigned hwspinlock, but immediately fail if -it is already taken. - -This function shall be called only from an atomic context. - -Returns 0 on success and an appropriate error code otherwise (most -notably -EBUSY if the hwspinlock was already taken). -The function will never sleep. - -:: - - void hwspin_unlock(struct hwspinlock *hwlock); - -Unlock a previously-locked hwspinlock. Always succeed, and can be called -from any context (the function never sleeps). - -.. note:: - - code should **never** unlock an hwspinlock which is already unlocked - (there is no protection against this). - -:: - - void hwspin_unlock_irq(struct hwspinlock *hwlock); - -Unlock a previously-locked hwspinlock and enable local interrupts. -The caller should **never** unlock an hwspinlock which is already unlocked. - -Doing so is considered a bug (there is no protection against this). -Upon a successful return from this function, preemption and local -interrupts are enabled. This function will never sleep. - -:: - - void - hwspin_unlock_irqrestore(struct hwspinlock *hwlock, unsigned long *flags); - -Unlock a previously-locked hwspinlock. - -The caller should **never** unlock an hwspinlock which is already unlocked. -Doing so is considered a bug (there is no protection against this). -Upon a successful return from this function, preemption is reenabled, -and the state of the local interrupts is restored to the state saved at -the given flags. This function will never sleep. - -:: - - void hwspin_unlock_raw(struct hwspinlock *hwlock); - -Unlock a previously-locked hwspinlock. - -The caller should **never** unlock an hwspinlock which is already unlocked. -Doing so is considered a bug (there is no protection against this). -This function will never sleep. - -:: - - void hwspin_unlock_in_atomic(struct hwspinlock *hwlock); - -Unlock a previously-locked hwspinlock. - -The caller should **never** unlock an hwspinlock which is already unlocked. -Doing so is considered a bug (there is no protection against this). -This function will never sleep. - -:: - - int hwspin_lock_get_id(struct hwspinlock *hwlock); - -Retrieve id number of a given hwspinlock. This is needed when an -hwspinlock is dynamically assigned: before it can be used to achieve -mutual exclusion with a remote cpu, the id number should be communicated -to the remote task with which we want to synchronize. - -Returns the hwspinlock id number, or -EINVAL if hwlock is null. - -Typical usage -============= - -:: - - #include <linux/hwspinlock.h> - #include <linux/err.h> - - int hwspinlock_example1(void) - { - struct hwspinlock *hwlock; - int ret; - - /* dynamically assign a hwspinlock */ - hwlock = hwspin_lock_request(); - if (!hwlock) - ... - - id = hwspin_lock_get_id(hwlock); - /* probably need to communicate id to a remote processor now */ - - /* take the lock, spin for 1 sec if it's already taken */ - ret = hwspin_lock_timeout(hwlock, 1000); - if (ret) - ... - - /* - * we took the lock, do our thing now, but do NOT sleep - */ - - /* release the lock */ - hwspin_unlock(hwlock); - - /* free the lock */ - ret = hwspin_lock_free(hwlock); - if (ret) - ... - - return ret; - } - - int hwspinlock_example2(void) - { - struct hwspinlock *hwlock; - int ret; - - /* - * assign a specific hwspinlock id - this should be called early - * by board init code. - */ - hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID); - if (!hwlock) - ... - - /* try to take it, but don't spin on it */ - ret = hwspin_trylock(hwlock); - if (!ret) { - pr_info("lock is already taken\n"); - return -EBUSY; - } - - /* - * we took the lock, do our thing now, but do NOT sleep - */ - - /* release the lock */ - hwspin_unlock(hwlock); - - /* free the lock */ - ret = hwspin_lock_free(hwlock); - if (ret) - ... - - return ret; - } - - -API for implementors -==================== - -:: - - int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev, - const struct hwspinlock_ops *ops, int base_id, int num_locks); - -To be called from the underlying platform-specific implementation, in -order to register a new hwspinlock device (which is usually a bank of -numerous locks). Should be called from a process context (this function -might sleep). - -Returns 0 on success, or appropriate error code on failure. - -:: - - int hwspin_lock_unregister(struct hwspinlock_device *bank); - -To be called from the underlying vendor-specific implementation, in order -to unregister an hwspinlock device (which is usually a bank of numerous -locks). - -Should be called from a process context (this function might sleep). - -Returns the address of hwspinlock on success, or NULL on error (e.g. -if the hwspinlock is still in use). - -Important structs -================= - -struct hwspinlock_device is a device which usually contains a bank -of hardware locks. It is registered by the underlying hwspinlock -implementation using the hwspin_lock_register() API. - -:: - - /** - * struct hwspinlock_device - a device which usually spans numerous hwspinlocks - * @dev: underlying device, will be used to invoke runtime PM api - * @ops: platform-specific hwspinlock handlers - * @base_id: id index of the first lock in this device - * @num_locks: number of locks in this device - * @lock: dynamically allocated array of 'struct hwspinlock' - */ - struct hwspinlock_device { - struct device *dev; - const struct hwspinlock_ops *ops; - int base_id; - int num_locks; - struct hwspinlock lock[0]; - }; - -struct hwspinlock_device contains an array of hwspinlock structs, each -of which represents a single hardware lock:: - - /** - * struct hwspinlock - this struct represents a single hwspinlock instance - * @bank: the hwspinlock_device structure which owns this lock - * @lock: initialized and used by hwspinlock core - * @priv: private data, owned by the underlying platform-specific hwspinlock drv - */ - struct hwspinlock { - struct hwspinlock_device *bank; - spinlock_t lock; - void *priv; - }; - -When registering a bank of locks, the hwspinlock driver only needs to -set the priv members of the locks. The rest of the members are set and -initialized by the hwspinlock core itself. - -Implementation callbacks -======================== - -There are three possible callbacks defined in 'struct hwspinlock_ops':: - - struct hwspinlock_ops { - int (*trylock)(struct hwspinlock *lock); - void (*unlock)(struct hwspinlock *lock); - void (*relax)(struct hwspinlock *lock); - }; - -The first two callbacks are mandatory: - -The ->trylock() callback should make a single attempt to take the lock, and -return 0 on failure and 1 on success. This callback may **not** sleep. - -The ->unlock() callback releases the lock. It always succeed, and it, too, -may **not** sleep. - -The ->relax() callback is optional. It is called by hwspinlock core while -spinning on a lock, and can be used by the underlying implementation to force -a delay between two successive invocations of ->trylock(). It may **not** sleep. |