lkml.org 
[lkml]   [2019]   [Jun]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject[RESEND PATCH v1 2/5] driver core: Add device links support for pending links to suppliers
    From
    When consumer devices are added, they might not have a supplier device
    to link to despite needing mandatory resources/functionality from one
    or more suppliers. Add a waiting_for_suppliers list to track such
    consumers and add helper functions to manage the list.

    Marking/unmarking a consumer device as waiting for suppliers is
    generally expected to be done by the entity that's creating the
    device.

    Signed-off-by: Saravana Kannan <saravanak@google.com>
    ---
    drivers/base/core.c | 67 ++++++++++++++++++++++++++++++++++++++++++
    include/linux/device.h | 5 ++++
    2 files changed, 72 insertions(+)

    diff --git a/drivers/base/core.c b/drivers/base/core.c
    index fd7511e04e62..9ab6782dda1c 100644
    --- a/drivers/base/core.c
    +++ b/drivers/base/core.c
    @@ -44,6 +44,8 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup);
    #endif

    /* Device links support. */
    +static LIST_HEAD(wait_for_suppliers);
    +static DEFINE_MUTEX(wfs_lock);

    #ifdef CONFIG_SRCU
    static DEFINE_MUTEX(device_links_lock);
    @@ -401,6 +403,53 @@ struct device_link *device_link_add(struct device *consumer,
    }
    EXPORT_SYMBOL_GPL(device_link_add);

    +/**
    + * device_link_wait_for_supplier - Mark device as waiting for supplier
    + * @consumer: Consumer device
    + *
    + * Marks the consumer device as waiting for suppliers to become available. The
    + * consumer device will never be probed until it's unmarked as waiting for
    + * suppliers. The caller is responsible for adding the link to the supplier
    + * once the supplier device is present.
    + *
    + * This function is NOT meant to be called from the probe function of the
    + * consumer but rather from code that creates the consumer device.
    + */
    +void device_link_wait_for_supplier(struct device *consumer)
    +{
    + mutex_lock(&wfs_lock);
    + list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers);
    + mutex_unlock(&wfs_lock);
    +}
    +
    +/**
    + * device_link_check_waiting_consumers - Try to unmark waiting consumers
    + * @add_suppliers: Callback function to add suppliers to waiting consumer
    + *
    + * Loops through all consumers waiting on suppliers and tries to add all their
    + * supplier links. If that succeeds, the consumer device is unmarked as waiting
    + * for suppliers. Otherwise, they are left marked as waiting on suppliers,
    + *
    + * The add_suppliers callback is expected to return 0 if it has found and added
    + * all the supplier links for the consumer device. It should return an error if
    + * it isn't able to do so.
    + *
    + * The caller of device_link_wait_for_supplier() is expected to call this once
    + * it's aware of potential suppliers becoming available.
    + */
    +void device_link_check_waiting_consumers(
    + int (*add_suppliers)(struct device *consumer))
    +{
    + struct device *dev, *tmp;
    +
    + mutex_lock(&wfs_lock);
    + list_for_each_entry_safe(dev, tmp, &wait_for_suppliers,
    + links.needs_suppliers)
    + if (!add_suppliers(dev))
    + list_del_init(&dev->links.needs_suppliers);
    + mutex_unlock(&wfs_lock);
    +}
    +
    static void device_link_free(struct device_link *link)
    {
    while (refcount_dec_not_one(&link->rpm_active))
    @@ -535,6 +584,19 @@ int device_links_check_suppliers(struct device *dev)
    struct device_link *link;
    int ret = 0;

    + /*
    + * If a device is waiting for one or more suppliers (in
    + * wait_for_suppliers list), it is not ready to probe yet. So just
    + * return -EPROBE_DEFER without having to check the links with existing
    + * suppliers.
    + */
    + mutex_lock(&wfs_lock);
    + if (!list_empty(&dev->links.needs_suppliers)) {
    + mutex_unlock(&wfs_lock);
    + return -EPROBE_DEFER;
    + }
    + mutex_unlock(&wfs_lock);
    +
    device_links_write_lock();

    list_for_each_entry(link, &dev->links.suppliers, c_node) {
    @@ -812,6 +874,10 @@ static void device_links_purge(struct device *dev)
    {
    struct device_link *link, *ln;

    + mutex_lock(&wfs_lock);
    + list_del(&dev->links.needs_suppliers);
    + mutex_unlock(&wfs_lock);
    +
    /*
    * Delete all of the remaining links from this device to any other
    * devices (either consumers or suppliers).
    @@ -1673,6 +1739,7 @@ void device_initialize(struct device *dev)
    #endif
    INIT_LIST_HEAD(&dev->links.consumers);
    INIT_LIST_HEAD(&dev->links.suppliers);
    + INIT_LIST_HEAD(&dev->links.needs_suppliers);
    dev->links.status = DL_DEV_NO_DRIVER;
    }
    EXPORT_SYMBOL_GPL(device_initialize);
    diff --git a/include/linux/device.h b/include/linux/device.h
    index e85264fb6616..4e71e5386aae 100644
    --- a/include/linux/device.h
    +++ b/include/linux/device.h
    @@ -887,11 +887,13 @@ enum dl_dev_state {
    * struct dev_links_info - Device data related to device links.
    * @suppliers: List of links to supplier devices.
    * @consumers: List of links to consumer devices.
    + * @needs_suppliers: Hook to global list of devices waiting for suppliers.
    * @status: Driver status information.
    */
    struct dev_links_info {
    struct list_head suppliers;
    struct list_head consumers;
    + struct list_head needs_suppliers;
    enum dl_dev_state status;
    };

    @@ -1395,6 +1397,9 @@ struct device_link *device_link_add(struct device *consumer,
    struct device *supplier, u32 flags);
    void device_link_del(struct device_link *link);
    void device_link_remove(void *consumer, struct device *supplier);
    +void device_link_wait_for_supplier(struct device *consumer);
    +void device_link_check_waiting_consumers(
    + int (*add_suppliers)(struct device *consumer));

    #ifndef dev_fmt
    #define dev_fmt(fmt) fmt
    --
    2.22.0.rc1.257.g3120a18244-goog
    \
     
     \ /
      Last update: 2019-06-04 02:33    [W:6.795 / U:0.080 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site