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()

+73
+11
Documentation/locking/hwspinlock.rst
··· 87 88 :: 89 90 int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); 91 92 Lock a previously-assigned hwspinlock with a timeout limit (specified in
··· 87 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 + 99 + :: 100 + 101 int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); 102 103 Lock a previously-assigned hwspinlock with a timeout limit (specified in
+28
drivers/hwspinlock/hwspinlock_core.c
··· 306 EXPORT_SYMBOL_GPL(__hwspin_unlock); 307 308 /** 309 * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id 310 * @hwlock_spec: hwlock specifier as found in the device tree 311 *
··· 306 EXPORT_SYMBOL_GPL(__hwspin_unlock); 307 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 + 336 + /** 337 * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id 338 * @hwlock_spec: hwlock specifier as found in the device tree 339 *
+3
drivers/hwspinlock/hwspinlock_internal.h
··· 21 * @trylock: make a single attempt to take the lock. returns 0 on 22 * failure and true on success. may _not_ sleep. 23 * @unlock: release the lock. always succeed. may _not_ sleep. 24 * @relax: optional, platform-specific relax handler, called by hwspinlock 25 * core while spinning on a lock, between two successive 26 * invocations of @trylock. may _not_ sleep. ··· 30 struct hwspinlock_ops { 31 int (*trylock)(struct hwspinlock *lock); 32 void (*unlock)(struct hwspinlock *lock); 33 void (*relax)(struct hwspinlock *lock); 34 }; 35
··· 21 * @trylock: make a single attempt to take the lock. returns 0 on 22 * failure and true on success. may _not_ sleep. 23 * @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. 26 * @relax: optional, platform-specific relax handler, called by hwspinlock 27 * core while spinning on a lock, between two successive 28 * invocations of @trylock. may _not_ sleep. ··· 28 struct hwspinlock_ops { 29 int (*trylock)(struct hwspinlock *lock); 30 void (*unlock)(struct hwspinlock *lock); 31 + int (*bust)(struct hwspinlock *lock, unsigned int id); 32 void (*relax)(struct hwspinlock *lock); 33 }; 34
+25
drivers/hwspinlock/qcom_hwspinlock.c
··· 64 pr_err("%s: failed to unlock spinlock\n", __func__); 65 } 66 67 static const struct hwspinlock_ops qcom_hwspinlock_ops = { 68 .trylock = qcom_hwspinlock_trylock, 69 .unlock = qcom_hwspinlock_unlock, 70 }; 71 72 static const struct regmap_config sfpb_mutex_config = {
··· 64 pr_err("%s: failed to unlock spinlock\n", __func__); 65 } 66 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 + 91 static const struct hwspinlock_ops qcom_hwspinlock_ops = { 92 .trylock = qcom_hwspinlock_trylock, 93 .unlock = qcom_hwspinlock_unlock, 94 + .bust = qcom_hwspinlock_bust, 95 }; 96 97 static const struct regmap_config sfpb_mutex_config = {
+6
include/linux/hwspinlock.h
··· 68 int __hwspin_trylock(struct hwspinlock *, int, unsigned long *); 69 void __hwspin_unlock(struct hwspinlock *, int, unsigned long *); 70 int of_hwspin_lock_get_id_byname(struct device_node *np, const char *name); 71 int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock); 72 struct hwspinlock *devm_hwspin_lock_request(struct device *dev); 73 struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev, ··· 126 static inline 127 void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) 128 { 129 } 130 131 static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
··· 68 int __hwspin_trylock(struct hwspinlock *, int, unsigned long *); 69 void __hwspin_unlock(struct hwspinlock *, int, unsigned long *); 70 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); 72 int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock); 73 struct hwspinlock *devm_hwspin_lock_request(struct device *dev); 74 struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev, ··· 125 static inline 126 void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) 127 { 128 + } 129 + 130 + static inline int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id) 131 + { 132 + return 0; 133 } 134 135 static inline int of_hwspin_lock_get_id(struct device_node *np, int index)