mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-06 08:47:44 -04:00
Merge tag 'hwlock-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Pull hwspinlock updates from Bjorn Andersson: "This introduces a mechanism in the hardware spinlock framework, and the Qualcomm TCSR mutex driver, for allowing clients to bust locks held by a remote processor in the event that this enters a faulty state while holding the shared lock" * tag 'hwlock-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: hwspinlock: qcom: implement bust operation hwspinlock: Introduce hwspin_lock_bust()
This commit is contained in:
@@ -85,6 +85,17 @@ is already free).
|
||||
|
||||
Should be called from a process context (might sleep).
|
||||
|
||||
::
|
||||
|
||||
int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id);
|
||||
|
||||
After verifying the owner of the hwspinlock, release a previously acquired
|
||||
hwspinlock; returns 0 on success, or an appropriate error code on failure
|
||||
(e.g. -EOPNOTSUPP if the bust operation is not defined for the specific
|
||||
hwspinlock).
|
||||
|
||||
Should be called from a process context (might sleep).
|
||||
|
||||
::
|
||||
|
||||
int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);
|
||||
|
||||
@@ -305,6 +305,34 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hwspin_unlock);
|
||||
|
||||
/**
|
||||
* hwspin_lock_bust() - bust a specific hwspinlock
|
||||
* @hwlock: a previously-acquired hwspinlock which we want to bust
|
||||
* @id: identifier of the remote lock holder, if applicable
|
||||
*
|
||||
* This function will bust a hwspinlock that was previously acquired as
|
||||
* long as the current owner of the lock matches the id given by the caller.
|
||||
*
|
||||
* Context: Process context.
|
||||
*
|
||||
* Returns: 0 on success, or -EINVAL if the hwspinlock does not exist, or
|
||||
* the bust operation fails, and -EOPNOTSUPP if the bust operation is not
|
||||
* defined for the hwspinlock.
|
||||
*/
|
||||
int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id)
|
||||
{
|
||||
if (WARN_ON(!hwlock))
|
||||
return -EINVAL;
|
||||
|
||||
if (!hwlock->bank->ops->bust) {
|
||||
pr_err("bust operation not defined\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return hwlock->bank->ops->bust(hwlock, id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hwspin_lock_bust);
|
||||
|
||||
/**
|
||||
* of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
|
||||
* @hwlock_spec: hwlock specifier as found in the device tree
|
||||
|
||||
@@ -21,6 +21,8 @@ struct hwspinlock_device;
|
||||
* @trylock: make a single attempt to take the lock. returns 0 on
|
||||
* failure and true on success. may _not_ sleep.
|
||||
* @unlock: release the lock. always succeed. may _not_ sleep.
|
||||
* @bust: optional, platform-specific bust handler, called by hwspinlock
|
||||
* core to bust a specific lock.
|
||||
* @relax: optional, platform-specific relax handler, called by hwspinlock
|
||||
* core while spinning on a lock, between two successive
|
||||
* invocations of @trylock. may _not_ sleep.
|
||||
@@ -28,6 +30,7 @@ struct hwspinlock_device;
|
||||
struct hwspinlock_ops {
|
||||
int (*trylock)(struct hwspinlock *lock);
|
||||
void (*unlock)(struct hwspinlock *lock);
|
||||
int (*bust)(struct hwspinlock *lock, unsigned int id);
|
||||
void (*relax)(struct hwspinlock *lock);
|
||||
};
|
||||
|
||||
|
||||
@@ -64,9 +64,34 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
|
||||
pr_err("%s: failed to unlock spinlock\n", __func__);
|
||||
}
|
||||
|
||||
static int qcom_hwspinlock_bust(struct hwspinlock *lock, unsigned int id)
|
||||
{
|
||||
struct regmap_field *field = lock->priv;
|
||||
u32 owner;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(field, &owner);
|
||||
if (ret) {
|
||||
dev_err(lock->bank->dev, "unable to query spinlock owner\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (owner != id)
|
||||
return 0;
|
||||
|
||||
ret = regmap_field_write(field, 0);
|
||||
if (ret) {
|
||||
dev_err(lock->bank->dev, "failed to bust spinlock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwspinlock_ops qcom_hwspinlock_ops = {
|
||||
.trylock = qcom_hwspinlock_trylock,
|
||||
.unlock = qcom_hwspinlock_unlock,
|
||||
.bust = qcom_hwspinlock_bust,
|
||||
};
|
||||
|
||||
static const struct regmap_config sfpb_mutex_config = {
|
||||
|
||||
@@ -68,6 +68,7 @@ int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
|
||||
int __hwspin_trylock(struct hwspinlock *, int, unsigned long *);
|
||||
void __hwspin_unlock(struct hwspinlock *, int, unsigned long *);
|
||||
int of_hwspin_lock_get_id_byname(struct device_node *np, const char *name);
|
||||
int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id);
|
||||
int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock);
|
||||
struct hwspinlock *devm_hwspin_lock_request(struct device *dev);
|
||||
struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev,
|
||||
@@ -127,6 +128,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
|
||||
{
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user