From 862f89b3d4c6bf3caab7fc69661fc6e725edd00a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Nov 2009 01:06:37 +0100 Subject: PM: fix irq enable/disable in runtime PM code This patch (as1305) fixes a bug in the irq-enable settings and removes some related overhead in the runtime PM code. In __pm_runtime_resume(), within the scope of the original spin_lock_irq(), we know that irqs are disabled. There's no reason to go through a pair of enable/disable cycles when acquiring and releasing the parent's lock. In __pm_runtime_set_status(), irqs are already disabled when the parent's lock is acquired, and they must remain disabled when it is released. Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index a770498a74ec..846d89e3d122 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -328,11 +328,11 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) * necessary. */ parent = dev->parent; - spin_unlock_irq(&dev->power.lock); + spin_unlock(&dev->power.lock); pm_runtime_get_noresume(parent); - spin_lock_irq(&parent->power.lock); + spin_lock(&parent->power.lock); /* * We can resume if the parent's run-time PM is disabled or it * is set to ignore children. @@ -343,9 +343,9 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) if (parent->power.runtime_status != RPM_ACTIVE) retval = -EBUSY; } - spin_unlock_irq(&parent->power.lock); + spin_unlock(&parent->power.lock); - spin_lock_irq(&dev->power.lock); + spin_lock(&dev->power.lock); if (retval) goto out; goto repeat; @@ -777,7 +777,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) } if (parent) { - spin_lock_irq(&parent->power.lock); + spin_lock(&parent->power.lock); /* * It is invalid to put an active child under a parent that is @@ -793,7 +793,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) atomic_inc(&parent->power.child_count); } - spin_unlock_irq(&parent->power.lock); + spin_unlock(&parent->power.lock); if (error) goto out; -- cgit v1.2.3 From bab636b921017f0db6e0c2979438f50b898a9808 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 3 Dec 2009 20:21:21 +0100 Subject: PM / Runtime: Fix lockdep warning in __pm_runtime_set_status() Lockdep complains about taking the parent lock in __pm_runtime_set_status(), so mark it as nested. Signed-off-by: Rafael J. Wysocki Reported-by: Alan Stern Cc: stable@kernel.org --- drivers/base/power/runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 846d89e3d122..0a4b75f834c0 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -777,7 +777,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) } if (parent) { - spin_lock(&parent->power.lock); + spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING); /* * It is invalid to put an active child under a parent that is -- cgit v1.2.3 From 63c94801701abfea21570d3302687ec027ed33e8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 3 Dec 2009 20:22:34 +0100 Subject: PM / Runtime: Use deferred_resume flag in pm_request_resume This patch (as1307) adds a small optimization to __pm_request_resume(). If the device is currently being suspended, there's no need to queue a work routine to resume it. Setting the deferred_resume flag will suffice. (There's also a minor improvement to the function's code layout: An unnecessary "else" is removed.) Also, the patch clarifies the usage of the deferred_resume flag. It is meaningful only while a suspend is in progress, so it should be cleared just before a suspend starts, not just after one ends. Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 0a4b75f834c0..6e8577d1f750 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -185,6 +185,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) } dev->power.runtime_status = RPM_SUSPENDING; + dev->power.deferred_resume = false; if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { spin_unlock_irq(&dev->power.lock); @@ -200,7 +201,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) if (retval) { dev->power.runtime_status = RPM_ACTIVE; pm_runtime_cancel_pending(dev); - dev->power.deferred_resume = false; if (retval == -EAGAIN || retval == -EBUSY) { notify = true; @@ -217,7 +217,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) wake_up_all(&dev->power.wait_queue); if (dev->power.deferred_resume) { - dev->power.deferred_resume = false; __pm_runtime_resume(dev, false); retval = -EAGAIN; goto out; @@ -659,13 +658,17 @@ static int __pm_request_resume(struct device *dev) pm_runtime_deactivate_timer(dev); + if (dev->power.runtime_status == RPM_SUSPENDING) { + dev->power.deferred_resume = true; + return retval; + } if (dev->power.request_pending) { /* If non-resume request is pending, we can overtake it. */ dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; return retval; - } else if (retval) { - return retval; } + if (retval) + return retval; dev->power.request = RPM_REQ_RESUME; dev->power.request_pending = true; -- cgit v1.2.3 From 0ddf0ed1d47e2d4170fa2989273886a1df66a862 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 3 Dec 2009 21:03:57 +0100 Subject: PM / Runtime: Ensure timer_expires is nonzero in pm_schedule_suspend() The runtime PM core code assumes that dev->power.timer_expires is nonzero when the timer is scheduled, but it may become zero incidentally in pm_schedule_suspend(). Prevent this from happening by bumping dev->power.timer_expires up to 1 if it's 0 before calling mod_timer(). Signed-off-by: Rafael J. Wysocki Reported-by: Alan Stern --- drivers/base/power/runtime.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 6e8577d1f750..637706951885 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -625,6 +625,8 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay) goto out; dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); + if (!dev->power.timer_expires) + dev->power.timer_expires = 1; mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); out: -- cgit v1.2.3 From 965c4ac0613b071d6f035334c5d9d942013df4f9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 3 Dec 2009 21:04:41 +0100 Subject: PM / Runtime: Remove unnecessary braces in __pm_runtime_set_status() Some braces in __pm_runtime_set_status() are not necessary, so remove them. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 637706951885..5a01ecef4af3 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -791,12 +791,10 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) */ if (!parent->power.disable_depth && !parent->power.ignore_children - && parent->power.runtime_status != RPM_ACTIVE) { + && parent->power.runtime_status != RPM_ACTIVE) error = -EBUSY; - } else { - if (dev->power.runtime_status == RPM_SUSPENDED) - atomic_inc(&parent->power.child_count); - } + else if (dev->power.runtime_status == RPM_SUSPENDED) + atomic_inc(&parent->power.child_count); spin_unlock(&parent->power.lock); -- cgit v1.2.3