summaryrefslogtreecommitdiff
path: root/drivers/base/power/main.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-12-18 00:34:13 +0100
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-21 22:01:05 +0100
commit35cd133c6130c1eb52806808abee9d62e6854a27 (patch)
tree2f06e7f0288b9d4a3785a202f6480928113d8d5c /drivers/base/power/main.c
parent9cf519d1c15fa05a538c2b3963c5f3903daf765a (diff)
PM: Run the driver callback directly if the subsystem one is not there
Make the PM core execute driver PM callbacks directly if the corresponding subsystem callbacks are not present. There are three reasons for doing that. First, it reflects the behavior of drivers/base/dd.c:really_probe() that runs the driver's .probe() callback directly if the bus type's one is not defined, so this change will remove one arbitrary difference between the PM core and the remaining parts of the driver core. Second, it will allow some subsystems, whose PM callbacks don't do anything except for executing driver callbacks, to be simplified quite a bit by removing those "forward-only" callbacks. Finally, it will allow us to remove one level of indirection in the system suspend and resume code paths where it is not necessary, which is going to lead to less debug noise with initcall_debug passed in the kernel command line (messages won't be printed for driverless devices whose subsystems don't provide PM callbacks among other things). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r--drivers/base/power/main.c109
1 files changed, 72 insertions, 37 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index b5cef7e7de2..e2cc3d2e0ec 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -383,10 +383,15 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
info = "EARLY class ";
callback = pm_noirq_op(dev->class->pm, state);
} else if (dev->bus && dev->bus->pm) {
- info = "EARLY ";
+ info = "EARLY bus ";
callback = pm_noirq_op(dev->bus->pm, state);
}
+ if (!callback && dev->driver && dev->driver->pm) {
+ info = "EARLY driver ";
+ callback = pm_noirq_op(dev->driver->pm, state);
+ }
+
error = dpm_run_callback(callback, dev, state, info);
TRACE_RESUME(error);
@@ -464,20 +469,20 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (dev->pm_domain) {
info = "power domain ";
callback = pm_op(&dev->pm_domain->ops, state);
- goto End;
+ goto Driver;
}
if (dev->type && dev->type->pm) {
info = "type ";
callback = pm_op(dev->type->pm, state);
- goto End;
+ goto Driver;
}
if (dev->class) {
if (dev->class->pm) {
info = "class ";
callback = pm_op(dev->class->pm, state);
- goto End;
+ goto Driver;
} else if (dev->class->resume) {
info = "legacy class ";
callback = dev->class->resume;
@@ -487,14 +492,21 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (dev->bus) {
if (dev->bus->pm) {
- info = "";
+ info = "bus ";
callback = pm_op(dev->bus->pm, state);
} else if (dev->bus->resume) {
- info = "legacy ";
+ info = "legacy bus ";
callback = dev->bus->resume;
+ goto End;
}
}
+ Driver:
+ if (!callback && dev->driver && dev->driver->pm) {
+ info = "driver ";
+ callback = pm_op(dev->driver->pm, state);
+ }
+
End:
error = dpm_run_callback(callback, dev, state, info);
dev->power.is_suspended = false;
@@ -588,24 +600,33 @@ void dpm_resume(pm_message_t state)
*/
static void device_complete(struct device *dev, pm_message_t state)
{
+ void (*callback)(struct device *) = NULL;
+ char *info = NULL;
+
device_lock(dev);
if (dev->pm_domain) {
- pm_dev_dbg(dev, state, "completing power domain ");
- if (dev->pm_domain->ops.complete)
- dev->pm_domain->ops.complete(dev);
+ info = "completing power domain ";
+ callback = dev->pm_domain->ops.complete;
} else if (dev->type && dev->type->pm) {
- pm_dev_dbg(dev, state, "completing type ");
- if (dev->type->pm->complete)
- dev->type->pm->complete(dev);
+ info = "completing type ";
+ callback = dev->type->pm->complete;
} else if (dev->class && dev->class->pm) {
- pm_dev_dbg(dev, state, "completing class ");
- if (dev->class->pm->complete)
- dev->class->pm->complete(dev);
+ info = "completing class ";
+ callback = dev->class->pm->complete;
} else if (dev->bus && dev->bus->pm) {
- pm_dev_dbg(dev, state, "completing ");
- if (dev->bus->pm->complete)
- dev->bus->pm->complete(dev);
+ info = "completing bus ";
+ callback = dev->bus->pm->complete;
+ }
+
+ if (!callback && dev->driver && dev->driver->pm) {
+ info = "completing driver ";
+ callback = dev->driver->pm->complete;
+ }
+
+ if (callback) {
+ pm_dev_dbg(dev, state, info);
+ callback(dev);
}
device_unlock(dev);
@@ -704,10 +725,15 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
info = "LATE class ";
callback = pm_noirq_op(dev->class->pm, state);
} else if (dev->bus && dev->bus->pm) {
- info = "LATE ";
+ info = "LATE bus ";
callback = pm_noirq_op(dev->bus->pm, state);
}
+ if (!callback && dev->driver && dev->driver->pm) {
+ info = "LATE driver ";
+ callback = pm_noirq_op(dev->driver->pm, state);
+ }
+
return dpm_run_callback(callback, dev, state, info);
}
@@ -832,16 +858,21 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (dev->bus) {
if (dev->bus->pm) {
- info = "";
+ info = "bus ";
callback = pm_op(dev->bus->pm, state);
} else if (dev->bus->suspend) {
- pm_dev_dbg(dev, state, "legacy ");
+ pm_dev_dbg(dev, state, "legacy bus ");
error = legacy_suspend(dev, state, dev->bus->suspend);
goto End;
}
}
Run:
+ if (!callback && dev->driver && dev->driver->pm) {
+ info = "driver ";
+ callback = pm_op(dev->driver->pm, state);
+ }
+
error = dpm_run_callback(callback, dev, state, info);
End:
@@ -949,6 +980,8 @@ int dpm_suspend(pm_message_t state)
*/
static int device_prepare(struct device *dev, pm_message_t state)
{
+ int (*callback)(struct device *) = NULL;
+ char *info = NULL;
int error = 0;
device_lock(dev);
@@ -956,25 +989,27 @@ static int device_prepare(struct device *dev, pm_message_t state)
dev->power.wakeup_path = device_may_wakeup(dev);
if (dev->pm_domain) {
- pm_dev_dbg(dev, state, "preparing power domain ");
- if (dev->pm_domain->ops.prepare)
- error = dev->pm_domain->ops.prepare(dev);
- suspend_report_result(dev->pm_domain->ops.prepare, error);
+ info = "preparing power domain ";
+ callback = dev->pm_domain->ops.prepare;
} else if (dev->type && dev->type->pm) {
- pm_dev_dbg(dev, state, "preparing type ");
- if (dev->type->pm->prepare)
- error = dev->type->pm->prepare(dev);
- suspend_report_result(dev->type->pm->prepare, error);
+ info = "preparing type ";
+ callback = dev->type->pm->prepare;
} else if (dev->class && dev->class->pm) {
- pm_dev_dbg(dev, state, "preparing class ");
- if (dev->class->pm->prepare)
- error = dev->class->pm->prepare(dev);
- suspend_report_result(dev->class->pm->prepare, error);
+ info = "preparing class ";
+ callback = dev->class->pm->prepare;
} else if (dev->bus && dev->bus->pm) {
- pm_dev_dbg(dev, state, "preparing ");
- if (dev->bus->pm->prepare)
- error = dev->bus->pm->prepare(dev);
- suspend_report_result(dev->bus->pm->prepare, error);
+ info = "preparing bus ";
+ callback = dev->bus->pm->prepare;
+ }
+
+ if (!callback && dev->driver && dev->driver->pm) {
+ info = "preparing driver ";
+ callback = dev->driver->pm->prepare;
+ }
+
+ if (callback) {
+ error = callback(dev);
+ suspend_report_result(callback, error);
}
device_unlock(dev);