]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Apr 2026 23:36:51 +0000 (17:36 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Apr 2026 23:36:51 +0000 (17:36 -0600)
added patches:
device-property-make-modifications-of-fwnode-flags-thread-safe.patch

queue-6.1/device-property-make-modifications-of-fwnode-flags-thread-safe.patch [new file with mode: 0644]
queue-6.1/series

diff --git a/queue-6.1/device-property-make-modifications-of-fwnode-flags-thread-safe.patch b/queue-6.1/device-property-make-modifications-of-fwnode-flags-thread-safe.patch
new file mode 100644 (file)
index 0000000..c02c0e2
--- /dev/null
@@ -0,0 +1,313 @@
+From f72e77c33e4b5657af35125e75bab249256030f3 Mon Sep 17 00:00:00 2001
+From: Douglas Anderson <dianders@chromium.org>
+Date: Tue, 17 Mar 2026 09:01:20 -0700
+Subject: device property: Make modifications of fwnode "flags" thread safe
+
+From: Douglas Anderson <dianders@chromium.org>
+
+commit f72e77c33e4b5657af35125e75bab249256030f3 upstream.
+
+In various places in the kernel, we modify the fwnode "flags" member
+by doing either:
+  fwnode->flags |= SOME_FLAG;
+  fwnode->flags &= ~SOME_FLAG;
+
+This type of modification is not thread-safe. If two threads are both
+mucking with the flags at the same time then one can clobber the
+other.
+
+While flags are often modified while under the "fwnode_link_lock",
+this is not universally true.
+
+Create some accessor functions for setting, clearing, and testing the
+FWNODE flags and move all users to these accessor functions. New
+accessor functions use set_bit() and clear_bit(), which are
+thread-safe.
+
+Cc: stable@vger.kernel.org
+Fixes: c2c724c868c4 ("driver core: Add fw_devlink_parse_fwtree()")
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Acked-by: Mark Brown <broonie@kernel.org>
+Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
+Reviewed-by: Saravana Kannan <saravanak@kernel.org>
+Link: https://patch.msgid.link/20260317090112.v2.1.I0a4d03104ecd5103df3d76f66c8d21b1d15a2e38@changeid
+[ Fix fwnode_clear_flag() argument alignment, restore dropped blank
+  line in fwnode_dev_initialized(), and remove unnecessary parentheses
+  around fwnode_test_flag() calls. - Danilo ]
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/base/core.c        |   24 ++++++++++++------------
+ drivers/bus/imx-weim.c     |    2 +-
+ drivers/i2c/i2c-core-of.c  |    2 +-
+ drivers/net/phy/mdio_bus.c |    4 ++--
+ drivers/of/base.c          |    2 +-
+ drivers/of/dynamic.c       |    2 +-
+ drivers/of/platform.c      |    2 +-
+ drivers/spi/spi.c          |    2 +-
+ include/linux/fwnode.h     |   44 +++++++++++++++++++++++++++++++++-----------
+ 9 files changed, 53 insertions(+), 31 deletions(-)
+
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -194,7 +194,7 @@ void fw_devlink_purge_absent_suppliers(s
+       if (fwnode->dev)
+               return;
+-      fwnode->flags |= FWNODE_FLAG_NOT_DEVICE;
++      fwnode_set_flag(fwnode, FWNODE_FLAG_NOT_DEVICE);
+       fwnode_links_purge_consumers(fwnode);
+       fwnode_for_each_available_child_node(fwnode, child)
+@@ -240,7 +240,7 @@ static void __fw_devlink_pickup_dangling
+       if (fwnode->dev && fwnode->dev->bus)
+               return;
+-      fwnode->flags |= FWNODE_FLAG_NOT_DEVICE;
++      fwnode_set_flag(fwnode, FWNODE_FLAG_NOT_DEVICE);
+       __fwnode_links_move_consumers(fwnode, new_sup);
+       fwnode_for_each_available_child_node(fwnode, child)
+@@ -1070,7 +1070,7 @@ static void device_links_missing_supplie
+ static bool dev_is_best_effort(struct device *dev)
+ {
+       return (fw_devlink_best_effort && dev->can_match) ||
+-              (dev->fwnode && (dev->fwnode->flags & FWNODE_FLAG_BEST_EFFORT));
++              (dev->fwnode && fwnode_test_flag(dev->fwnode, FWNODE_FLAG_BEST_EFFORT));
+ }
+ static struct fwnode_handle *fwnode_links_check_suppliers(
+@@ -1764,11 +1764,11 @@ bool fw_devlink_is_strict(void)
+ static void fw_devlink_parse_fwnode(struct fwnode_handle *fwnode)
+ {
+-      if (fwnode->flags & FWNODE_FLAG_LINKS_ADDED)
++      if (fwnode_test_flag(fwnode, FWNODE_FLAG_LINKS_ADDED))
+               return;
+       fwnode_call_int_op(fwnode, add_links);
+-      fwnode->flags |= FWNODE_FLAG_LINKS_ADDED;
++      fwnode_set_flag(fwnode, FWNODE_FLAG_LINKS_ADDED);
+ }
+ static void fw_devlink_parse_fwtree(struct fwnode_handle *fwnode)
+@@ -1889,7 +1889,7 @@ static bool fwnode_init_without_drv(stru
+       struct device *dev;
+       bool ret;
+-      if (!(fwnode->flags & FWNODE_FLAG_INITIALIZED))
++      if (!fwnode_test_flag(fwnode, FWNODE_FLAG_INITIALIZED))
+               return false;
+       dev = get_dev_from_fwnode(fwnode);
+@@ -1948,10 +1948,10 @@ static bool __fw_devlink_relax_cycles(st
+        * We aren't trying to find all cycles. Just a cycle between con and
+        * sup_handle.
+        */
+-      if (sup_handle->flags & FWNODE_FLAG_VISITED)
++      if (fwnode_test_flag(sup_handle, FWNODE_FLAG_VISITED))
+               return false;
+-      sup_handle->flags |= FWNODE_FLAG_VISITED;
++      fwnode_set_flag(sup_handle, FWNODE_FLAG_VISITED);
+       /* Termination condition. */
+       if (sup_handle == con_handle) {
+@@ -2021,7 +2021,7 @@ static bool __fw_devlink_relax_cycles(st
+       }
+ out:
+-      sup_handle->flags &= ~FWNODE_FLAG_VISITED;
++      fwnode_clear_flag(sup_handle, FWNODE_FLAG_VISITED);
+       put_device(sup_dev);
+       put_device(con_dev);
+       put_device(par_dev);
+@@ -2074,7 +2074,7 @@ static int fw_devlink_create_devlink(str
+        * When such a flag is set, we can't create device links where P is the
+        * supplier of C as that would delay the probe of C.
+        */
+-      if (sup_handle->flags & FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD &&
++      if (fwnode_test_flag(sup_handle, FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD) &&
+           fwnode_is_ancestor_of(sup_handle, con->fwnode))
+               return -EINVAL;
+@@ -2097,7 +2097,7 @@ static int fw_devlink_create_devlink(str
+       else
+               flags = FW_DEVLINK_FLAGS_PERMISSIVE;
+-      if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE)
++      if (fwnode_test_flag(sup_handle, FWNODE_FLAG_NOT_DEVICE))
+               sup_dev = fwnode_get_next_parent_dev(sup_handle);
+       else
+               sup_dev = get_dev_from_fwnode(sup_handle);
+@@ -2109,7 +2109,7 @@ static int fw_devlink_create_devlink(str
+                * supplier device indefinitely.
+                */
+               if (sup_dev->links.status == DL_DEV_NO_DRIVER &&
+-                  sup_handle->flags & FWNODE_FLAG_INITIALIZED) {
++                  fwnode_test_flag(sup_handle, FWNODE_FLAG_INITIALIZED)) {
+                       dev_dbg(con,
+                               "Not linking %pfwf - dev might never probe\n",
+                               sup_handle);
+--- a/drivers/bus/imx-weim.c
++++ b/drivers/bus/imx-weim.c
+@@ -336,7 +336,7 @@ static int of_weim_notify(struct notifie
+                        * fw_devlink doesn't skip adding consumers to this
+                        * device.
+                        */
+-                      rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
++                      fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
+                       if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) {
+                               dev_err(&pdev->dev,
+                                       "Failed to create child device '%pOF'\n",
+--- a/drivers/i2c/i2c-core-of.c
++++ b/drivers/i2c/i2c-core-of.c
+@@ -182,7 +182,7 @@ static int of_i2c_notify(struct notifier
+                * Clear the flag before adding the device so that fw_devlink
+                * doesn't skip adding consumers to this device.
+                */
+-              rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
++              fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
+               client = of_i2c_register_device(adap, rd->dn);
+               if (IS_ERR(client)) {
+                       dev_err(&adap->dev, "failed to create client for '%pOF'\n",
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -539,8 +539,8 @@ int __mdiobus_register(struct mii_bus *b
+               return -EINVAL;
+       if (bus->parent && bus->parent->of_node)
+-              bus->parent->of_node->fwnode.flags |=
+-                                      FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD;
++              fwnode_set_flag(&bus->parent->of_node->fwnode,
++                              FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD);
+       WARN(bus->state != MDIOBUS_ALLOCATED &&
+            bus->state != MDIOBUS_UNREGISTERED,
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -1927,7 +1927,7 @@ void of_alias_scan(void * (*dt_alloc)(u6
+               if (name)
+                       of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
+               if (of_stdout)
+-                      of_stdout->fwnode.flags |= FWNODE_FLAG_BEST_EFFORT;
++                      fwnode_set_flag(&of_stdout->fwnode, FWNODE_FLAG_BEST_EFFORT);
+       }
+       if (!of_aliases)
+--- a/drivers/of/dynamic.c
++++ b/drivers/of/dynamic.c
+@@ -227,7 +227,7 @@ static void __of_attach_node(struct devi
+       np->sibling = np->parent->child;
+       np->parent->child = np;
+       of_node_clear_flag(np, OF_DETACHED);
+-      np->fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;
++      fwnode_set_flag(&np->fwnode, FWNODE_FLAG_NOT_DEVICE);
+ }
+ /**
+--- a/drivers/of/platform.c
++++ b/drivers/of/platform.c
+@@ -745,7 +745,7 @@ static int of_platform_notify(struct not
+                * Clear the flag before adding the device so that fw_devlink
+                * doesn't skip adding consumers to this device.
+                */
+-              rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
++              fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
+               /* pdev_parent may be NULL when no bus platform device */
+               pdev_parent = of_find_device_by_node(rd->dn->parent);
+               pdev = of_platform_device_create(rd->dn, NULL,
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -4480,7 +4480,7 @@ static int of_spi_notify(struct notifier
+                * Clear the flag before adding the device so that fw_devlink
+                * doesn't skip adding consumers to this device.
+                */
+-              rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
++              fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
+               spi = of_register_spi_device(ctlr, rd->dn);
+               put_device(&ctlr->dev);
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -12,6 +12,7 @@
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/bits.h>
++#include <linux/bitops.h>
+ #include <linux/err.h>
+ struct fwnode_operations;
+@@ -31,12 +32,12 @@ struct device;
+  *            suppliers. Only enforce ordering with suppliers that have
+  *            drivers.
+  */
+-#define FWNODE_FLAG_LINKS_ADDED                       BIT(0)
+-#define FWNODE_FLAG_NOT_DEVICE                        BIT(1)
+-#define FWNODE_FLAG_INITIALIZED                       BIT(2)
+-#define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD  BIT(3)
+-#define FWNODE_FLAG_BEST_EFFORT                       BIT(4)
+-#define FWNODE_FLAG_VISITED                   BIT(5)
++#define FWNODE_FLAG_LINKS_ADDED                       0
++#define FWNODE_FLAG_NOT_DEVICE                        1
++#define FWNODE_FLAG_INITIALIZED                       2
++#define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD  3
++#define FWNODE_FLAG_BEST_EFFORT                       4
++#define FWNODE_FLAG_VISITED                   5
+ struct fwnode_handle {
+       struct fwnode_handle *secondary;
+@@ -44,7 +45,7 @@ struct fwnode_handle {
+       struct device *dev;
+       struct list_head suppliers;
+       struct list_head consumers;
+-      u8 flags;
++      unsigned long flags;
+ };
+ /*
+@@ -197,16 +198,37 @@ static inline void fwnode_init(struct fw
+       INIT_LIST_HEAD(&fwnode->suppliers);
+ }
++static inline void fwnode_set_flag(struct fwnode_handle *fwnode,
++                                 unsigned int bit)
++{
++      set_bit(bit, &fwnode->flags);
++}
++
++static inline void fwnode_clear_flag(struct fwnode_handle *fwnode,
++                                   unsigned int bit)
++{
++      clear_bit(bit, &fwnode->flags);
++}
++
++static inline void fwnode_assign_flag(struct fwnode_handle *fwnode,
++                                    unsigned int bit, bool value)
++{
++      assign_bit(bit, &fwnode->flags, value);
++}
++
++static inline bool fwnode_test_flag(struct fwnode_handle *fwnode,
++                                  unsigned int bit)
++{
++      return test_bit(bit, &fwnode->flags);
++}
++
+ static inline void fwnode_dev_initialized(struct fwnode_handle *fwnode,
+                                         bool initialized)
+ {
+       if (IS_ERR_OR_NULL(fwnode))
+               return;
+-      if (initialized)
+-              fwnode->flags |= FWNODE_FLAG_INITIALIZED;
+-      else
+-              fwnode->flags &= ~FWNODE_FLAG_INITIALIZED;
++      fwnode_assign_flag(fwnode, FWNODE_FLAG_INITIALIZED, initialized);
+ }
+ extern bool fw_devlink_is_strict(void);
index a48c39abbb75e96f7b9de5a843cf0182379ebdd4..6286755b28d78da8de6b07d684995b3922e232be 100644 (file)
@@ -175,3 +175,4 @@ net-enetc-fix-the-deadlock-of-enetc_mdio_lock.patch
 blk-mq-fix-null-dereference-on-q-elevator-in-blk_mq_.patch
 arm64-set-__exception_irq_entry-with-__irq_entry-as-.patch
 regset-use-kvzalloc-for-regset_get_alloc.patch
+device-property-make-modifications-of-fwnode-flags-thread-safe.patch