Commit 9cf519d1 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

PM / Sleep: Make pm_op() and pm_noirq_op() return callback pointers

Make the pm_op() and pm_noirq_op() functions return pointers to
appropriate callbacks instead of executing those callbacks and
returning their results.

This change is required for a subsequent modification that will
execute the corresponding driver callback if the subsystem
callback returned by either pm_op(), or pm_noirq_op() is NULL.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent b00f4dc5
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include "../base.h" #include "../base.h"
#include "power.h" #include "power.h"
typedef int (*pm_callback_t)(struct device *);
/* /*
* The entries in the dpm_list list are in a depth first order, simply * The entries in the dpm_list list are in a depth first order, simply
* because children are guaranteed to be discovered after parents, and * because children are guaranteed to be discovered after parents, and
...@@ -211,113 +213,70 @@ static void dpm_wait_for_children(struct device *dev, bool async) ...@@ -211,113 +213,70 @@ static void dpm_wait_for_children(struct device *dev, bool async)
device_for_each_child(dev, &async, dpm_wait_fn); device_for_each_child(dev, &async, dpm_wait_fn);
} }
static int dpm_run_callback(struct device *dev, int (*cb)(struct device *))
{
ktime_t calltime;
int error;
if (!cb)
return 0;
calltime = initcall_debug_start(dev);
error = cb(dev);
suspend_report_result(cb, error);
initcall_debug_report(dev, calltime, error);
return error;
}
/** /**
* pm_op - Execute the PM operation appropriate for given PM event. * pm_op - Return the PM operation appropriate for given PM event.
* @dev: Device to handle.
* @ops: PM operations to choose from. * @ops: PM operations to choose from.
* @state: PM transition of the system being carried out. * @state: PM transition of the system being carried out.
*/ */
static int pm_op(struct device *dev, static pm_callback_t pm_op(const struct dev_pm_ops *ops, pm_message_t state)
const struct dev_pm_ops *ops,
pm_message_t state)
{ {
int error = 0;
switch (state.event) { switch (state.event) {
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
case PM_EVENT_SUSPEND: case PM_EVENT_SUSPEND:
error = dpm_run_callback(dev, ops->suspend); return ops->suspend;
break;
case PM_EVENT_RESUME: case PM_EVENT_RESUME:
error = dpm_run_callback(dev, ops->resume); return ops->resume;
break;
#endif /* CONFIG_SUSPEND */ #endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATE_CALLBACKS #ifdef CONFIG_HIBERNATE_CALLBACKS
case PM_EVENT_FREEZE: case PM_EVENT_FREEZE:
case PM_EVENT_QUIESCE: case PM_EVENT_QUIESCE:
error = dpm_run_callback(dev, ops->freeze); return ops->freeze;
break;
case PM_EVENT_HIBERNATE: case PM_EVENT_HIBERNATE:
error = dpm_run_callback(dev, ops->poweroff); return ops->poweroff;
break;
case PM_EVENT_THAW: case PM_EVENT_THAW:
case PM_EVENT_RECOVER: case PM_EVENT_RECOVER:
error = dpm_run_callback(dev, ops->thaw); return ops->thaw;
break; break;
case PM_EVENT_RESTORE: case PM_EVENT_RESTORE:
error = dpm_run_callback(dev, ops->restore); return ops->restore;
break;
#endif /* CONFIG_HIBERNATE_CALLBACKS */ #endif /* CONFIG_HIBERNATE_CALLBACKS */
default:
error = -EINVAL;
} }
return error; return NULL;
} }
/** /**
* pm_noirq_op - Execute the PM operation appropriate for given PM event. * pm_noirq_op - Return the PM operation appropriate for given PM event.
* @dev: Device to handle.
* @ops: PM operations to choose from. * @ops: PM operations to choose from.
* @state: PM transition of the system being carried out. * @state: PM transition of the system being carried out.
* *
* The driver of @dev will not receive interrupts while this function is being * The driver of @dev will not receive interrupts while this function is being
* executed. * executed.
*/ */
static int pm_noirq_op(struct device *dev, static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t state)
const struct dev_pm_ops *ops,
pm_message_t state)
{ {
int error = 0;
switch (state.event) { switch (state.event) {
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
case PM_EVENT_SUSPEND: case PM_EVENT_SUSPEND:
error = dpm_run_callback(dev, ops->suspend_noirq); return ops->suspend_noirq;
break;
case PM_EVENT_RESUME: case PM_EVENT_RESUME:
error = dpm_run_callback(dev, ops->resume_noirq); return ops->resume_noirq;
break;
#endif /* CONFIG_SUSPEND */ #endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATE_CALLBACKS #ifdef CONFIG_HIBERNATE_CALLBACKS
case PM_EVENT_FREEZE: case PM_EVENT_FREEZE:
case PM_EVENT_QUIESCE: case PM_EVENT_QUIESCE:
error = dpm_run_callback(dev, ops->freeze_noirq); return ops->freeze_noirq;
break;
case PM_EVENT_HIBERNATE: case PM_EVENT_HIBERNATE:
error = dpm_run_callback(dev, ops->poweroff_noirq); return ops->poweroff_noirq;
break;
case PM_EVENT_THAW: case PM_EVENT_THAW:
case PM_EVENT_RECOVER: case PM_EVENT_RECOVER:
error = dpm_run_callback(dev, ops->thaw_noirq); return ops->thaw_noirq;
break;
case PM_EVENT_RESTORE: case PM_EVENT_RESTORE:
error = dpm_run_callback(dev, ops->restore_noirq); return ops->restore_noirq;
break;
#endif /* CONFIG_HIBERNATE_CALLBACKS */ #endif /* CONFIG_HIBERNATE_CALLBACKS */
default:
error = -EINVAL;
} }
return error; return NULL;
} }
static char *pm_verb(int event) static char *pm_verb(int event)
...@@ -375,6 +334,26 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) ...@@ -375,6 +334,26 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
} }
static int dpm_run_callback(pm_callback_t cb, struct device *dev,
pm_message_t state, char *info)
{
ktime_t calltime;
int error;
if (!cb)
return 0;
calltime = initcall_debug_start(dev);
pm_dev_dbg(dev, state, info);
error = cb(dev);
suspend_report_result(cb, error);
initcall_debug_report(dev, calltime, error);
return error;
}
/*------------------------- Resume routines -------------------------*/ /*------------------------- Resume routines -------------------------*/
/** /**
...@@ -387,25 +366,29 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) ...@@ -387,25 +366,29 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
*/ */
static int device_resume_noirq(struct device *dev, pm_message_t state) static int device_resume_noirq(struct device *dev, pm_message_t state)
{ {
pm_callback_t callback = NULL;
char *info = NULL;
int error = 0; int error = 0;
TRACE_DEVICE(dev); TRACE_DEVICE(dev);
TRACE_RESUME(0); TRACE_RESUME(0);
if (dev->pm_domain) { if (dev->pm_domain) {
pm_dev_dbg(dev, state, "EARLY power domain "); info = "EARLY power domain ";
error = pm_noirq_op(dev, &dev->pm_domain->ops, state); callback = pm_noirq_op(&dev->pm_domain->ops, state);
} else if (dev->type && dev->type->pm) { } else if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "EARLY type "); info = "EARLY type ";
error = pm_noirq_op(dev, dev->type->pm, state); callback = pm_noirq_op(dev->type->pm, state);
} else if (dev->class && dev->class->pm) { } else if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "EARLY class "); info = "EARLY class ";
error = pm_noirq_op(dev, dev->class->pm, state); callback = pm_noirq_op(dev->class->pm, state);
} else if (dev->bus && dev->bus->pm) { } else if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "EARLY "); info = "EARLY ";
error = pm_noirq_op(dev, dev->bus->pm, state); callback = pm_noirq_op(dev->bus->pm, state);
} }
error = dpm_run_callback(callback, dev, state, info);
TRACE_RESUME(error); TRACE_RESUME(error);
return error; return error;
} }
...@@ -455,6 +438,8 @@ EXPORT_SYMBOL_GPL(dpm_resume_noirq); ...@@ -455,6 +438,8 @@ EXPORT_SYMBOL_GPL(dpm_resume_noirq);
*/ */
static int device_resume(struct device *dev, pm_message_t state, bool async) static int device_resume(struct device *dev, pm_message_t state, bool async)
{ {
pm_callback_t callback = NULL;
char *info = NULL;
int error = 0; int error = 0;
bool put = false; bool put = false;
...@@ -477,40 +462,41 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) ...@@ -477,40 +462,41 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
put = true; put = true;
if (dev->pm_domain) { if (dev->pm_domain) {
pm_dev_dbg(dev, state, "power domain "); info = "power domain ";
error = pm_op(dev, &dev->pm_domain->ops, state); callback = pm_op(&dev->pm_domain->ops, state);
goto End; goto End;
} }
if (dev->type && dev->type->pm) { if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "type "); info = "type ";
error = pm_op(dev, dev->type->pm, state); callback = pm_op(dev->type->pm, state);
goto End; goto End;
} }
if (dev->class) { if (dev->class) {
if (dev->class->pm) { if (dev->class->pm) {
pm_dev_dbg(dev, state, "class "); info = "class ";
error = pm_op(dev, dev->class->pm, state); callback = pm_op(dev->class->pm, state);
goto End; goto End;
} else if (dev->class->resume) { } else if (dev->class->resume) {
pm_dev_dbg(dev, state, "legacy class "); info = "legacy class ";
error = dpm_run_callback(dev, dev->class->resume); callback = dev->class->resume;
goto End; goto End;
} }
} }
if (dev->bus) { if (dev->bus) {
if (dev->bus->pm) { if (dev->bus->pm) {
pm_dev_dbg(dev, state, ""); info = "";
error = pm_op(dev, dev->bus->pm, state); callback = pm_op(dev->bus->pm, state);
} else if (dev->bus->resume) { } else if (dev->bus->resume) {
pm_dev_dbg(dev, state, "legacy "); info = "legacy ";
error = dpm_run_callback(dev, dev->bus->resume); callback = dev->bus->resume;
} }
} }
End: End:
error = dpm_run_callback(callback, dev, state, info);
dev->power.is_suspended = false; dev->power.is_suspended = false;
Unlock: Unlock:
...@@ -705,23 +691,24 @@ static pm_message_t resume_event(pm_message_t sleep_state) ...@@ -705,23 +691,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
*/ */
static int device_suspend_noirq(struct device *dev, pm_message_t state) static int device_suspend_noirq(struct device *dev, pm_message_t state)
{ {
int error = 0; pm_callback_t callback = NULL;
char *info = NULL;
if (dev->pm_domain) { if (dev->pm_domain) {
pm_dev_dbg(dev, state, "LATE power domain "); info = "LATE power domain ";
error = pm_noirq_op(dev, &dev->pm_domain->ops, state); callback = pm_noirq_op(&dev->pm_domain->ops, state);
} else if (dev->type && dev->type->pm) { } else if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "LATE type "); info = "LATE type ";
error = pm_noirq_op(dev, dev->type->pm, state); callback = pm_noirq_op(dev->type->pm, state);
} else if (dev->class && dev->class->pm) { } else if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "LATE class "); info = "LATE class ";
error = pm_noirq_op(dev, dev->class->pm, state); callback = pm_noirq_op(dev->class->pm, state);
} else if (dev->bus && dev->bus->pm) { } else if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "LATE "); info = "LATE ";
error = pm_noirq_op(dev, dev->bus->pm, state); callback = pm_noirq_op(dev->bus->pm, state);
} }
return error; return dpm_run_callback(callback, dev, state, info);
} }
/** /**
...@@ -798,6 +785,8 @@ static int legacy_suspend(struct device *dev, pm_message_t state, ...@@ -798,6 +785,8 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
*/ */
static int __device_suspend(struct device *dev, pm_message_t state, bool async) static int __device_suspend(struct device *dev, pm_message_t state, bool async)
{ {
pm_callback_t callback = NULL;
char *info = NULL;
int error = 0; int error = 0;
dpm_wait_for_children(dev, async); dpm_wait_for_children(dev, async);
...@@ -818,22 +807,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) ...@@ -818,22 +807,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
device_lock(dev); device_lock(dev);
if (dev->pm_domain) { if (dev->pm_domain) {
pm_dev_dbg(dev, state, "power domain "); info = "power domain ";
error = pm_op(dev, &dev->pm_domain->ops, state); callback = pm_op(&dev->pm_domain->ops, state);
goto End; goto Run;
} }
if (dev->type && dev->type->pm) { if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "type "); info = "type ";
error = pm_op(dev, dev->type->pm, state); callback = pm_op(dev->type->pm, state);
goto End; goto Run;
} }
if (dev->class) { if (dev->class) {
if (dev->class->pm) { if (dev->class->pm) {
pm_dev_dbg(dev, state, "class "); info = "class ";
error = pm_op(dev, dev->class->pm, state); callback = pm_op(dev->class->pm, state);
goto End; goto Run;
} else if (dev->class->suspend) { } else if (dev->class->suspend) {
pm_dev_dbg(dev, state, "legacy class "); pm_dev_dbg(dev, state, "legacy class ");
error = legacy_suspend(dev, state, dev->class->suspend); error = legacy_suspend(dev, state, dev->class->suspend);
...@@ -843,14 +832,18 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) ...@@ -843,14 +832,18 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (dev->bus) { if (dev->bus) {
if (dev->bus->pm) { if (dev->bus->pm) {
pm_dev_dbg(dev, state, ""); info = "";
error = pm_op(dev, dev->bus->pm, state); callback = pm_op(dev->bus->pm, state);
} else if (dev->bus->suspend) { } else if (dev->bus->suspend) {
pm_dev_dbg(dev, state, "legacy "); pm_dev_dbg(dev, state, "legacy ");
error = legacy_suspend(dev, state, dev->bus->suspend); error = legacy_suspend(dev, state, dev->bus->suspend);
goto End;
} }
} }
Run:
error = dpm_run_callback(callback, dev, state, info);
End: End:
if (!error) { if (!error) {
dev->power.is_suspended = true; dev->power.is_suspended = true;
......
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