Commit 02b26774 authored by Kevin Hilman's avatar Kevin Hilman Committed by Rafael J. Wysocki

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: default avatarColin Cross <ccross@google.com>
Tested-by: default avatarNishanth Menon <nm@ti.com>
Signed-off-by: default avatarKevin Hilman <khilman@ti.com>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent fe202fde
......@@ -54,11 +54,10 @@ referred to as subsystem-level callbacks in what follows.
By default, the callbacks are always invoked in process context with interrupts
enabled. However, subsystems can use the pm_runtime_irq_safe() helper function
to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume()
callbacks should be invoked in atomic context with interrupts disabled
(->runtime_idle() is still invoked the default way). This implies that these
callback routines must not block or sleep, but it also means that the
synchronous helper functions listed at the end of Section 4 can be used within
an interrupt handler or in an atomic context.
callbacks should be invoked in atomic context with interrupts disabled.
This implies that these callback routines must not block or sleep, but it also
means that the synchronous helper functions listed at the end of Section 4 can
be used within an interrupt handler or in an atomic context.
The subsystem-level suspend callback is _entirely_ _responsible_ for handling
the suspend of the device as appropriate, which may, but need not include
......@@ -483,6 +482,7 @@ pm_runtime_suspend()
pm_runtime_autosuspend()
pm_runtime_resume()
pm_runtime_get_sync()
pm_runtime_put_sync()
pm_runtime_put_sync_suspend()
5. Runtime PM Initialization, Device Probing and Removal
......
......@@ -226,11 +226,17 @@ static int rpm_idle(struct device *dev, int rpmflags)
callback = NULL;
if (callback) {
spin_unlock_irq(&dev->power.lock);
if (dev->power.irq_safe)
spin_unlock(&dev->power.lock);
else
spin_unlock_irq(&dev->power.lock);
callback(dev);
spin_lock_irq(&dev->power.lock);
if (dev->power.irq_safe)
spin_lock(&dev->power.lock);
else
spin_lock_irq(&dev->power.lock);
}
dev->power.idle_notification = false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment