driver core: fw_devlink: Handle suppliers that don't use driver core
authorSaravana Kannan <saravanak@google.com>
Fri, 5 Feb 2021 22:26:41 +0000 (14:26 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Feb 2021 13:31:06 +0000 (14:31 +0100)
Device links only work between devices that use the driver core to match
and bind a driver to a device. So, add an API for frameworks to let the
driver core know that a fwnode has been initialized by a driver without
using the driver core.

Then use this information to make sure that fw_devlink doesn't make the
consumers wait indefinitely on suppliers that'll never bind to a driver.

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20210205222644.2357303-6-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/core.c
include/linux/fwnode.h

index f466ab4..ea710b3 100644 (file)
@@ -1637,6 +1637,17 @@ static int fw_devlink_create_devlink(struct device *con,
        sup_dev = get_dev_from_fwnode(sup_handle);
        if (sup_dev) {
                /*
+                * If it's one of those drivers that don't actually bind to
+                * their device using driver core, then don't wait on this
+                * supplier device indefinitely.
+                */
+               if (sup_dev->links.status == DL_DEV_NO_DRIVER &&
+                   sup_handle->flags & FWNODE_FLAG_INITIALIZED) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /*
                 * If this fails, it is due to cycles in device links.  Just
                 * give up on this link and treat it as invalid.
                 */
@@ -1655,6 +1666,10 @@ static int fw_devlink_create_devlink(struct device *con,
                goto out;
        }
 
+       /* Supplier that's already initialized without a struct device. */
+       if (sup_handle->flags & FWNODE_FLAG_INITIALIZED)
+               return -EINVAL;
+
        /*
         * DL_FLAG_SYNC_STATE_ONLY doesn't block probing and supports
         * cycles. So cycle detection isn't necessary and shouldn't be
index d5caefe..dfefd43 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/err.h>
 
 struct fwnode_operations;
 struct device;
@@ -18,11 +19,13 @@ struct device;
 /*
  * fwnode link flags
  *
- * LINKS_ADDED: The fwnode has already be parsed to add fwnode links.
- * NOT_DEVICE: The fwnode will never be populated as a struct device.
+ * LINKS_ADDED:        The fwnode has already be parsed to add fwnode links.
+ * NOT_DEVICE: The fwnode will never be populated as a struct device.
+ * INITIALIZED: The hardware corresponding to fwnode has been initialized.
  */
 #define FWNODE_FLAG_LINKS_ADDED                BIT(0)
 #define FWNODE_FLAG_NOT_DEVICE         BIT(1)
+#define FWNODE_FLAG_INITIALIZED                BIT(2)
 
 struct fwnode_handle {
        struct fwnode_handle *secondary;
@@ -161,6 +164,18 @@ static inline void fwnode_init(struct fwnode_handle *fwnode,
        INIT_LIST_HEAD(&fwnode->suppliers);
 }
 
+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;
+}
+
 extern u32 fw_devlink_get_flags(void);
 extern bool fw_devlink_is_strict(void);
 int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup);