PM / Runtime: Add might_sleep() to runtime PM functions
Some of the entry points to pm runtime are not safe to call in atomic context unless pm_runtime_irq_safe() has been called. Inspecting the code, it is not immediately obvious that the functions sleep at all, as they run inside a spin_lock_irqsave, but under some conditions they can drop the lock and turn on irqs. If a driver incorrectly calls the pm_runtime apis, it can cause sleeping and irq processing when it expects to stay in atomic context. Add might_sleep_if to the majority of the __pm_runtime_* entry points to enforce correct usage. Add pm_runtime_put_sync_autosuspend to the list of functions that can be called in atomic context. Signed-off-by: Colin Cross <ccross@android.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
This commit is contained in:
parent
17f2ae7f67
commit
311aab73d2
|
@ -484,6 +484,7 @@ pm_runtime_resume()
|
||||||
pm_runtime_get_sync()
|
pm_runtime_get_sync()
|
||||||
pm_runtime_put_sync()
|
pm_runtime_put_sync()
|
||||||
pm_runtime_put_sync_suspend()
|
pm_runtime_put_sync_suspend()
|
||||||
|
pm_runtime_put_sync_autosuspend()
|
||||||
|
|
||||||
5. Runtime PM Initialization, Device Probing and Removal
|
5. Runtime PM Initialization, Device Probing and Removal
|
||||||
|
|
||||||
|
|
|
@ -732,13 +732,16 @@ EXPORT_SYMBOL_GPL(pm_schedule_suspend);
|
||||||
* return immediately if it is larger than zero. Then carry out an idle
|
* return immediately if it is larger than zero. Then carry out an idle
|
||||||
* notification, either synchronous or asynchronous.
|
* notification, either synchronous or asynchronous.
|
||||||
*
|
*
|
||||||
* This routine may be called in atomic context if the RPM_ASYNC flag is set.
|
* This routine may be called in atomic context if the RPM_ASYNC flag is set,
|
||||||
|
* or if pm_runtime_irq_safe() has been called.
|
||||||
*/
|
*/
|
||||||
int __pm_runtime_idle(struct device *dev, int rpmflags)
|
int __pm_runtime_idle(struct device *dev, int rpmflags)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
|
||||||
|
|
||||||
if (rpmflags & RPM_GET_PUT) {
|
if (rpmflags & RPM_GET_PUT) {
|
||||||
if (!atomic_dec_and_test(&dev->power.usage_count))
|
if (!atomic_dec_and_test(&dev->power.usage_count))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -761,13 +764,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle);
|
||||||
* return immediately if it is larger than zero. Then carry out a suspend,
|
* return immediately if it is larger than zero. Then carry out a suspend,
|
||||||
* either synchronous or asynchronous.
|
* either synchronous or asynchronous.
|
||||||
*
|
*
|
||||||
* This routine may be called in atomic context if the RPM_ASYNC flag is set.
|
* This routine may be called in atomic context if the RPM_ASYNC flag is set,
|
||||||
|
* or if pm_runtime_irq_safe() has been called.
|
||||||
*/
|
*/
|
||||||
int __pm_runtime_suspend(struct device *dev, int rpmflags)
|
int __pm_runtime_suspend(struct device *dev, int rpmflags)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
|
||||||
|
|
||||||
if (rpmflags & RPM_GET_PUT) {
|
if (rpmflags & RPM_GET_PUT) {
|
||||||
if (!atomic_dec_and_test(&dev->power.usage_count))
|
if (!atomic_dec_and_test(&dev->power.usage_count))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -789,13 +795,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
|
||||||
* If the RPM_GET_PUT flag is set, increment the device's usage count. Then
|
* If the RPM_GET_PUT flag is set, increment the device's usage count. Then
|
||||||
* carry out a resume, either synchronous or asynchronous.
|
* carry out a resume, either synchronous or asynchronous.
|
||||||
*
|
*
|
||||||
* This routine may be called in atomic context if the RPM_ASYNC flag is set.
|
* This routine may be called in atomic context if the RPM_ASYNC flag is set,
|
||||||
|
* or if pm_runtime_irq_safe() has been called.
|
||||||
*/
|
*/
|
||||||
int __pm_runtime_resume(struct device *dev, int rpmflags)
|
int __pm_runtime_resume(struct device *dev, int rpmflags)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
|
||||||
|
|
||||||
if (rpmflags & RPM_GET_PUT)
|
if (rpmflags & RPM_GET_PUT)
|
||||||
atomic_inc(&dev->power.usage_count);
|
atomic_inc(&dev->power.usage_count);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue