driver core: Add device links from fwnode only for the primary device
authorSaravana Kannan <saravanak@google.com>
Sat, 21 Mar 2020 04:54:48 +0000 (21:54 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 21 Mar 2020 10:55:27 +0000 (11:55 +0100)
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>
drivers/base/core.c

index fc6a609..5e3cc16 100644 (file)
@@ -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)
@@ -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
@@ -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);