Skip to content

Commit

Permalink
driver core: Add device links from fwnode only for the primary device
Browse files Browse the repository at this point in the history
Sometimes, more than one (generally two) device can point to the same
fwnode.  However, only one device is set as the fwnode's device
(fwnode->dev) and can be looked up from the fwnode.

Typically, only one of these devices actually have a driver and actually
probe. If we create device links for all these devices, then the
suppliers' of these devices (with the same fwnode) will never get a
sync_state() call because one of their consumer devices will never probe
(because they don't have a driver).

So, create device links only for the device that is considered as the
fwnode's device.

One such example of this is the PCI bridge platform_device and the
corresponding pci_bus device. Both these devices will have the same
fwnode. It's the platform_device that is registered first and is set as
the fwnode's device. Also the platform_device is the one that actually
probes. Without this patch none of the suppliers of a PCI bridge
platform_device would get a sync_state() callback.

Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20200321045448.15192-1-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Saravana Kannan authored and gregkh committed Mar 21, 2020
1 parent b94b807 commit 4dbe191
Showing 1 changed file with 6 additions and 2 deletions.
8 changes: 6 additions & 2 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2404,6 +2404,7 @@ int device_add(struct device *dev)
struct class_interface *class_intf;
int error = -EINVAL, fw_ret;
struct kobject *glue_dir = NULL;
bool is_fwnode_dev = false;

dev = get_device(dev);
if (!dev)
Expand Down Expand Up @@ -2501,8 +2502,10 @@ int device_add(struct device *dev)

kobject_uevent(&dev->kobj, KOBJ_ADD);

if (dev->fwnode && !dev->fwnode->dev)
if (dev->fwnode && !dev->fwnode->dev) {
dev->fwnode->dev = dev;
is_fwnode_dev = true;
}

/*
* Check if any of the other devices (consumers) have been waiting for
Expand All @@ -2518,7 +2521,8 @@ int device_add(struct device *dev)
*/
device_link_add_missing_supplier_links();

if (fw_devlink_flags && fwnode_has_op(dev->fwnode, add_links)) {
if (fw_devlink_flags && is_fwnode_dev &&
fwnode_has_op(dev->fwnode, add_links)) {
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
if (fw_ret == -ENODEV)
device_link_wait_for_mandatory_supplier(dev);
Expand Down

0 comments on commit 4dbe191

Please sign in to comment.