hwspinlock.txt: standardize document format
Each text file under Documentation follows a different format. Some doesn't even have titles! Change its representation to follow the adopted standard, using ReST markups for it to be parseable by Sphinx: - Adjust title markups; - remove explicit numeration from titles; - mark literal blocks as such; - replace _foo_ by **foo** for emphasis; - adjust whitespaces and add blank lines where needed. Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com> Signed-off-by: Jonathan Corbet <corbet@lwn.net>zero-colors
parent
440e4f6d29
commit
e2862b25dc
|
@ -1,6 +1,9 @@
|
||||||
|
===========================
|
||||||
Hardware Spinlock Framework
|
Hardware Spinlock Framework
|
||||||
|
===========================
|
||||||
|
|
||||||
1. Introduction
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
Hardware spinlock modules provide hardware assistance for synchronization
|
Hardware spinlock modules provide hardware assistance for synchronization
|
||||||
and mutual exclusion between heterogeneous processors and those not operating
|
and mutual exclusion between heterogeneous processors and those not operating
|
||||||
|
@ -32,286 +35,370 @@ structure).
|
||||||
A common hwspinlock interface makes it possible to have generic, platform-
|
A common hwspinlock interface makes it possible to have generic, platform-
|
||||||
independent, drivers.
|
independent, drivers.
|
||||||
|
|
||||||
2. User API
|
User API
|
||||||
|
========
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
struct hwspinlock *hwspin_lock_request(void);
|
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
|
Dynamically assign an hwspinlock and return its address, or NULL
|
||||||
API will usually want to communicate the lock's id to the remote core
|
in case an unused hwspinlock isn't available. Users of this
|
||||||
before it can be used to achieve synchronization.
|
API will usually want to communicate the lock's id to the remote core
|
||||||
Should be called from a process context (might sleep).
|
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);
|
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
|
Assign a specific hwspinlock id and return its address, or NULL
|
||||||
be calling this function in order to reserve specific hwspinlock
|
if that hwspinlock is already in use. Usually board code will
|
||||||
ids for predefined purposes.
|
be calling this function in order to reserve specific hwspinlock
|
||||||
Should be called from a process context (might sleep).
|
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);
|
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
|
Retrieve the global lock id for an OF phandle-based specific lock.
|
||||||
to get the global lock id of a specific hwspinlock, so that it can
|
This function provides a means for DT users of a hwspinlock module
|
||||||
be requested using the normal hwspin_lock_request_specific() API.
|
to get the global lock id of a specific hwspinlock, so that it can
|
||||||
The function returns a lock id number on success, -EPROBE_DEFER if
|
be requested using the normal hwspin_lock_request_specific() API.
|
||||||
the hwspinlock device is not yet registered with the core, or other
|
|
||||||
error values.
|
The function returns a lock id number on success, -EPROBE_DEFER if
|
||||||
Should be called from a process context (might sleep).
|
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);
|
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
|
Free a previously-assigned hwspinlock; returns 0 on success, or an
|
||||||
is already free).
|
appropriate error code on failure (e.g. -EINVAL if the hwspinlock
|
||||||
Should be called from a process context (might sleep).
|
is already free).
|
||||||
|
|
||||||
|
Should be called from a process context (might sleep).
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);
|
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
|
Lock a previously-assigned hwspinlock with a timeout limit (specified in
|
||||||
waiting for it to be released, but give up when the timeout elapses.
|
msecs). If the hwspinlock is already taken, the function will busy loop
|
||||||
Upon a successful return from this function, preemption is disabled so
|
waiting for it to be released, but give up when the timeout elapses.
|
||||||
the caller must not sleep, and is advised to release the hwspinlock as
|
Upon a successful return from this function, preemption is disabled so
|
||||||
soon as possible, in order to minimize remote cores polling on the
|
the caller must not sleep, and is advised to release the hwspinlock as
|
||||||
hardware interconnect.
|
soon as possible, in order to minimize remote cores polling on the
|
||||||
Returns 0 when successful and an appropriate error code otherwise (most
|
hardware interconnect.
|
||||||
notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
|
|
||||||
The function will never sleep.
|
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);
|
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
|
Lock a previously-assigned hwspinlock with a timeout limit (specified in
|
||||||
waiting for it to be released, but give up when the timeout elapses.
|
msecs). If the hwspinlock is already taken, the function will busy loop
|
||||||
Upon a successful return from this function, preemption and the local
|
waiting for it to be released, but give up when the timeout elapses.
|
||||||
interrupts are disabled, so the caller must not sleep, and is advised to
|
Upon a successful return from this function, preemption and the local
|
||||||
release the hwspinlock as soon as possible.
|
interrupts are disabled, so the caller must not sleep, and is advised to
|
||||||
Returns 0 when successful and an appropriate error code otherwise (most
|
release the hwspinlock as soon as possible.
|
||||||
notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
|
|
||||||
The function will never sleep.
|
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,
|
int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock, unsigned int to,
|
||||||
unsigned long *flags);
|
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
|
Lock a previously-assigned hwspinlock with a timeout limit (specified in
|
||||||
waiting for it to be released, but give up when the timeout elapses.
|
msecs). If the hwspinlock is already taken, the function will busy loop
|
||||||
Upon a successful return from this function, preemption is disabled,
|
waiting for it to be released, but give up when the timeout elapses.
|
||||||
local interrupts are disabled and their previous state is saved at the
|
Upon a successful return from this function, preemption is disabled,
|
||||||
given flags placeholder. The caller must not sleep, and is advised to
|
local interrupts are disabled and their previous state is saved at the
|
||||||
release the hwspinlock as soon as possible.
|
given flags placeholder. The caller must not sleep, and is advised to
|
||||||
Returns 0 when successful and an appropriate error code otherwise (most
|
release the hwspinlock as soon as possible.
|
||||||
notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
|
|
||||||
The function will never sleep.
|
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);
|
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
|
Attempt to lock a previously-assigned hwspinlock, but immediately fail if
|
||||||
caller must not sleep, and is advised to release the hwspinlock as soon as
|
it is already taken.
|
||||||
possible, in order to minimize remote cores polling on the hardware
|
|
||||||
interconnect.
|
Upon a successful return from this function, preemption is disabled so
|
||||||
Returns 0 on success and an appropriate error code otherwise (most
|
caller must not sleep, and is advised to release the hwspinlock as soon as
|
||||||
notably -EBUSY if the hwspinlock was already taken).
|
possible, in order to minimize remote cores polling on the hardware
|
||||||
The function will never sleep.
|
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);
|
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
|
Attempt to lock a previously-assigned hwspinlock, but immediately fail if
|
||||||
interrupts are disabled so caller must not sleep, and is advised to
|
it is already taken.
|
||||||
release the hwspinlock as soon as possible.
|
|
||||||
Returns 0 on success and an appropriate error code otherwise (most
|
Upon a successful return from this function, preemption and the local
|
||||||
notably -EBUSY if the hwspinlock was already taken).
|
interrupts are disabled so caller must not sleep, and is advised to
|
||||||
The function will never sleep.
|
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);
|
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.
|
Attempt to lock a previously-assigned hwspinlock, but immediately fail if
|
||||||
Upon a successful return from this function, preemption is disabled,
|
it is already taken.
|
||||||
the local interrupts are disabled and their previous state is saved
|
|
||||||
at the given flags placeholder. The caller must not sleep, and is advised
|
Upon a successful return from this function, preemption is disabled,
|
||||||
to release the hwspinlock as soon as possible.
|
the local interrupts are disabled and their previous state is saved
|
||||||
Returns 0 on success and an appropriate error code otherwise (most
|
at the given flags placeholder. The caller must not sleep, and is advised
|
||||||
notably -EBUSY if the hwspinlock was already taken).
|
to release the hwspinlock as soon as possible.
|
||||||
The function will never sleep.
|
|
||||||
|
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);
|
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 a previously-locked hwspinlock. Always succeed, and can be called
|
||||||
unlock an hwspinlock which is already unlocked (there is no protection
|
from any context (the function never sleeps).
|
||||||
against this).
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
code should **never** unlock an hwspinlock which is already unlocked
|
||||||
|
(there is no protection against this).
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
void hwspin_unlock_irq(struct hwspinlock *hwlock);
|
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.
|
Unlock a previously-locked hwspinlock and enable local interrupts.
|
||||||
Doing so is considered a bug (there is no protection against this).
|
The caller should **never** unlock an hwspinlock which is already unlocked.
|
||||||
Upon a successful return from this function, preemption and local
|
|
||||||
interrupts are enabled. This function will never sleep.
|
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
|
void
|
||||||
hwspin_unlock_irqrestore(struct hwspinlock *hwlock, unsigned long *flags);
|
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.
|
Unlock a previously-locked hwspinlock.
|
||||||
Doing so is considered a bug (there is no protection against this).
|
|
||||||
Upon a successful return from this function, preemption is reenabled,
|
The caller should **never** unlock an hwspinlock which is already unlocked.
|
||||||
and the state of the local interrupts is restored to the state saved at
|
Doing so is considered a bug (there is no protection against this).
|
||||||
the given flags. This function will never sleep.
|
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.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int hwspin_lock_get_id(struct hwspinlock *hwlock);
|
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.
|
|
||||||
|
|
||||||
3. Typical usage
|
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.
|
||||||
|
|
||||||
#include <linux/hwspinlock.h>
|
Returns the hwspinlock id number, or -EINVAL if hwlock is null.
|
||||||
#include <linux/err.h>
|
|
||||||
|
|
||||||
int hwspinlock_example1(void)
|
Typical usage
|
||||||
{
|
=============
|
||||||
struct hwspinlock *hwlock;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* dynamically assign a hwspinlock */
|
::
|
||||||
hwlock = hwspin_lock_request();
|
|
||||||
if (!hwlock)
|
|
||||||
...
|
|
||||||
|
|
||||||
id = hwspin_lock_get_id(hwlock);
|
#include <linux/hwspinlock.h>
|
||||||
/* probably need to communicate id to a remote processor now */
|
#include <linux/err.h>
|
||||||
|
|
||||||
/* take the lock, spin for 1 sec if it's already taken */
|
int hwspinlock_example1(void)
|
||||||
ret = hwspin_lock_timeout(hwlock, 1000);
|
{
|
||||||
if (ret)
|
struct hwspinlock *hwlock;
|
||||||
...
|
int ret;
|
||||||
|
|
||||||
/*
|
/* dynamically assign a hwspinlock */
|
||||||
* we took the lock, do our thing now, but do NOT sleep
|
hwlock = hwspin_lock_request();
|
||||||
*/
|
if (!hwlock)
|
||||||
|
...
|
||||||
|
|
||||||
/* release the lock */
|
id = hwspin_lock_get_id(hwlock);
|
||||||
hwspin_unlock(hwlock);
|
/* probably need to communicate id to a remote processor now */
|
||||||
|
|
||||||
/* free the lock */
|
/* take the lock, spin for 1 sec if it's already taken */
|
||||||
ret = hwspin_lock_free(hwlock);
|
ret = hwspin_lock_timeout(hwlock, 1000);
|
||||||
if (ret)
|
if (ret)
|
||||||
...
|
...
|
||||||
|
|
||||||
return ret;
|
/*
|
||||||
}
|
* we took the lock, do our thing now, but do NOT sleep
|
||||||
|
*/
|
||||||
|
|
||||||
int hwspinlock_example2(void)
|
/* release the lock */
|
||||||
{
|
hwspin_unlock(hwlock);
|
||||||
struct hwspinlock *hwlock;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
/* free the lock */
|
||||||
* assign a specific hwspinlock id - this should be called early
|
ret = hwspin_lock_free(hwlock);
|
||||||
* by board init code.
|
if (ret)
|
||||||
*/
|
...
|
||||||
hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID);
|
|
||||||
if (!hwlock)
|
|
||||||
...
|
|
||||||
|
|
||||||
/* try to take it, but don't spin on it */
|
return ret;
|
||||||
ret = hwspin_trylock(hwlock);
|
|
||||||
if (!ret) {
|
|
||||||
pr_info("lock is already taken\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int hwspinlock_example2(void)
|
||||||
* we took the lock, do our thing now, but do NOT sleep
|
{
|
||||||
*/
|
struct hwspinlock *hwlock;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* release the lock */
|
/*
|
||||||
hwspin_unlock(hwlock);
|
* assign a specific hwspinlock id - this should be called early
|
||||||
|
* by board init code.
|
||||||
|
*/
|
||||||
|
hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID);
|
||||||
|
if (!hwlock)
|
||||||
|
...
|
||||||
|
|
||||||
/* free the lock */
|
/* try to take it, but don't spin on it */
|
||||||
ret = hwspin_lock_free(hwlock);
|
ret = hwspin_trylock(hwlock);
|
||||||
if (ret)
|
if (!ret) {
|
||||||
...
|
pr_info("lock is already taken\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
4. API for implementors
|
API for implementors
|
||||||
|
====================
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
|
int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
|
||||||
const struct hwspinlock_ops *ops, int base_id, int num_locks);
|
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
|
To be called from the underlying platform-specific implementation, in
|
||||||
numerous locks). Should be called from a process context (this function
|
order to register a new hwspinlock device (which is usually a bank of
|
||||||
might sleep).
|
numerous locks). Should be called from a process context (this function
|
||||||
Returns 0 on success, or appropriate error code on failure.
|
might sleep).
|
||||||
|
|
||||||
|
Returns 0 on success, or appropriate error code on failure.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
int hwspin_lock_unregister(struct hwspinlock_device *bank);
|
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).
|
|
||||||
|
|
||||||
5. Important structs
|
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
|
struct hwspinlock_device is a device which usually contains a bank
|
||||||
of hardware locks. It is registered by the underlying hwspinlock
|
of hardware locks. It is registered by the underlying hwspinlock
|
||||||
implementation using the hwspin_lock_register() API.
|
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
|
* struct hwspinlock_device - a device which usually spans numerous hwspinlocks
|
||||||
* @base_id: id index of the first lock in this device
|
* @dev: underlying device, will be used to invoke runtime PM api
|
||||||
* @num_locks: number of locks in this device
|
* @ops: platform-specific hwspinlock handlers
|
||||||
* @lock: dynamically allocated array of 'struct hwspinlock'
|
* @base_id: id index of the first lock in this device
|
||||||
*/
|
* @num_locks: number of locks in this device
|
||||||
struct hwspinlock_device {
|
* @lock: dynamically allocated array of 'struct hwspinlock'
|
||||||
struct device *dev;
|
*/
|
||||||
const struct hwspinlock_ops *ops;
|
struct hwspinlock_device {
|
||||||
int base_id;
|
struct device *dev;
|
||||||
int num_locks;
|
const struct hwspinlock_ops *ops;
|
||||||
struct hwspinlock lock[0];
|
int base_id;
|
||||||
};
|
int num_locks;
|
||||||
|
struct hwspinlock lock[0];
|
||||||
|
};
|
||||||
|
|
||||||
struct hwspinlock_device contains an array of hwspinlock structs, each
|
struct hwspinlock_device contains an array of hwspinlock structs, each
|
||||||
of which represents a single hardware lock:
|
of which represents a single hardware lock::
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hwspinlock - this struct represents a single hwspinlock instance
|
* struct hwspinlock - this struct represents a single hwspinlock instance
|
||||||
* @bank: the hwspinlock_device structure which owns this lock
|
* @bank: the hwspinlock_device structure which owns this lock
|
||||||
* @lock: initialized and used by hwspinlock core
|
* @lock: initialized and used by hwspinlock core
|
||||||
* @priv: private data, owned by the underlying platform-specific hwspinlock drv
|
* @priv: private data, owned by the underlying platform-specific hwspinlock drv
|
||||||
*/
|
*/
|
||||||
struct hwspinlock {
|
struct hwspinlock {
|
||||||
struct hwspinlock_device *bank;
|
struct hwspinlock_device *bank;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
When registering a bank of locks, the hwspinlock driver only needs to
|
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
|
set the priv members of the locks. The rest of the members are set and
|
||||||
initialized by the hwspinlock core itself.
|
initialized by the hwspinlock core itself.
|
||||||
|
|
||||||
6. Implementation callbacks
|
Implementation callbacks
|
||||||
|
========================
|
||||||
|
|
||||||
There are three possible callbacks defined in 'struct hwspinlock_ops':
|
There are three possible callbacks defined in 'struct hwspinlock_ops'::
|
||||||
|
|
||||||
struct hwspinlock_ops {
|
struct hwspinlock_ops {
|
||||||
int (*trylock)(struct hwspinlock *lock);
|
int (*trylock)(struct hwspinlock *lock);
|
||||||
void (*unlock)(struct hwspinlock *lock);
|
void (*unlock)(struct hwspinlock *lock);
|
||||||
void (*relax)(struct hwspinlock *lock);
|
void (*relax)(struct hwspinlock *lock);
|
||||||
};
|
};
|
||||||
|
|
||||||
The first two callbacks are mandatory:
|
The first two callbacks are mandatory:
|
||||||
|
|
||||||
The ->trylock() callback should make a single attempt to take the lock, and
|
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.
|
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,
|
The ->unlock() callback releases the lock. It always succeed, and it, too,
|
||||||
may _not_ sleep.
|
may **not** sleep.
|
||||||
|
|
||||||
The ->relax() callback is optional. It is called by hwspinlock core while
|
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
|
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.
|
a delay between two successive invocations of ->trylock(). It may **not** sleep.
|
||||||
|
|
Loading…
Reference in New Issue