aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-10-10 19:02:27 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-10-16 19:57:49 -0400
commitf71648d73c1650b8b4aceb3856bebbde6daa3b86 (patch)
treede47bd189c730d82781a43cc638452aef37facfe /drivers/base
parent3624eb04c24861ab296842414f9752a393e68372 (diff)
PM / Runtime: Remove idle notification after failing suspend
If runtime suspend of a device fails returning -EAGAIN or -EBUSY, which means that it's safe to try to suspend it again, the PM core runs the runtime idle helper function for it. Unfortunately this may lead to problems, for example for PCI devices whose drivers don't implement the ->runtime_idle() callback, because in that case the PCI bus type's ->runtime_idle() always calls pm_runtime_suspend() for the given device. Then, if there's an automatic idle notification after the driver's ->runtime_suspend() returning -EAGAIN or -EBUSY, it will make the suspend happen again possibly causing a busy loop to appear. To avoid that, remove the idle notification after failing runtime suspend of a device altogether and let the callers of pm_runtime_suspend() repeat the operation if need be. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Alan Stern <stern@rowland.harvard.edu>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/runtime.c11
1 files changed, 2 insertions, 9 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index e957c496a1b..1dd8676d7f5 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -281,7 +281,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
281{ 281{
282 int (*callback)(struct device *); 282 int (*callback)(struct device *);
283 struct device *parent = NULL; 283 struct device *parent = NULL;
284 bool notify = false;
285 int retval; 284 int retval;
286 285
287 dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags); 286 dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
@@ -383,13 +382,10 @@ static int rpm_suspend(struct device *dev, int rpmflags)
383 if (retval) { 382 if (retval) {
384 __update_runtime_status(dev, RPM_ACTIVE); 383 __update_runtime_status(dev, RPM_ACTIVE);
385 dev->power.deferred_resume = 0; 384 dev->power.deferred_resume = 0;
386 if (retval == -EAGAIN || retval == -EBUSY) { 385 if (retval == -EAGAIN || retval == -EBUSY)
387 if (dev->power.timer_expires == 0)
388 notify = true;
389 dev->power.runtime_error = 0; 386 dev->power.runtime_error = 0;
390 } else { 387 else
391 pm_runtime_cancel_pending(dev); 388 pm_runtime_cancel_pending(dev);
392 }
393 } else { 389 } else {
394 no_callback: 390 no_callback:
395 __update_runtime_status(dev, RPM_SUSPENDED); 391 __update_runtime_status(dev, RPM_SUSPENDED);
@@ -408,9 +404,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
408 goto out; 404 goto out;
409 } 405 }
410 406
411 if (notify)
412 rpm_idle(dev, 0);
413
414 if (parent && !parent->power.ignore_children) { 407 if (parent && !parent->power.ignore_children) {
415 spin_unlock_irq(&dev->power.lock); 408 spin_unlock_irq(&dev->power.lock);
416 409