aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Hilman <khilman@ti.com>2011-08-05 15:45:20 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-08-05 15:45:20 -0400
commit02b26774afebb2d62695ba3230319d70d8c6cc2d (patch)
tree956c4056fcb42d2c2b2a75e20d3ad98f148865fc
parentfe202fde50a986a8510c62a76dc8733c1a8fac86 (diff)
PM / Runtime: Allow _put_sync() from interrupts-disabled context
Currently the use of pm_runtime_put_sync() is not safe from interrupts-disabled context because rpm_idle() will release the spinlock and enable interrupts for the idle callbacks. This enables interrupts during a time where interrupts were expected to be disabled, and can have strange side effects on drivers that expected interrupts to be disabled. This is not a bug since the documentation clearly states that only _put_sync_suspend() is safe in IRQ-safe mode. However, pm_runtime_put_sync() could be made safe when in IRQ-safe mode by releasing the spinlock but not re-enabling interrupts, which is what this patch aims to do. Problem was found when using some buggy drivers that set pm_runtime_irq_safe() and used _put_sync() in interrupts-disabled context. Reported-by: Colin Cross <ccross@google.com> Tested-by: Nishanth Menon <nm@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--Documentation/power/runtime_pm.txt10
-rw-r--r--drivers/base/power/runtime.c10
2 files changed, 13 insertions, 7 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 14dd3c6ad97e..4ce5450ab6e8 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -54,11 +54,10 @@ referred to as subsystem-level callbacks in what follows.
54By default, the callbacks are always invoked in process context with interrupts 54By default, the callbacks are always invoked in process context with interrupts
55enabled. However, subsystems can use the pm_runtime_irq_safe() helper function 55enabled. However, subsystems can use the pm_runtime_irq_safe() helper function
56to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume() 56to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume()
57callbacks should be invoked in atomic context with interrupts disabled 57callbacks should be invoked in atomic context with interrupts disabled.
58(->runtime_idle() is still invoked the default way). This implies that these 58This implies that these callback routines must not block or sleep, but it also
59callback routines must not block or sleep, but it also means that the 59means that the synchronous helper functions listed at the end of Section 4 can
60synchronous helper functions listed at the end of Section 4 can be used within 60be used within an interrupt handler or in an atomic context.
61an interrupt handler or in an atomic context.
62 61
63The subsystem-level suspend callback is _entirely_ _responsible_ for handling 62The subsystem-level suspend callback is _entirely_ _responsible_ for handling
64the suspend of the device as appropriate, which may, but need not include 63the suspend of the device as appropriate, which may, but need not include
@@ -483,6 +482,7 @@ pm_runtime_suspend()
483pm_runtime_autosuspend() 482pm_runtime_autosuspend()
484pm_runtime_resume() 483pm_runtime_resume()
485pm_runtime_get_sync() 484pm_runtime_get_sync()
485pm_runtime_put_sync()
486pm_runtime_put_sync_suspend() 486pm_runtime_put_sync_suspend()
487 487
4885. Runtime PM Initialization, Device Probing and Removal 4885. Runtime PM Initialization, Device Probing and Removal
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 8dc247c974af..acb3f83b8079 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -226,11 +226,17 @@ static int rpm_idle(struct device *dev, int rpmflags)
226 callback = NULL; 226 callback = NULL;
227 227
228 if (callback) { 228 if (callback) {
229 spin_unlock_irq(&dev->power.lock); 229 if (dev->power.irq_safe)
230 spin_unlock(&dev->power.lock);
231 else
232 spin_unlock_irq(&dev->power.lock);
230 233
231 callback(dev); 234 callback(dev);
232 235
233 spin_lock_irq(&dev->power.lock); 236 if (dev->power.irq_safe)
237 spin_lock(&dev->power.lock);
238 else
239 spin_lock_irq(&dev->power.lock);
234 } 240 }
235 241
236 dev->power.idle_notification = false; 242 dev->power.idle_notification = false;