|
@@ -399,6 +399,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
|
|
|
*
|
|
|
* This function must be called with @dev lock held. When called for a
|
|
|
* USB interface, @dev->parent lock must be held as well.
|
|
|
+ *
|
|
|
+ * If the device has a parent, runtime-resume the parent before driver probing.
|
|
|
*/
|
|
|
int driver_probe_device(struct device_driver *drv, struct device *dev)
|
|
|
{
|
|
@@ -410,10 +412,16 @@ 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 (dev->parent)
|
|
|
+ pm_runtime_get_sync(dev->parent);
|
|
|
+
|
|
|
pm_runtime_barrier(dev);
|
|
|
ret = really_probe(dev, drv);
|
|
|
pm_request_idle(dev);
|
|
|
|
|
|
+ if (dev->parent)
|
|
|
+ pm_runtime_put(dev->parent);
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -507,11 +515,17 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
|
|
|
|
|
|
device_lock(dev);
|
|
|
|
|
|
+ if (dev->parent)
|
|
|
+ pm_runtime_get_sync(dev->parent);
|
|
|
+
|
|
|
bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
|
|
|
dev_dbg(dev, "async probe completed\n");
|
|
|
|
|
|
pm_request_idle(dev);
|
|
|
|
|
|
+ if (dev->parent)
|
|
|
+ pm_runtime_put(dev->parent);
|
|
|
+
|
|
|
device_unlock(dev);
|
|
|
|
|
|
put_device(dev);
|
|
@@ -541,6 +555,9 @@ static int __device_attach(struct device *dev, bool allow_async)
|
|
|
.want_async = false,
|
|
|
};
|
|
|
|
|
|
+ if (dev->parent)
|
|
|
+ pm_runtime_get_sync(dev->parent);
|
|
|
+
|
|
|
ret = bus_for_each_drv(dev->bus, NULL, &data,
|
|
|
__device_attach_driver);
|
|
|
if (!ret && allow_async && data.have_async) {
|
|
@@ -557,6 +574,9 @@ static int __device_attach(struct device *dev, bool allow_async)
|
|
|
} else {
|
|
|
pm_request_idle(dev);
|
|
|
}
|
|
|
+
|
|
|
+ if (dev->parent)
|
|
|
+ pm_runtime_put(dev->parent);
|
|
|
}
|
|
|
out_unlock:
|
|
|
device_unlock(dev);
|