diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index 3f08cd4a5c28..e6cb9426c91d 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "hwspinlock_internal.h" @@ -25,6 +26,43 @@ struct qcom_hwspinlock_of_data { const struct regmap_config *regmap_config; }; +/** + * qcom_hwspinlock_bust() - bust qcom 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 error if bust operation fails + */ +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) { + pr_err("%s: unable to query spinlock owner\n", __func__); + return ret; + } + + if (owner != id) + return 0; + + ret = regmap_field_write(field, 0); + if (ret) { + pr_err("%s: failed to bust spinlock\n", __func__); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_hwspinlock_bust); + static int qcom_hwspinlock_trylock(struct hwspinlock *lock) { struct regmap_field *field = lock->priv; diff --git a/include/linux/soc/qcom/qcom_hwspinlock.h b/include/linux/soc/qcom/qcom_hwspinlock.h new file mode 100644 index 000000000000..a5f5a7ec85fc --- /dev/null +++ b/include/linux/soc/qcom/qcom_hwspinlock.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __QCOM_HWSPINLOCK_H +#define __QCOM_HWSPINLOCK_H + +struct hwspinlock; + +#if IS_ENABLED(CONFIG_HWSPINLOCK_QCOM) + +int qcom_hwspinlock_bust(struct hwspinlock *hwlock, unsigned int id); + +#else /* !CONFIG_HWSPINLOCK_QCOM */ + +static inline int qcom_hwspinlock_bust(struct hwspinlock *hwlock, unsigned int id) +{ + return 0; +} + +#endif /* CONFIG_HWSPINLOCK_QCOM */ + +#endif /* __QCOM_HWSPINLOCK_H */