Commit 74c782cf authored by Saravana Kannan's avatar Saravana Kannan Committed by Greg Kroah-Hartman
Browse files

driver core: fw_devlink: Handle suppliers that don't use driver core



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: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: default avatarSaravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20210205222644.2357303-6-saravanak@google.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a9dd8f3c
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -1636,6 +1636,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
+17 −2
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include <linux/types.h>
#include <linux/list.h>
#include <linux/err.h>

struct fwnode_operations;
struct device;
@@ -20,9 +21,11 @@ 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);