Skip to content

Commit 58bffba

Browse files
committed
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()
2 parents e968001 + 718a7ad commit 58bffba

File tree

5 files changed

+73
-0
lines changed

5 files changed

+73
-0
lines changed

Documentation/locking/hwspinlock.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,17 @@ is already free).
8585

8686
Should be called from a process context (might sleep).
8787

88+
::
89+
90+
int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id);
91+
92+
After verifying the owner of the hwspinlock, release a previously acquired
93+
hwspinlock; returns 0 on success, or an appropriate error code on failure
94+
(e.g. -EOPNOTSUPP if the bust operation is not defined for the specific
95+
hwspinlock).
96+
97+
Should be called from a process context (might sleep).
98+
8899
::
89100

90101
int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);

drivers/hwspinlock/hwspinlock_core.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,34 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
305305
}
306306
EXPORT_SYMBOL_GPL(__hwspin_unlock);
307307

308+
/**
309+
* hwspin_lock_bust() - bust a specific hwspinlock
310+
* @hwlock: a previously-acquired hwspinlock which we want to bust
311+
* @id: identifier of the remote lock holder, if applicable
312+
*
313+
* This function will bust a hwspinlock that was previously acquired as
314+
* long as the current owner of the lock matches the id given by the caller.
315+
*
316+
* Context: Process context.
317+
*
318+
* Returns: 0 on success, or -EINVAL if the hwspinlock does not exist, or
319+
* the bust operation fails, and -EOPNOTSUPP if the bust operation is not
320+
* defined for the hwspinlock.
321+
*/
322+
int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id)
323+
{
324+
if (WARN_ON(!hwlock))
325+
return -EINVAL;
326+
327+
if (!hwlock->bank->ops->bust) {
328+
pr_err("bust operation not defined\n");
329+
return -EOPNOTSUPP;
330+
}
331+
332+
return hwlock->bank->ops->bust(hwlock, id);
333+
}
334+
EXPORT_SYMBOL_GPL(hwspin_lock_bust);
335+
308336
/**
309337
* of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
310338
* @hwlock_spec: hwlock specifier as found in the device tree

drivers/hwspinlock/hwspinlock_internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ struct hwspinlock_device;
2121
* @trylock: make a single attempt to take the lock. returns 0 on
2222
* failure and true on success. may _not_ sleep.
2323
* @unlock: release the lock. always succeed. may _not_ sleep.
24+
* @bust: optional, platform-specific bust handler, called by hwspinlock
25+
* core to bust a specific lock.
2426
* @relax: optional, platform-specific relax handler, called by hwspinlock
2527
* core while spinning on a lock, between two successive
2628
* invocations of @trylock. may _not_ sleep.
2729
*/
2830
struct hwspinlock_ops {
2931
int (*trylock)(struct hwspinlock *lock);
3032
void (*unlock)(struct hwspinlock *lock);
33+
int (*bust)(struct hwspinlock *lock, unsigned int id);
3134
void (*relax)(struct hwspinlock *lock);
3235
};
3336

drivers/hwspinlock/qcom_hwspinlock.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,34 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
6464
pr_err("%s: failed to unlock spinlock\n", __func__);
6565
}
6666

67+
static int qcom_hwspinlock_bust(struct hwspinlock *lock, unsigned int id)
68+
{
69+
struct regmap_field *field = lock->priv;
70+
u32 owner;
71+
int ret;
72+
73+
ret = regmap_field_read(field, &owner);
74+
if (ret) {
75+
dev_err(lock->bank->dev, "unable to query spinlock owner\n");
76+
return ret;
77+
}
78+
79+
if (owner != id)
80+
return 0;
81+
82+
ret = regmap_field_write(field, 0);
83+
if (ret) {
84+
dev_err(lock->bank->dev, "failed to bust spinlock\n");
85+
return ret;
86+
}
87+
88+
return 0;
89+
}
90+
6791
static const struct hwspinlock_ops qcom_hwspinlock_ops = {
6892
.trylock = qcom_hwspinlock_trylock,
6993
.unlock = qcom_hwspinlock_unlock,
94+
.bust = qcom_hwspinlock_bust,
7095
};
7196

7297
static const struct regmap_config sfpb_mutex_config = {

include/linux/hwspinlock.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
6868
int __hwspin_trylock(struct hwspinlock *, int, unsigned long *);
6969
void __hwspin_unlock(struct hwspinlock *, int, unsigned long *);
7070
int of_hwspin_lock_get_id_byname(struct device_node *np, const char *name);
71+
int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id);
7172
int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock);
7273
struct hwspinlock *devm_hwspin_lock_request(struct device *dev);
7374
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)
127128
{
128129
}
129130

131+
static inline int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id)
132+
{
133+
return 0;
134+
}
135+
130136
static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
131137
{
132138
return 0;

0 commit comments

Comments
 (0)