driver core: Add waiting_for_supplier sysfs file for devices
authorSaravana Kannan <saravanak@google.com>
Thu, 21 May 2020 19:18:00 +0000 (12:18 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Jul 2020 13:24:56 +0000 (15:24 +0200)
This would be useful to check if a device is not probing because it's
waiting for a supplier to be added and then linked to before it can
probe.

To reduce sysfs clutter, this file is added only if it can ever be 1.
So, if fw_devlink is disabled or set to permissive, this file is not
added. Also, this file is removed once the device probes as it's no
longer relevant.

Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20200521191800.136035-4-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-devices-waiting_for_supplier [new file with mode: 0644]
drivers/base/core.c

diff --git a/Documentation/ABI/testing/sysfs-devices-waiting_for_supplier b/Documentation/ABI/testing/sysfs-devices-waiting_for_supplier
new file mode 100644 (file)
index 0000000..59d073d
--- /dev/null
@@ -0,0 +1,17 @@
+What:          /sys/devices/.../waiting_for_supplier
+Date:          May 2020
+Contact:       Saravana Kannan <saravanak@google.com>
+Description:
+               The /sys/devices/.../waiting_for_supplier attribute is only
+               present when fw_devlink kernel command line option is enabled
+               and is set to something stricter than "permissive".  It is
+               removed once a device probes successfully (because the
+               information is no longer relevant). The number read from it (0
+               or 1) reflects whether the device is waiting for one or more
+               suppliers to be added and then linked to using device links
+               before the device can probe.
+
+               A value of 0 means the device is not waiting for any suppliers
+               to be added before it can probe.  A value of 1 means the device
+               is waiting for one or more suppliers to be added before it can
+               probe.
index ca64033..5373ddd 100644 (file)
@@ -1041,6 +1041,22 @@ static void device_link_drop_managed(struct device_link *link)
        kref_put(&link->kref, __device_link_del);
 }
 
+static ssize_t waiting_for_supplier_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       bool val;
+
+       device_lock(dev);
+       mutex_lock(&wfs_lock);
+       val = !list_empty(&dev->links.needs_suppliers)
+             && dev->links.need_for_probe;
+       mutex_unlock(&wfs_lock);
+       device_unlock(dev);
+       return sprintf(buf, "%u\n", val);
+}
+static DEVICE_ATTR_RO(waiting_for_supplier);
+
 /**
  * device_links_driver_bound - Update device links after probing its driver.
  * @dev: Device to update the links for.
@@ -1065,6 +1081,7 @@ void device_links_driver_bound(struct device *dev)
        mutex_lock(&wfs_lock);
        list_del_init(&dev->links.needs_suppliers);
        mutex_unlock(&wfs_lock);
+       device_remove_file(dev, &dev_attr_waiting_for_supplier);
 
        device_links_write_lock();
 
@@ -2144,8 +2161,16 @@ static int device_add_attrs(struct device *dev)
                        goto err_remove_dev_groups;
        }
 
+       if (fw_devlink_flags && !fw_devlink_is_permissive()) {
+               error = device_create_file(dev, &dev_attr_waiting_for_supplier);
+               if (error)
+                       goto err_remove_dev_online;
+       }
+
        return 0;
 
+ err_remove_dev_online:
+       device_remove_file(dev, &dev_attr_online);
  err_remove_dev_groups:
        device_remove_groups(dev, dev->groups);
  err_remove_type_groups:
@@ -2163,6 +2188,7 @@ static void device_remove_attrs(struct device *dev)
        struct class *class = dev->class;
        const struct device_type *type = dev->type;
 
+       device_remove_file(dev, &dev_attr_waiting_for_supplier);
        device_remove_file(dev, &dev_attr_online);
        device_remove_groups(dev, dev->groups);