Commit ddef08dd authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Lee Jones

Driver core: wakeup the parent device before trying probe

If the parent is still suspended when driver probe is
attempted, the result may be failure.

For example, if the parent is a PCI MFD device that has been
suspended when we try to probe our device, any register
reads will return 0xffffffff.

To fix the problem, making sure the parent is always awake
before attempting driver probe.
Signed-off-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
parent 712e960f
...@@ -399,6 +399,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe); ...@@ -399,6 +399,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
* *
* This function must be called with @dev lock held. When called for a * This function must be called with @dev lock held. When called for a
* USB interface, @dev->parent lock must be held as well. * 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) 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) ...@@ -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", pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name); drv->bus->name, __func__, dev_name(dev), drv->name);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
pm_runtime_barrier(dev); pm_runtime_barrier(dev);
ret = really_probe(dev, drv); ret = really_probe(dev, drv);
pm_request_idle(dev); pm_request_idle(dev);
if (dev->parent)
pm_runtime_put(dev->parent);
return ret; return ret;
} }
...@@ -507,11 +515,17 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) ...@@ -507,11 +515,17 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
device_lock(dev); device_lock(dev);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
dev_dbg(dev, "async probe completed\n"); dev_dbg(dev, "async probe completed\n");
pm_request_idle(dev); pm_request_idle(dev);
if (dev->parent)
pm_runtime_put(dev->parent);
device_unlock(dev); device_unlock(dev);
put_device(dev); put_device(dev);
...@@ -541,6 +555,9 @@ static int __device_attach(struct device *dev, bool allow_async) ...@@ -541,6 +555,9 @@ static int __device_attach(struct device *dev, bool allow_async)
.want_async = false, .want_async = false,
}; };
if (dev->parent)
pm_runtime_get_sync(dev->parent);
ret = bus_for_each_drv(dev->bus, NULL, &data, ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver); __device_attach_driver);
if (!ret && allow_async && data.have_async) { if (!ret && allow_async && data.have_async) {
...@@ -557,6 +574,9 @@ static int __device_attach(struct device *dev, bool allow_async) ...@@ -557,6 +574,9 @@ static int __device_attach(struct device *dev, bool allow_async)
} else { } else {
pm_request_idle(dev); pm_request_idle(dev);
} }
if (dev->parent)
pm_runtime_put(dev->parent);
} }
out_unlock: out_unlock:
device_unlock(dev); device_unlock(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment