Commit 718a7ad7 authored by Bjorn Andersson's avatar Bjorn Andersson
Browse files

Merge branch '20240529-hwspinlock-bust-v3-2-c8b924ffa5a2@quicinc.com' into hwspinlock-next

Merge the introduction of hwspin_lock_bust() through a topic branch, so
that it can also be merged into the rproc-next branch. This to avoid any
potential conflicts between the two trees.
parents 1613e604 73100deb
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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);
+28 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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);
};

+25 −0
Original line number Diff line number Diff line
@@ -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 = {
+6 −0
Original line number Diff line number Diff line
@@ -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;