diff --git a/drivers/base/core.c b/drivers/base/core.c index f466ab4f1c35..ea710b33bda6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -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 diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index d5caefe39d93..dfefd43a737c 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -11,6 +11,7 @@ #include #include +#include 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);