From f71648d73c1650b8b4aceb3856bebbde6daa3b86 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Oct 2010 01:02:27 +0200 Subject: 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 Acked-by: Alan Stern diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index e957c49..1dd8676 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) { int (*callback)(struct device *); struct device *parent = NULL; - bool notify = false; int retval; dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags); @@ -383,13 +382,10 @@ static int rpm_suspend(struct device *dev, int rpmflags) if (retval) { __update_runtime_status(dev, RPM_ACTIVE); dev->power.deferred_resume = 0; - if (retval == -EAGAIN || retval == -EBUSY) { - if (dev->power.timer_expires == 0) - notify = true; + if (retval == -EAGAIN || retval == -EBUSY) dev->power.runtime_error = 0; - } else { + else pm_runtime_cancel_pending(dev); - } } else { no_callback: __update_runtime_status(dev, RPM_SUSPENDED); @@ -408,9 +404,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) goto out; } - if (notify) - rpm_idle(dev, 0); - if (parent && !parent->power.ignore_children) { spin_unlock_irq(&dev->power.lock); -- cgit v0.10.2