aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-04-28 18:33:45 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-05-17 17:19:17 -0400
commite1866b33b1e89f077b7132daae3dfd9a594e9a1a (patch)
tree674760cf6db30a664112ef73ad15b7b676a4debd
parentee940d8dccd899aa1777ea84da3d9cd04b1d2e8e (diff)
PM / Runtime: Rework runtime PM handling during driver removal
The driver core tries to prevent race conditions between runtime PM and driver removal from happening by incrementing the runtime PM usage counter of the device and executing pm_runtime_barrier() before running the bus notifier and the ->remove() callbacks provided by the device's subsystem or driver. This guarantees that, if a future runtime suspend of the device has been scheduled or a runtime resume or idle request has been queued up right before the driver removal, it will be canceled or waited for to complete and no other asynchronous runtime suspend or idle requests for the device will be put into the PM workqueue until the ->remove() callback returns. However, it doesn't prevent resume requests from being queued up after pm_runtime_barrier() has been called and it doesn't prevent pm_runtime_resume() from executing the device subsystem's runtime resume callback. Morever, it prevents the device's subsystem or driver from putting the device into the suspended state by calling pm_runtime_suspend() from its ->remove() routine. This turns out to be a major inconvenience for some subsystems and drivers that want to leave the devices they handle in the suspended state. To really prevent runtime PM callbacks from racing with the bus notifier callback in __device_release_driver(), which is necessary, because the notifier is used by some subsystems to carry out operations affecting the runtime PM functionality, use pm_runtime_get_sync() instead of the combination of pm_runtime_get_noresume() and pm_runtime_barrier(). This will resume the device if it's in the suspended state and will prevent it from being suspended again until pm_runtime_put_*() is called. To allow subsystems and drivers to put devices into the suspended state by calling pm_runtime_suspend() from their ->remove() routines, execute pm_runtime_put_sync() after running the bus notifier in __device_release_driver(). This will require subsystems and drivers to make their ->remove() callbacks avoid races with runtime PM directly, but it will allow of more flexibility in the handling of devices during the removal of their drivers. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--drivers/base/dd.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index da57ee9d63fe..29917c7506cb 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -316,8 +316,7 @@ static void __device_release_driver(struct device *dev)
316 316
317 drv = dev->driver; 317 drv = dev->driver;
318 if (drv) { 318 if (drv) {
319 pm_runtime_get_noresume(dev); 319 pm_runtime_get_sync(dev);
320 pm_runtime_barrier(dev);
321 320
322 driver_sysfs_remove(dev); 321 driver_sysfs_remove(dev);
323 322
@@ -326,6 +325,8 @@ static void __device_release_driver(struct device *dev)
326 BUS_NOTIFY_UNBIND_DRIVER, 325 BUS_NOTIFY_UNBIND_DRIVER,
327 dev); 326 dev);
328 327
328 pm_runtime_put_sync(dev);
329
329 if (dev->bus && dev->bus->remove) 330 if (dev->bus && dev->bus->remove)
330 dev->bus->remove(dev); 331 dev->bus->remove(dev);
331 else if (drv->remove) 332 else if (drv->remove)
@@ -338,7 +339,6 @@ static void __device_release_driver(struct device *dev)
338 BUS_NOTIFY_UNBOUND_DRIVER, 339 BUS_NOTIFY_UNBOUND_DRIVER,
339 dev); 340 dev);
340 341
341 pm_runtime_put_sync(dev);
342 } 342 }
343} 343}
344 344