* [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters
@ 2026-08-23 16:34 Ahmad Byagowi
2026-08-23 16:34 ` [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure Ahmad Byagowi
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Ahmad Byagowi @ 2026-08-23 16:34 UTC (permalink / raw)
To: Andi Shyti
Cc: Peter Rosin, Jakub Kicinski, linux-i2c, linux-kernel,
Ahmad Byagowi
Device Tree channel nodes are associated with the adapters created by
i2c-mux, but equivalent software-node descriptions are not. Use generic
firmware-node operations for the channel lookup so child I2C devices can be
instantiated from software-node properties.
This is the I2C prerequisite split out of the Time Card series. The first
patch fixes the existing Device Tree channel-node leak on adapter-add
failure. The second factors the Device Tree lookup into a helper without
changing behavior. The third converts that helper and the node lifetime
handling to generic firmware-node operations.
The dependent ptp_ocp board profiles will be resent to net-next after the
LED and I2C prerequisites land.
---
Changes since v6:
- Split the existing Device Tree leak fix into its own patch.
- Add a preparatory patch that only factors out the OF lookup.
- Convert the helper to generic firmware-node operations in the final
patch.
- Drop the separate private software-node pointer and use the adapter's
firmware node for cleanup.
- Save the firmware node before adapter deletion, then release it
afterwards following the i2c-atr lifetime pattern.
- Rebase onto the current I2C i2c-next branch.
Validation:
- git diff --check
- strict checkpatch
- x86-64 Clang syntax check
v6: https://lore.kernel.org/r/eb4a8ab1eedd8a01ca34c6a7e0685639d0498423.1787247467.git.ahmadexp@gmail.com/
Ahmad Byagowi (3):
i2c: mux: Fix channel node leak on adapter add failure
i2c: mux: Factor out channel node lookup
i2c: mux: Propagate software nodes to channel adapters
drivers/i2c/i2c-mux.c | 96 +++++++++++++++++++++++--------------------
1 file changed, 52 insertions(+), 44 deletions(-)
base-commit: cd5fec79af3fa04e88e5900cdfa56d5525f5740b
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure 2026-08-23 16:34 [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi @ 2026-08-23 16:34 ` Ahmad Byagowi 2026-08-25 5:49 ` Peter Rosin 2026-08-23 16:34 ` [PATCH v7 2/3] i2c: mux: Factor out channel node lookup Ahmad Byagowi ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: Ahmad Byagowi @ 2026-08-23 16:34 UTC (permalink / raw) To: Andi Shyti Cc: Peter Rosin, Jakub Kicinski, linux-i2c, linux-kernel, Ahmad Byagowi i2c_mux_add_adapter() takes a reference to the Device Tree channel node before registering the new adapter. If adapter registration fails, the error path frees the private data without dropping that reference. Release the channel node before freeing the private data. Fixes: bc45449b1444 ("i2c/of: Automatically populate i2c mux busses from device tree data.") Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> --- drivers/i2c/i2c-mux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 681a201c239b..68a4c34b5987 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -408,6 +408,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, return 0; err_free_priv: + of_node_put(priv->adap.dev.of_node); kfree(priv); return ret; } -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure 2026-08-23 16:34 ` [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure Ahmad Byagowi @ 2026-08-25 5:49 ` Peter Rosin 0 siblings, 0 replies; 9+ messages in thread From: Peter Rosin @ 2026-08-25 5:49 UTC (permalink / raw) To: Ahmad Byagowi; +Cc: Andi Shyti, Jakub Kicinski, linux-i2c, linux-kernel Den Sun, Aug 23, 2026 at 09:34:36AM -0700, skrev Ahmad Byagowi: > i2c_mux_add_adapter() takes a reference to the Device Tree channel node > before registering the new adapter. If adapter registration fails, the > error path frees the private data without dropping that reference. > > Release the channel node before freeing the private data. > > Fixes: bc45449b1444 ("i2c/of: Automatically populate i2c mux busses from device tree data.") > Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> Acked-by: Peter Rosin <peda@lysator.liu.se> Cheers, Peter > --- > drivers/i2c/i2c-mux.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c > index 681a201c239b..68a4c34b5987 100644 > --- a/drivers/i2c/i2c-mux.c > +++ b/drivers/i2c/i2c-mux.c > @@ -408,6 +408,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, > return 0; > > err_free_priv: > + of_node_put(priv->adap.dev.of_node); > kfree(priv); > return ret; > } > -- > 2.50.1 (Apple Git-155) > ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v7 2/3] i2c: mux: Factor out channel node lookup 2026-08-23 16:34 [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi 2026-08-23 16:34 ` [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure Ahmad Byagowi @ 2026-08-23 16:34 ` Ahmad Byagowi 2026-08-25 5:50 ` Peter Rosin 2026-08-23 16:34 ` [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi 2026-08-26 13:45 ` [PATCH v7 0/3] " Andi Shyti 3 siblings, 1 reply; 9+ messages in thread From: Ahmad Byagowi @ 2026-08-23 16:34 UTC (permalink / raw) To: Andi Shyti Cc: Peter Rosin, Jakub Kicinski, linux-i2c, linux-kernel, Ahmad Byagowi Move the existing Device Tree channel-node lookup into a helper in preparation for using generic firmware-node operations. This is a pure refactoring with no functional change. Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> --- drivers/i2c/i2c-mux.c | 84 +++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 68a4c34b5987..a8b94b97a725 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -264,6 +264,51 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { .unlock_bus = i2c_parent_unlock_bus, }; +static struct device_node * +i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) +{ + struct device_node *dev_node = muxc->dev->of_node; + struct device_node *mux_node, *child = NULL; + u32 reg; + int ret; + + if (!dev_node) + return NULL; + + if (muxc->arbitrator) + mux_node = of_get_child_by_name(dev_node, "i2c-arb"); + else if (muxc->gate) + mux_node = of_get_child_by_name(dev_node, "i2c-gate"); + else + mux_node = of_get_child_by_name(dev_node, "i2c-mux"); + + if (mux_node) { + /* A "reg" property indicates an old-style DT entry */ + if (!of_property_read_u32(mux_node, "reg", ®)) { + of_node_put(mux_node); + mux_node = NULL; + } + } + + if (!mux_node) + mux_node = of_node_get(dev_node); + else if (muxc->arbitrator || muxc->gate) + child = of_node_get(mux_node); + + if (!child) { + for_each_child_of_node(mux_node, child) { + ret = of_property_read_u32(child, "reg", ®); + if (ret) + continue; + if (chan_id == reg) + break; + } + } + + of_node_put(mux_node); + return child; +} + int i2c_mux_add_adapter(struct i2c_mux_core *muxc, u32 force_nr, u32 chan_id) { @@ -327,44 +372,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, * Try to populate the mux adapter's of_node, expands to * nothing if !CONFIG_OF. */ - if (muxc->dev->of_node) { - struct device_node *dev_node = muxc->dev->of_node; - struct device_node *mux_node, *child = NULL; - u32 reg; - - if (muxc->arbitrator) - mux_node = of_get_child_by_name(dev_node, "i2c-arb"); - else if (muxc->gate) - mux_node = of_get_child_by_name(dev_node, "i2c-gate"); - else - mux_node = of_get_child_by_name(dev_node, "i2c-mux"); - - if (mux_node) { - /* A "reg" property indicates an old-style DT entry */ - if (!of_property_read_u32(mux_node, "reg", ®)) { - of_node_put(mux_node); - mux_node = NULL; - } - } - - if (!mux_node) - mux_node = of_node_get(dev_node); - else if (muxc->arbitrator || muxc->gate) - child = of_node_get(mux_node); - - if (!child) { - for_each_child_of_node(mux_node, child) { - ret = of_property_read_u32(child, "reg", ®); - if (ret) - continue; - if (chan_id == reg) - break; - } - } - - priv->adap.dev.of_node = child; - of_node_put(mux_node); - } + priv->adap.dev.of_node = i2c_mux_get_channel_node(muxc, chan_id); /* * Associate the mux channel with an ACPI node. -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v7 2/3] i2c: mux: Factor out channel node lookup 2026-08-23 16:34 ` [PATCH v7 2/3] i2c: mux: Factor out channel node lookup Ahmad Byagowi @ 2026-08-25 5:50 ` Peter Rosin 0 siblings, 0 replies; 9+ messages in thread From: Peter Rosin @ 2026-08-25 5:50 UTC (permalink / raw) To: Ahmad Byagowi; +Cc: Andi Shyti, Jakub Kicinski, linux-i2c, linux-kernel Hi! Den Sun, Aug 23, 2026 at 09:34:37AM -0700, skrev Ahmad Byagowi: > Move the existing Device Tree channel-node lookup into a helper in > preparation for using generic firmware-node operations. > > This is a pure refactoring with no functional change. > > Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> > --- > drivers/i2c/i2c-mux.c | 84 +++++++++++++++++++++++-------------------- > 1 file changed, 46 insertions(+), 38 deletions(-) > > diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c > index 68a4c34b5987..a8b94b97a725 100644 > --- a/drivers/i2c/i2c-mux.c > +++ b/drivers/i2c/i2c-mux.c > @@ -264,6 +264,51 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { > .unlock_bus = i2c_parent_unlock_bus, > }; > > +static struct device_node * > +i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) > +{ > + struct device_node *dev_node = muxc->dev->of_node; > + struct device_node *mux_node, *child = NULL; > + u32 reg; > + int ret; > + > + if (!dev_node) > + return NULL; > + > + if (muxc->arbitrator) > + mux_node = of_get_child_by_name(dev_node, "i2c-arb"); > + else if (muxc->gate) > + mux_node = of_get_child_by_name(dev_node, "i2c-gate"); > + else > + mux_node = of_get_child_by_name(dev_node, "i2c-mux"); > + > + if (mux_node) { > + /* A "reg" property indicates an old-style DT entry */ > + if (!of_property_read_u32(mux_node, "reg", ®)) { > + of_node_put(mux_node); > + mux_node = NULL; > + } > + } > + > + if (!mux_node) > + mux_node = of_node_get(dev_node); > + else if (muxc->arbitrator || muxc->gate) > + child = of_node_get(mux_node); You can return early here with "return mux_node;" (which also obviates the need for the above " = NULL"-initializer and the below "if (!child)"-test). Cheers, Peter > + > + if (!child) { > + for_each_child_of_node(mux_node, child) { > + ret = of_property_read_u32(child, "reg", ®); > + if (ret) > + continue; > + if (chan_id == reg) > + break; > + } > + } > + > + of_node_put(mux_node); > + return child; > +} > + > int i2c_mux_add_adapter(struct i2c_mux_core *muxc, > u32 force_nr, u32 chan_id) > { > @@ -327,44 +372,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, > * Try to populate the mux adapter's of_node, expands to > * nothing if !CONFIG_OF. > */ > - if (muxc->dev->of_node) { > - struct device_node *dev_node = muxc->dev->of_node; > - struct device_node *mux_node, *child = NULL; > - u32 reg; > - > - if (muxc->arbitrator) > - mux_node = of_get_child_by_name(dev_node, "i2c-arb"); > - else if (muxc->gate) > - mux_node = of_get_child_by_name(dev_node, "i2c-gate"); > - else > - mux_node = of_get_child_by_name(dev_node, "i2c-mux"); > - > - if (mux_node) { > - /* A "reg" property indicates an old-style DT entry */ > - if (!of_property_read_u32(mux_node, "reg", ®)) { > - of_node_put(mux_node); > - mux_node = NULL; > - } > - } > - > - if (!mux_node) > - mux_node = of_node_get(dev_node); > - else if (muxc->arbitrator || muxc->gate) > - child = of_node_get(mux_node); > - > - if (!child) { > - for_each_child_of_node(mux_node, child) { > - ret = of_property_read_u32(child, "reg", ®); > - if (ret) > - continue; > - if (chan_id == reg) > - break; > - } > - } > - > - priv->adap.dev.of_node = child; > - of_node_put(mux_node); > - } > + priv->adap.dev.of_node = i2c_mux_get_channel_node(muxc, chan_id); > > /* > * Associate the mux channel with an ACPI node. > -- > 2.50.1 (Apple Git-155) > ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters 2026-08-23 16:34 [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi 2026-08-23 16:34 ` [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure Ahmad Byagowi 2026-08-23 16:34 ` [PATCH v7 2/3] i2c: mux: Factor out channel node lookup Ahmad Byagowi @ 2026-08-23 16:34 ` Ahmad Byagowi 2026-08-25 5:50 ` Peter Rosin 2026-08-26 13:45 ` [PATCH v7 0/3] " Andi Shyti 3 siblings, 1 reply; 9+ messages in thread From: Ahmad Byagowi @ 2026-08-23 16:34 UTC (permalink / raw) To: Andi Shyti Cc: Peter Rosin, Jakub Kicinski, linux-i2c, linux-kernel, Ahmad Byagowi Device Tree channel nodes are associated with the adapters created by i2c-mux, but equivalent software-node descriptions are not. Use generic firmware-node operations for the existing channel lookup and accept either an OF node or a software node. Associate the returned node with the adapter so child I2C devices can be instantiated from software-node properties. Save the adapter firmware node before adapter deletion and release the reference afterwards, following the lifetime pattern in i2c-atr. Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> --- drivers/i2c/i2c-mux.c | 45 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index a8b94b97a725..b37d36d3b121 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/sysfs.h> @@ -264,40 +265,40 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { .unlock_bus = i2c_parent_unlock_bus, }; -static struct device_node * +static struct fwnode_handle * i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) { - struct device_node *dev_node = muxc->dev->of_node; - struct device_node *mux_node, *child = NULL; + struct fwnode_handle *dev_node = dev_fwnode(muxc->dev); + struct fwnode_handle *mux_node, *child = NULL; u32 reg; int ret; - if (!dev_node) + if (!is_of_node(dev_node) && !is_software_node(dev_node)) return NULL; if (muxc->arbitrator) - mux_node = of_get_child_by_name(dev_node, "i2c-arb"); + mux_node = fwnode_get_named_child_node(dev_node, "i2c-arb"); else if (muxc->gate) - mux_node = of_get_child_by_name(dev_node, "i2c-gate"); + mux_node = fwnode_get_named_child_node(dev_node, "i2c-gate"); else - mux_node = of_get_child_by_name(dev_node, "i2c-mux"); + mux_node = fwnode_get_named_child_node(dev_node, "i2c-mux"); if (mux_node) { - /* A "reg" property indicates an old-style DT entry */ - if (!of_property_read_u32(mux_node, "reg", ®)) { - of_node_put(mux_node); + /* A "reg" property indicates an old-style firmware entry. */ + if (!fwnode_property_read_u32(mux_node, "reg", ®)) { + fwnode_handle_put(mux_node); mux_node = NULL; } } if (!mux_node) - mux_node = of_node_get(dev_node); + mux_node = fwnode_handle_get(dev_node); else if (muxc->arbitrator || muxc->gate) - child = of_node_get(mux_node); + child = fwnode_handle_get(mux_node); if (!child) { - for_each_child_of_node(mux_node, child) { - ret = of_property_read_u32(child, "reg", ®); + fwnode_for_each_child_node(mux_node, child) { + ret = fwnode_property_read_u32(child, "reg", ®); if (ret) continue; if (chan_id == reg) @@ -305,7 +306,7 @@ i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) } } - of_node_put(mux_node); + fwnode_handle_put(mux_node); return child; } @@ -368,11 +369,9 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, else priv->adap.lock_ops = &i2c_parent_lock_ops; - /* - * Try to populate the mux adapter's of_node, expands to - * nothing if !CONFIG_OF. - */ - priv->adap.dev.of_node = i2c_mux_get_channel_node(muxc, chan_id); + /* Associate the mux adapter with its OF or software-node channel. */ + device_set_node(&priv->adap.dev, + i2c_mux_get_channel_node(muxc, chan_id)); /* * Associate the mux channel with an ACPI node. @@ -416,7 +415,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, return 0; err_free_priv: - of_node_put(priv->adap.dev.of_node); + fwnode_handle_put(dev_fwnode(&priv->adap.dev)); kfree(priv); return ret; } @@ -429,7 +428,7 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) while (muxc->num_adapters) { struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters]; struct i2c_mux_priv *priv = adap->algo_data; - struct device_node *np = adap->dev.of_node; + struct fwnode_handle *fwnode = dev_fwnode(&adap->dev); muxc->adapter[muxc->num_adapters] = NULL; @@ -439,7 +438,7 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) sysfs_remove_link(&priv->adap.dev.kobj, "mux_device"); i2c_del_adapter(adap); - of_node_put(np); + fwnode_handle_put(fwnode); kfree(priv); } } -- 2.50.1 (Apple Git-155) ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters 2026-08-23 16:34 ` [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi @ 2026-08-25 5:50 ` Peter Rosin [not found] ` <CAOQiBWNVvHpO7X8yWyZEa3-nV76YJfRbkzo+_4U-upEj4VNfow@mail.gmail.com> 0 siblings, 1 reply; 9+ messages in thread From: Peter Rosin @ 2026-08-25 5:50 UTC (permalink / raw) To: Ahmad Byagowi, Andy Shevchenko Cc: Andi Shyti, Jakub Kicinski, linux-i2c, linux-kernel Hi! [Adding Andy] Den Sun, Aug 23, 2026 at 09:34:38AM -0700, skrev Ahmad Byagowi: > Device Tree channel nodes are associated with the adapters created by > i2c-mux, but equivalent software-node descriptions are not. > > Use generic firmware-node operations for the existing channel lookup and > accept either an OF node or a software node. Associate the returned node > with the adapter so child I2C devices can be instantiated from > software-node properties. > > Save the adapter firmware node before adapter deletion and release the > reference afterwards, following the lifetime pattern in i2c-atr. > > Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> > --- > drivers/i2c/i2c-mux.c | 45 +++++++++++++++++++++---------------------- > 1 file changed, 22 insertions(+), 23 deletions(-) > > diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c > index a8b94b97a725..b37d36d3b121 100644 > --- a/drivers/i2c/i2c-mux.c > +++ b/drivers/i2c/i2c-mux.c > @@ -25,6 +25,7 @@ > #include <linux/kernel.h> > #include <linux/module.h> > #include <linux/of.h> > +#include <linux/property.h> > #include <linux/slab.h> > #include <linux/sysfs.h> > > @@ -264,40 +265,40 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { > .unlock_bus = i2c_parent_unlock_bus, > }; > > -static struct device_node * > +static struct fwnode_handle * > i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) > { > - struct device_node *dev_node = muxc->dev->of_node; > - struct device_node *mux_node, *child = NULL; > + struct fwnode_handle *dev_node = dev_fwnode(muxc->dev); > + struct fwnode_handle *mux_node, *child = NULL; > u32 reg; > int ret; > > - if (!dev_node) > + if (!is_of_node(dev_node) && !is_software_node(dev_node)) > return NULL; I wonder if this is needed? Andy, I seem to recall that you were involved with adding ACPI support? Do you have anything to add? Cheers, Peter > > if (muxc->arbitrator) > - mux_node = of_get_child_by_name(dev_node, "i2c-arb"); > + mux_node = fwnode_get_named_child_node(dev_node, "i2c-arb"); > else if (muxc->gate) > - mux_node = of_get_child_by_name(dev_node, "i2c-gate"); > + mux_node = fwnode_get_named_child_node(dev_node, "i2c-gate"); > else > - mux_node = of_get_child_by_name(dev_node, "i2c-mux"); > + mux_node = fwnode_get_named_child_node(dev_node, "i2c-mux"); > > if (mux_node) { > - /* A "reg" property indicates an old-style DT entry */ > - if (!of_property_read_u32(mux_node, "reg", ®)) { > - of_node_put(mux_node); > + /* A "reg" property indicates an old-style firmware entry. */ > + if (!fwnode_property_read_u32(mux_node, "reg", ®)) { > + fwnode_handle_put(mux_node); > mux_node = NULL; > } > } > > if (!mux_node) > - mux_node = of_node_get(dev_node); > + mux_node = fwnode_handle_get(dev_node); > else if (muxc->arbitrator || muxc->gate) > - child = of_node_get(mux_node); > + child = fwnode_handle_get(mux_node); > > if (!child) { > - for_each_child_of_node(mux_node, child) { > - ret = of_property_read_u32(child, "reg", ®); > + fwnode_for_each_child_node(mux_node, child) { > + ret = fwnode_property_read_u32(child, "reg", ®); > if (ret) > continue; > if (chan_id == reg) > @@ -305,7 +306,7 @@ i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) > } > } > > - of_node_put(mux_node); > + fwnode_handle_put(mux_node); > return child; > } > > @@ -368,11 +369,9 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, > else > priv->adap.lock_ops = &i2c_parent_lock_ops; > > - /* > - * Try to populate the mux adapter's of_node, expands to > - * nothing if !CONFIG_OF. > - */ > - priv->adap.dev.of_node = i2c_mux_get_channel_node(muxc, chan_id); > + /* Associate the mux adapter with its OF or software-node channel. */ > + device_set_node(&priv->adap.dev, > + i2c_mux_get_channel_node(muxc, chan_id)); > > /* > * Associate the mux channel with an ACPI node. > @@ -416,7 +415,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, > return 0; > > err_free_priv: > - of_node_put(priv->adap.dev.of_node); > + fwnode_handle_put(dev_fwnode(&priv->adap.dev)); > kfree(priv); > return ret; > } > @@ -429,7 +428,7 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) > while (muxc->num_adapters) { > struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters]; > struct i2c_mux_priv *priv = adap->algo_data; > - struct device_node *np = adap->dev.of_node; > + struct fwnode_handle *fwnode = dev_fwnode(&adap->dev); > > muxc->adapter[muxc->num_adapters] = NULL; > > @@ -439,7 +438,7 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) > > sysfs_remove_link(&priv->adap.dev.kobj, "mux_device"); > i2c_del_adapter(adap); > - of_node_put(np); > + fwnode_handle_put(fwnode); > kfree(priv); > } > } > -- > 2.50.1 (Apple Git-155) > ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <CAOQiBWNVvHpO7X8yWyZEa3-nV76YJfRbkzo+_4U-upEj4VNfow@mail.gmail.com>]
* Re: [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters [not found] ` <CAOQiBWNVvHpO7X8yWyZEa3-nV76YJfRbkzo+_4U-upEj4VNfow@mail.gmail.com> @ 2026-08-26 16:39 ` Ahmad Byagowi 0 siblings, 0 replies; 9+ messages in thread From: Ahmad Byagowi @ 2026-08-26 16:39 UTC (permalink / raw) To: Peter Rosin Cc: Andy Shevchenko, Andi Shyti, Jakub Kicinski, linux-i2c, linux-kernel Resending in plain text because my previous reply was rejected by the mailing lists. Hi Peter, Andy, Yes, software-node handling is needed for the ptp_ocp use case. ptp_ocp is a PCI driver. It creates its board-specific I2C topology at runtime with software nodes: the mux, its channel nodes, sensors, and LED controller. Firmware does not provide ACPI nodes for this topology. The existing acpi_preset_companion() path only associates a mux adapter with an existing ACPI child. It does not associate the adapter with one of these dynamically created software-node channel nodes. Without that association, i2c_get_adapter_by_fwnode() cannot find the channel adapter by the channel software node, so ptp_ocp cannot instantiate the downstream I2C devices on the correct channel. Does this address the concern, or would you prefer a different way to represent this dynamically created topology? Thanks, Andi, for taking the first patch into i2c/i2c-fixes. I will drop it from the next revision and rebase the remaining two patches once this question is resolved. Thanks, Ahmad On Wed, Aug 26, 2026 at 8:29 AM Ahmad Byagowi <ahmadexp@gmail.com> wrote: > > Hi Peter, Andy, > > Yes, software-node handling is needed for the ptp_ocp use case. > > ptp_ocp is a PCI driver. It creates its board-specific I2C topology at runtime with software nodes: the mux, its channel nodes, sensors, and LED controller. Firmware does not provide ACPI nodes for this topology. > > The existing acpi_preset_companion() path only associates a mux adapter with an existing ACPI child. It does not associate the adapter with one of these dynamically created software-node channel nodes. Without that association, i2c_get_adapter_by_fwnode() cannot find the channel adapter by the channel software node, so ptp_ocp cannot instantiate the downstream I2C devices on the correct channel. > > Does this address the concern, or would you prefer a different way to represent this dynamically created topology? > > Thanks, Andi, for taking the first patch into i2c/i2c-fixes. I will drop it from the next revision and rebase the remaining two patches once this question is resolved. > > Thanks, > Ahmad > > On Mon, Aug 24, 2026 at 10:50 PM Peter Rosin <peda@lysator.liu.se> wrote: >> >> Hi! >> >> [Adding Andy] >> >> Den Sun, Aug 23, 2026 at 09:34:38AM -0700, skrev Ahmad Byagowi: >> > Device Tree channel nodes are associated with the adapters created by >> > i2c-mux, but equivalent software-node descriptions are not. >> > >> > Use generic firmware-node operations for the existing channel lookup and >> > accept either an OF node or a software node. Associate the returned node >> > with the adapter so child I2C devices can be instantiated from >> > software-node properties. >> > >> > Save the adapter firmware node before adapter deletion and release the >> > reference afterwards, following the lifetime pattern in i2c-atr. >> > >> > Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com> >> > --- >> > drivers/i2c/i2c-mux.c | 45 +++++++++++++++++++++---------------------- >> > 1 file changed, 22 insertions(+), 23 deletions(-) >> > >> > diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c >> > index a8b94b97a725..b37d36d3b121 100644 >> > --- a/drivers/i2c/i2c-mux.c >> > +++ b/drivers/i2c/i2c-mux.c >> > @@ -25,6 +25,7 @@ >> > #include <linux/kernel.h> >> > #include <linux/module.h> >> > #include <linux/of.h> >> > +#include <linux/property.h> >> > #include <linux/slab.h> >> > #include <linux/sysfs.h> >> > >> > @@ -264,40 +265,40 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { >> > .unlock_bus = i2c_parent_unlock_bus, >> > }; >> > >> > -static struct device_node * >> > +static struct fwnode_handle * >> > i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) >> > { >> > - struct device_node *dev_node = muxc->dev->of_node; >> > - struct device_node *mux_node, *child = NULL; >> > + struct fwnode_handle *dev_node = dev_fwnode(muxc->dev); >> > + struct fwnode_handle *mux_node, *child = NULL; >> > u32 reg; >> > int ret; >> > >> > - if (!dev_node) >> > + if (!is_of_node(dev_node) && !is_software_node(dev_node)) >> > return NULL; >> >> I wonder if this is needed? Andy, I seem to recall that you were >> involved with adding ACPI support? Do you have anything to add? >> >> Cheers, >> Peter >> >> > >> > if (muxc->arbitrator) >> > - mux_node = of_get_child_by_name(dev_node, "i2c-arb"); >> > + mux_node = fwnode_get_named_child_node(dev_node, "i2c-arb"); >> > else if (muxc->gate) >> > - mux_node = of_get_child_by_name(dev_node, "i2c-gate"); >> > + mux_node = fwnode_get_named_child_node(dev_node, "i2c-gate"); >> > else >> > - mux_node = of_get_child_by_name(dev_node, "i2c-mux"); >> > + mux_node = fwnode_get_named_child_node(dev_node, "i2c-mux"); >> > >> > if (mux_node) { >> > - /* A "reg" property indicates an old-style DT entry */ >> > - if (!of_property_read_u32(mux_node, "reg", ®)) { >> > - of_node_put(mux_node); >> > + /* A "reg" property indicates an old-style firmware entry. */ >> > + if (!fwnode_property_read_u32(mux_node, "reg", ®)) { >> > + fwnode_handle_put(mux_node); >> > mux_node = NULL; >> > } >> > } >> > >> > if (!mux_node) >> > - mux_node = of_node_get(dev_node); >> > + mux_node = fwnode_handle_get(dev_node); >> > else if (muxc->arbitrator || muxc->gate) >> > - child = of_node_get(mux_node); >> > + child = fwnode_handle_get(mux_node); >> > >> > if (!child) { >> > - for_each_child_of_node(mux_node, child) { >> > - ret = of_property_read_u32(child, "reg", ®); >> > + fwnode_for_each_child_node(mux_node, child) { >> > + ret = fwnode_property_read_u32(child, "reg", ®); >> > if (ret) >> > continue; >> > if (chan_id == reg) >> > @@ -305,7 +306,7 @@ i2c_mux_get_channel_node(struct i2c_mux_core *muxc, u32 chan_id) >> > } >> > } >> > >> > - of_node_put(mux_node); >> > + fwnode_handle_put(mux_node); >> > return child; >> > } >> > >> > @@ -368,11 +369,9 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, >> > else >> > priv->adap.lock_ops = &i2c_parent_lock_ops; >> > >> > - /* >> > - * Try to populate the mux adapter's of_node, expands to >> > - * nothing if !CONFIG_OF. >> > - */ >> > - priv->adap.dev.of_node = i2c_mux_get_channel_node(muxc, chan_id); >> > + /* Associate the mux adapter with its OF or software-node channel. */ >> > + device_set_node(&priv->adap.dev, >> > + i2c_mux_get_channel_node(muxc, chan_id)); >> > >> > /* >> > * Associate the mux channel with an ACPI node. >> > @@ -416,7 +415,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, >> > return 0; >> > >> > err_free_priv: >> > - of_node_put(priv->adap.dev.of_node); >> > + fwnode_handle_put(dev_fwnode(&priv->adap.dev)); >> > kfree(priv); >> > return ret; >> > } >> > @@ -429,7 +428,7 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) >> > while (muxc->num_adapters) { >> > struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters]; >> > struct i2c_mux_priv *priv = adap->algo_data; >> > - struct device_node *np = adap->dev.of_node; >> > + struct fwnode_handle *fwnode = dev_fwnode(&adap->dev); >> > >> > muxc->adapter[muxc->num_adapters] = NULL; >> > >> > @@ -439,7 +438,7 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) >> > >> > sysfs_remove_link(&priv->adap.dev.kobj, "mux_device"); >> > i2c_del_adapter(adap); >> > - of_node_put(np); >> > + fwnode_handle_put(fwnode); >> > kfree(priv); >> > } >> > } >> > -- >> > 2.50.1 (Apple Git-155) >> > > > > > -- > 73 > With best wishes / Mit herzlichsten Grüßen > Ahmad Byagowi, Ph.D., Dr. Techn., P.Eng. > Phone: +1 (650) 924 6653 > > Please consider the environment before printing this e-mail. -- 73 With best wishes / Mit herzlichsten Grüßen Ahmad Byagowi, Ph.D., Dr. Techn., P.Eng. Phone: +1 (650) 924 6653 Please consider the environment before printing this e-mail. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters 2026-08-23 16:34 [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi ` (2 preceding siblings ...) 2026-08-23 16:34 ` [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi @ 2026-08-26 13:45 ` Andi Shyti 3 siblings, 0 replies; 9+ messages in thread From: Andi Shyti @ 2026-08-26 13:45 UTC (permalink / raw) To: Ahmad Byagowi; +Cc: Peter Rosin, Jakub Kicinski, linux-i2c, linux-kernel Hi Ahmad, > Ahmad Byagowi (3): > i2c: mux: Fix channel node leak on adapter add failure I merged this first patch into i2c/i2c-fixes, while... > i2c: mux: Factor out channel node lookup > i2c: mux: Propagate software nodes to channel adapters ... I left these out because there are some pending comments. Thanks, Andi ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-08-26 16:40 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-23 16:34 [PATCH v7 0/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi
2026-08-23 16:34 ` [PATCH v7 1/3] i2c: mux: Fix channel node leak on adapter add failure Ahmad Byagowi
2026-08-25 5:49 ` Peter Rosin
2026-08-23 16:34 ` [PATCH v7 2/3] i2c: mux: Factor out channel node lookup Ahmad Byagowi
2026-08-25 5:50 ` Peter Rosin
2026-08-23 16:34 ` [PATCH v7 3/3] i2c: mux: Propagate software nodes to channel adapters Ahmad Byagowi
2026-08-25 5:50 ` Peter Rosin
[not found] ` <CAOQiBWNVvHpO7X8yWyZEa3-nV76YJfRbkzo+_4U-upEj4VNfow@mail.gmail.com>
2026-08-26 16:39 ` Ahmad Byagowi
2026-08-26 13:45 ` [PATCH v7 0/3] " Andi Shyti
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox