lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250326154613.3735-1-srinivas.kandagatla@linaro.org>
Date: Wed, 26 Mar 2025 15:46:13 +0000
From: srinivas.kandagatla@...aro.org
To: peda@...ntia.se
Cc: linux-kernel@...r.kernel.org,
	dmitry.baryshkov@....qualcomm.com,
	Srinivas Kandagatla <srinivas.kandagatla@...aro.org>
Subject: [RFC PATCH] mux: core: add exclusive mux controls support

From: Srinivas Kandagatla <srinivas.kandagatla@...aro.org>

Mux control core by design supports mux controls that are shared with
multiple consumers. However in some usecases where the mux is exclusively
owned by one consumer do not need some of the locking and deselect apis.

exclusive apis makes the consumer side of code much simipler.

ex:
From
	if (is_mux_selected)
		mux_control_deselect()

	if (mux_control_select())
		is_mux_selected = false;
	else
		is_mux_selected = true;

to
	if (mux_control_select())
		dev_err("mux select failed..");

This patch adds a new *_get_exclusive() api to request an exclusive mux
control and rest of the apis usage remains same, except that exclusive
mux do not need deselect api calling, drivers can simply select the
desired state and its consumers responsiblity to make sure that correct
state is selected.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@...aro.org>
---
 drivers/mux/core.c           | 123 ++++++++++++++++++++++++++++-------
 include/linux/mux/consumer.h |   3 +
 include/linux/mux/driver.h   |   9 +++
 3 files changed, 113 insertions(+), 22 deletions(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 02be4ba37257..e0b8a723948b 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -356,6 +356,10 @@ static void mux_control_delay(struct mux_control *mux, unsigned int delay_us)
  * until mux_control_deselect() or mux_state_deselect() is called (by someone
  * else).
  *
+ * Exception to this is for exclusive mux control, which do not need
+ * mux_state_deselect() as the owner of mux has exclusive access to this mux
+ * and is responsible to set the correct state.
+ *
  * Therefore, make sure to call mux_control_deselect() when the operation is
  * complete and the mux-control is free for others to use, but do not call
  * mux_control_deselect() if mux_control_select() fails.
@@ -368,15 +372,17 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
 {
 	int ret;
 
-	ret = down_killable(&mux->lock);
-	if (ret < 0)
-		return ret;
+	if (!mux->exclusive) {
+		ret = down_killable(&mux->lock);
+		if (ret < 0)
+			return ret;
+	}
 
 	ret = __mux_control_select(mux, state);
 	if (ret >= 0)
 		mux_control_delay(mux, delay_us);
 
-	if (ret < 0)
+	if (!mux->exclusive && ret < 0)
 		up(&mux->lock);
 
 	return ret;
@@ -428,14 +434,16 @@ int mux_control_try_select_delay(struct mux_control *mux, unsigned int state,
 {
 	int ret;
 
-	if (down_trylock(&mux->lock))
-		return -EBUSY;
+	if (!mux->exclusive) {
+		if (down_trylock(&mux->lock))
+			return -EBUSY;
+	}
 
 	ret = __mux_control_select(mux, state);
 	if (ret >= 0)
 		mux_control_delay(mux, delay_us);
 
-	if (ret < 0)
+	if (!mux->exclusive && ret < 0)
 		up(&mux->lock);
 
 	return ret;
@@ -479,6 +487,10 @@ int mux_control_deselect(struct mux_control *mux)
 {
 	int ret = 0;
 
+	/* exclusive mux control do not deselection */
+	if (mux->exclusive)
+		return -EINVAL;
+
 	if (mux->idle_state != MUX_IDLE_AS_IS &&
 	    mux->idle_state != mux->cached_state)
 		ret = mux_control_set(mux, mux->idle_state);
@@ -523,13 +535,15 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
  * @mux_name: The name identifying the mux-control.
  * @state: Pointer to where the requested state is returned, or NULL when
  *         the required multiplexer states are handled by other means.
+ * @get_type: Type of mux get, shared or exclusive
  *
  * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
  */
 static struct mux_control *mux_get(struct device *dev, const char *mux_name,
-				   unsigned int *state)
+				   unsigned int *state, enum mux_control_get_type get_type)
 {
 	struct device_node *np = dev->of_node;
+	struct mux_control *mux_ctrl;
 	struct of_phandle_args args;
 	struct mux_chip *mux_chip;
 	unsigned int controller;
@@ -606,7 +620,25 @@ static struct mux_control *mux_get(struct device *dev, const char *mux_name,
 		return ERR_PTR(-EINVAL);
 	}
 
-	return &mux_chip->mux[controller];
+	mux_ctrl = &mux_chip->mux[controller];
+
+	if (mux_ctrl->exclusive) {
+		mux_ctrl = ERR_PTR(-EPERM);
+		put_device(&mux_chip->dev);
+		return mux_ctrl;
+	}
+
+	if (get_type == EXCLUSIVE_GET && mux_ctrl->open_count) {
+		mux_ctrl = ERR_PTR(-EBUSY);
+		put_device(&mux_chip->dev);
+		return mux_ctrl;
+	}
+
+	mux_ctrl->open_count++;
+	if (get_type == EXCLUSIVE_GET)
+		mux_ctrl->exclusive = true;
+
+	return mux_ctrl;
 }
 
 /**
@@ -618,10 +650,33 @@ static struct mux_control *mux_get(struct device *dev, const char *mux_name,
  */
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 {
-	return mux_get(dev, mux_name, NULL);
+	return mux_get(dev, mux_name, NULL, NORMAL_GET);
 }
 EXPORT_SYMBOL_GPL(mux_control_get);
 
+/**
+ * mux_control_get_exclusive() - Get the mux-control exclusive access for a device.
+ * @dev: The device that needs a exclusive mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Other consumers will be unable to obtain this mux-control while this
+ * reference is held and the use count for the mux-control will be
+ * initialised to reflect the current state of the mux-control.
+ *
+ * This is intended for use by consumers which do not need mux shared
+ * mux-control, and need exclusive control of mux.
+ * exclusive mux controls do not need mux_control_deselect() before
+ * selecting a mux state. Any mux state can be selected directly
+ * by calling mux_control_select() as long as state is supported.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get_exclusive(struct device *dev, const char *mux_name)
+{
+	return mux_get(dev, mux_name, NULL, EXCLUSIVE_GET);
+}
+EXPORT_SYMBOL_GPL(mux_control_get_exclusive);
+
 /**
  * mux_control_put() - Put away the mux-control for good.
  * @mux: The mux-control to put away.
@@ -630,6 +685,8 @@ EXPORT_SYMBOL_GPL(mux_control_get);
  */
 void mux_control_put(struct mux_control *mux)
 {
+	mux->open_count--;
+	mux->exclusive = false;
 	put_device(&mux->chip->dev);
 }
 EXPORT_SYMBOL_GPL(mux_control_put);
@@ -641,16 +698,8 @@ static void devm_mux_control_release(struct device *dev, void *res)
 	mux_control_put(mux);
 }
 
-/**
- * devm_mux_control_get() - Get the mux-control for a device, with resource
- *			    management.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *devm_mux_control_get(struct device *dev,
-					 const char *mux_name)
+static struct mux_control *__devm_mux_control_get(struct device *dev, const char *mux_name,
+						  enum mux_control_get_type type)
 {
 	struct mux_control **ptr, *mux;
 
@@ -658,7 +707,10 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 	if (!ptr)
 		return ERR_PTR(-ENOMEM);
 
-	mux = mux_control_get(dev, mux_name);
+	if (type == EXCLUSIVE_GET)
+		mux = mux_control_get_exclusive(dev, mux_name);
+	else
+		mux = mux_control_get(dev, mux_name);
 	if (IS_ERR(mux)) {
 		devres_free(ptr);
 		return mux;
@@ -669,8 +721,35 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 
 	return mux;
 }
+
+/**
+ * devm_mux_control_get() - Get the mux-control for a device, with resource
+ *			    management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get(struct device *dev, const char *mux_name)
+{
+	return __devm_mux_control_get(dev, mux_name, NORMAL_GET);
+}
 EXPORT_SYMBOL_GPL(devm_mux_control_get);
 
+/**
+ * devm_mux_control_get_exclusive() - Get the mux-control exclusive for a device,
+ * 				 with resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get_exclusive(struct device *dev, const char *mux_name)
+{
+	return __devm_mux_control_get(dev, mux_name, EXCLUSIVE_GET);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_exclusive);
+
 /*
  * mux_state_get() - Get the mux-state for a device.
  * @dev: The device that needs a mux-state.
@@ -686,7 +765,7 @@ static struct mux_state *mux_state_get(struct device *dev, const char *mux_name)
 	if (!mstate)
 		return ERR_PTR(-ENOMEM);
 
-	mstate->mux = mux_get(dev, mux_name, &mstate->state);
+	mstate->mux = mux_get(dev, mux_name, &mstate->state, NORMAL_GET);
 	if (IS_ERR(mstate->mux)) {
 		int err = PTR_ERR(mstate->mux);
 
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index 2e25c838f831..649b86c74bf3 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -54,8 +54,11 @@ int mux_control_deselect(struct mux_control *mux);
 int mux_state_deselect(struct mux_state *mstate);
 
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
+struct mux_control *mux_control_get_exclusive(struct device *dev, const char *mux_name);
 void mux_control_put(struct mux_control *mux);
 
+struct mux_control *devm_mux_control_get_exclusive(struct device *dev,
+					 const char *mux_name);
 struct mux_control *devm_mux_control_get(struct device *dev,
 					 const char *mux_name);
 struct mux_state *devm_mux_state_get(struct device *dev,
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 18824064f8c0..cda75b9b4775 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -26,6 +26,12 @@ struct mux_control_ops {
 	int (*set)(struct mux_control *mux, int state);
 };
 
+enum mux_control_get_type {
+	NORMAL_GET, /*  Shared */
+	EXCLUSIVE_GET,
+	MAX_GET_TYPE
+};
+
 /**
  * struct mux_control -	Represents a mux controller.
  * @lock:		Protects the mux controller state.
@@ -34,6 +40,7 @@ struct mux_control_ops {
  * @states:		The number of mux controller states.
  * @idle_state:		The mux controller state to use when inactive, or one
  *			of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
+ * @type:		Indicate type of mux control, Shared or Exclusive
  * @last_change:	Timestamp of last change
  *
  * Mux drivers may only change @states and @idle_state, and may only do so
@@ -50,6 +57,8 @@ struct mux_control {
 	unsigned int states;
 	int idle_state;
 
+	int open_count;
+	bool exclusive;
 	ktime_t last_change;
 };
 
-- 
2.39.5


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ