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: 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>
This commit is contained in:
parent
a9dd8f3c2c
commit
74c782cff7
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user