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>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20230824121750.1673566-2-aniketmaurya@google.com>
Date:   Thu, 24 Aug 2023 12:17:49 +0000
From:   Aniket <aniketmaurya@...gle.com>
To:     Peter Rosin <peda@...ntia.se>
Cc:     linux-kernel@...r.kernel.org, joychakr@...gle.com,
        Aniket <aniketmaurya@...gle.com>
Subject: [PATCH v1 1/2] mux: Add support for handling array of mux-state

Sometimes consumer needs to manage a number of mux-
states, so it is easier if they can control it using
an array of such mux-states.
Add support to devm_get, select and deselect the array.

Signed-off-by: Aniket <aniketmaurya@...gle.com>
---
 drivers/mux/core.c           | 161 +++++++++++++++++++++++++++++++++--
 include/linux/mux/consumer.h |   7 ++
 2 files changed, 162 insertions(+), 6 deletions(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 990e7bc17c85..e4e57847e904 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -43,6 +43,16 @@ struct mux_state {
 	unsigned int state;
 };
 
+/**
+ * struct mux_state_array - Represents an array of mux states
+ * @num: number of mux state
+ * @mstate: array of mux states
+ */
+struct mux_state_array {
+	unsigned int num;
+	struct mux_state *mstate[];
+};
+
 static struct class mux_class = {
 	.name = "mux",
 };
@@ -408,6 +418,44 @@ int mux_state_select_delay(struct mux_state *mstate, unsigned int delay_us)
 }
 EXPORT_SYMBOL_GPL(mux_state_select_delay);
 
+/**
+ * mux_state_array_select() - Select the given multiplexer state.
+ * @mstates: The mux-state-array which contains multiple mux-state to select.
+ *
+ * On successfully selecting all the mux-states, their mux-control will be
+ * locked until there is a call to mux_state_array_deselect().
+ * If a mux-controls is already selected when mux_state_array_select() is
+ * called, then caller will be blocked.
+ *
+ * Therefore, make sure to call mux_state_array_deselect() when the operation
+ * is complete and the mux-state-array is free for others to use, but do not
+ * call mux_state_array_deselect() if mux_state_array_select() fails.
+ * If a mux_state_array_select() fails inbetween the already selected
+ * mux-states in the array are deselected.
+ *
+ * Return: 0 when the mux-state has been selected or a negative
+ * errno on error.
+ */
+int mux_state_array_select(struct mux_state_array *mstates)
+{
+	int ret, i;
+
+	for (i = 0; i < mstates->num; ++i) {
+		ret = mux_state_select(mstates->mstate[i]);
+		if (ret < 0)
+			goto err_mstates;
+	}
+
+	return 0;
+
+err_mstates:
+	while (--i >= 0)
+		mux_state_deselect(mstates->mstate[i]);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mux_state_array_select);
+
 /**
  * mux_control_try_select_delay() - Try to select the given multiplexer state.
  * @mux: The mux-control to request a change of state from.
@@ -508,6 +556,29 @@ int mux_state_deselect(struct mux_state *mstate)
 }
 EXPORT_SYMBOL_GPL(mux_state_deselect);
 
+/**
+ * mux_state_array_deselect() - Deselect the previously selected multiplexer state.
+ * @mstates: Array of mux-states to deselect.
+ *
+ * It is required that a single call is made to mux_state_array_deselect() for
+ * each and every successful call made to either of mux_state_array_select().
+ *
+ * Return: 0 on success and a negative errno on error.
+ */
+int mux_state_array_deselect(struct mux_state_array *mstates)
+{
+	int ret, i;
+
+	for (i = 0; i < mstates->num; ++i) {
+		ret = mux_state_deselect(mstates->mstate[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mux_state_array_deselect);
+
 /* Note this function returns a reference to the mux_chip dev. */
 static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
 {
@@ -522,19 +593,19 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
  * mux_get() - Get the mux-control for a device.
  * @dev: The device that needs a mux-control.
  * @mux_name: The name identifying the mux-control.
+ * @index: Index to identify mux-control if mux-name is NULL.
  * @state: Pointer to where the requested state is returned, or NULL when
  *         the required multiplexer states are handled by other means.
  *
  * 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)
+				   int index, unsigned int *state)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
 	struct mux_chip *mux_chip;
 	unsigned int controller;
-	int index = 0;
 	int ret;
 
 	if (mux_name) {
@@ -619,7 +690,7 @@ 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, 0, NULL);
 }
 EXPORT_SYMBOL_GPL(mux_control_get);
 
@@ -676,10 +747,12 @@ EXPORT_SYMBOL_GPL(devm_mux_control_get);
  * mux_state_get() - Get the mux-state for a device.
  * @dev: The device that needs a mux-state.
  * @mux_name: The name identifying the mux-state.
+ * @index: Index of the mux-state, to be used when mux-name is NULL
  *
  * Return: A pointer to the mux-state, or an ERR_PTR with a negative errno.
  */
-static struct mux_state *mux_state_get(struct device *dev, const char *mux_name)
+static struct mux_state *mux_state_get(struct device *dev, const char *mux_name,
+				       int index)
 {
 	struct mux_state *mstate;
 
@@ -687,7 +760,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, index, &mstate->state);
 	if (IS_ERR(mstate->mux)) {
 		int err = PTR_ERR(mstate->mux);
 
@@ -734,7 +807,7 @@ struct mux_state *devm_mux_state_get(struct device *dev,
 	if (!ptr)
 		return ERR_PTR(-ENOMEM);
 
-	mstate = mux_state_get(dev, mux_name);
+	mstate = mux_state_get(dev, mux_name, 0);
 	if (IS_ERR(mstate)) {
 		devres_free(ptr);
 		return mstate;
@@ -747,6 +820,82 @@ struct mux_state *devm_mux_state_get(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_mux_state_get);
 
+/*
+ * mux_state_array_get() - Get the all the mux-states for a device.
+ * @dev: The device that needs a mux-state.
+ *
+ * Return: A pointer to the mux-state, or an ERR_PTR with a negative errno.
+ */
+static struct mux_state_array *mux_state_array_get(struct device *dev)
+{
+	struct mux_state_array *mstates;
+	struct mux_state *mstate;
+	int num, i;
+
+	num = of_count_phandle_with_args(dev->of_node, "mux-states", "#mux-state-cells");
+	if (num < 0)
+		return ERR_PTR(num);
+
+	mstates = kzalloc(struct_size(mstates, mstate, num), GFP_KERNEL);
+	if (!mstates)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < num; i++) {
+		mstate = mux_state_get(dev, NULL, i);
+		if (IS_ERR(mstate))
+			goto err_mstates;
+		mstates->mstate[i] = mstate;
+	}
+	mstates->num = num;
+
+	return mstates;
+
+err_mstates:
+	while (--i >= 0)
+		mux_state_put(mstates->mstate[i]);
+	kfree(mstates);
+
+	return ERR_PTR(PTR_ERR(mstate));
+}
+
+static void devm_mux_state_array_release(struct device *dev, void *res)
+{
+	int i;
+	struct mux_state_array *mstates = *(struct mux_state_array **)res;
+
+	for (i = 0; i < mstates->num; i++)
+		mux_state_put(mstates->mstate[i]);
+	kfree(mstates);
+}
+
+/**
+ * devm_mux_state_array_get() - Get the all the mux-states for a device, with
+ * resource management.
+ * @dev: The device that needs a mux-control.
+ *
+ * Return: Pointer to the mux-state-array, or an ERR_PTR with a negative errno.
+ */
+struct mux_state_array *devm_mux_state_array_get(struct device *dev)
+{
+	struct mux_state_array **ptr, *mstates;
+
+	ptr = devres_alloc(devm_mux_state_array_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	mstates = mux_state_array_get(dev);
+	if (IS_ERR(mstates)) {
+		devres_free(ptr);
+		return mstates;
+	}
+
+	*ptr = mstates;
+	devres_add(dev, ptr);
+
+	return mstates;
+}
+EXPORT_SYMBOL_GPL(devm_mux_state_array_get);
+
 /*
  * Using subsys_initcall instead of module_init here to try to ensure - for
  * the non-modular case - that the subsystem is initialized when mux consumers
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index 2e25c838f831..da15d0542008 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -15,6 +15,7 @@
 struct device;
 struct mux_control;
 struct mux_state;
+struct mux_state_array;
 
 unsigned int mux_control_states(struct mux_control *mux);
 int __must_check mux_control_select_delay(struct mux_control *mux,
@@ -39,6 +40,8 @@ static inline int __must_check mux_state_select(struct mux_state *mstate)
 	return mux_state_select_delay(mstate, 0);
 }
 
+int mux_state_array_select(struct mux_state_array *mstates);
+
 static inline int __must_check mux_control_try_select(struct mux_control *mux,
 						      unsigned int state)
 {
@@ -53,6 +56,8 @@ static inline int __must_check mux_state_try_select(struct mux_state *mstate)
 int mux_control_deselect(struct mux_control *mux);
 int mux_state_deselect(struct mux_state *mstate);
 
+int mux_state_array_deselect(struct mux_state_array *mstates);
+
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
 void mux_control_put(struct mux_control *mux);
 
@@ -61,4 +66,6 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 struct mux_state *devm_mux_state_get(struct device *dev,
 				     const char *mux_name);
 
+struct mux_state_array *devm_mux_state_array_get(struct device *dev);
+
 #endif /* _LINUX_MUX_CONSUMER_H */
-- 
2.42.0.rc1.204.g551eb34607-goog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ