summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/core.c24
-rw-r--r--drivers/base/dd.c29
2 files changed, 51 insertions, 2 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 18e04ca1de13..feec8dee1e91 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -440,6 +440,19 @@ static void device_link_wait_for_supplier(struct device *consumer)
}
/**
+ * device_link_remove_from_wfs - Unmark device as waiting for supplier
+ * @consumer: Consumer device
+ *
+ * Unmark the consumer device as waiting for suppliers to become available.
+ */
+void device_link_remove_from_wfs(struct device *consumer)
+{
+ mutex_lock(&wfs_lock);
+ list_del_init(&consumer->links.needs_suppliers);
+ mutex_unlock(&wfs_lock);
+}
+
+/**
* device_link_check_waiting_consumers - Try to unmark waiting consumers
*
* Loops through all consumers waiting on suppliers and tries to add all their
@@ -456,12 +469,19 @@ static void device_link_wait_for_supplier(struct device *consumer)
static void device_link_check_waiting_consumers(void)
{
struct device *dev, *tmp;
+ int ret;
mutex_lock(&wfs_lock);
list_for_each_entry_safe(dev, tmp, &wait_for_suppliers,
- links.needs_suppliers)
- if (!dev->bus->add_links(dev))
+ links.needs_suppliers) {
+ ret = 0;
+ if (dev->has_edit_links)
+ ret = driver_edit_links(dev);
+ else if (dev->bus->add_links)
+ ret = dev->bus->add_links(dev);
+ if (!ret)
list_del_init(&dev->links.needs_suppliers);
+ }
mutex_unlock(&wfs_lock);
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 994a90747420..5e7041ede0d7 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -698,6 +698,12 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
+ if (drv->edit_links) {
+ if (drv->edit_links(dev))
+ dev->has_edit_links = true;
+ else
+ device_link_remove_from_wfs(dev);
+ }
pm_runtime_get_suppliers(dev);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
@@ -786,6 +792,29 @@ struct device_attach_data {
bool have_async;
};
+static int __driver_edit_links(struct device_driver *drv, void *data)
+{
+ struct device *dev = data;
+
+ if (!drv->edit_links)
+ return 0;
+
+ if (driver_match_device(drv, dev) <= 0)
+ return 0;
+
+ return drv->edit_links(dev);
+}
+
+int driver_edit_links(struct device *dev)
+{
+ int ret;
+
+ device_lock(dev);
+ ret = bus_for_each_drv(dev->bus, NULL, dev, __driver_edit_links);
+ device_unlock(dev);
+ return ret;
+}
+
static int __device_attach_driver(struct device_driver *drv, void *_data)
{
struct device_attach_data *data = _data;