Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 235152
b: refs/heads/master
c: 9659cc0
h: refs/heads/master
v: v3
  • Loading branch information
Rafael J. Wysocki committed Mar 14, 2011
1 parent 3f01e20 commit 6c225c3
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 119 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cf4fb80ca3d591cae366ae8364e3c3f7a68bd249
refs/heads/master: 9659cc0678b954f187290c6e8b247a673c5d37e1
29 changes: 12 additions & 17 deletions trunk/Documentation/power/devices.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,23 +249,18 @@ various phases always run after tasks have been frozen and before they are
unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have
been disabled (except for those marked with the IRQ_WAKEUP flag).

Most phases use bus, type, and class callbacks (that is, methods defined in
dev->bus->pm, dev->type->pm, and dev->class->pm). The prepare and complete
phases are exceptions; they use only bus callbacks. When multiple callbacks
are used in a phase, they are invoked in the order: <class, type, bus> during
power-down transitions and in the opposite order during power-up transitions.
For example, during the suspend phase the PM core invokes

dev->class->pm.suspend(dev);
dev->type->pm.suspend(dev);
dev->bus->pm.suspend(dev);

before moving on to the next device, whereas during the resume phase the core
invokes

dev->bus->pm.resume(dev);
dev->type->pm.resume(dev);
dev->class->pm.resume(dev);
All phases use bus, type, or class callbacks (that is, methods defined in
dev->bus->pm, dev->type->pm, or dev->class->pm). These callbacks are mutually
exclusive, so if the device type provides a struct dev_pm_ops object pointed to
by its pm field (i.e. both dev->type and dev->type->pm are defined), the
callbacks included in that object (i.e. dev->type->pm) will be used. Otherwise,
if the class provides a struct dev_pm_ops object pointed to by its pm field
(i.e. both dev->class and dev->class->pm are defined), the PM core will use the
callbacks from that object (i.e. dev->class->pm). Finally, if the pm fields of
both the device type and class objects are NULL (or those objects do not exist),
the callbacks provided by the bus (that is, the callbacks from dev->bus->pm)
will be used (this allows device types to override callbacks provided by bus
types or classes if necessary).

These callbacks may in turn invoke device- or driver-specific methods stored in
dev->driver->pm, but they don't have to.
Expand Down
13 changes: 7 additions & 6 deletions trunk/Documentation/power/runtime_pm.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Run-time Power Management Framework for I/O Devices

(C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
(C) 2009-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
(C) 2010 Alan Stern <stern@rowland.harvard.edu>

1. Introduction
Expand Down Expand Up @@ -44,11 +44,12 @@ struct dev_pm_ops {
};

The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
executed by the PM core for either the bus type, or device type (if the bus
type's callback is not defined), or device class (if the bus type's and device
type's callbacks are not defined) of given device. The bus type, device type
and device class callbacks are referred to as subsystem-level callbacks in what
follows.
executed by the PM core for either the device type, or the class (if the device
type's struct dev_pm_ops object does not exist), or the bus type (if the
device type's and class' struct dev_pm_ops objects do not exist) of the given
device (this allows device types to override callbacks provided by bus types or
classes if necessary). The bus type, device type and class callbacks are
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
Expand Down
150 changes: 64 additions & 86 deletions trunk/drivers/base/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,26 +428,17 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
pm_noirq_op(dev, &dev->pwr_domain->ops, state);
}

if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "EARLY ");
error = pm_noirq_op(dev, dev->bus->pm, state);
if (error)
goto End;
}

if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "EARLY type ");
error = pm_noirq_op(dev, dev->type->pm, state);
if (error)
goto End;
}

if (dev->class && dev->class->pm) {
} else if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "EARLY class ");
error = pm_noirq_op(dev, dev->class->pm, state);
} else if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "EARLY ");
error = pm_noirq_op(dev, dev->bus->pm, state);
}

End:
TRACE_RESUME(error);
return error;
}
Expand Down Expand Up @@ -528,36 +519,34 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
pm_op(dev, &dev->pwr_domain->ops, state);
}

if (dev->bus) {
if (dev->bus->pm) {
pm_dev_dbg(dev, state, "");
error = pm_op(dev, dev->bus->pm, state);
} else if (dev->bus->resume) {
pm_dev_dbg(dev, state, "legacy ");
error = legacy_resume(dev, dev->bus->resume);
}
if (error)
goto End;
}

if (dev->type) {
if (dev->type->pm) {
pm_dev_dbg(dev, state, "type ");
error = pm_op(dev, dev->type->pm, state);
}
if (error)
goto End;
if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "type ");
error = pm_op(dev, dev->type->pm, state);
goto End;
}

if (dev->class) {
if (dev->class->pm) {
pm_dev_dbg(dev, state, "class ");
error = pm_op(dev, dev->class->pm, state);
goto End;
} else if (dev->class->resume) {
pm_dev_dbg(dev, state, "legacy class ");
error = legacy_resume(dev, dev->class->resume);
goto End;
}
}

if (dev->bus) {
if (dev->bus->pm) {
pm_dev_dbg(dev, state, "");
error = pm_op(dev, dev->bus->pm, state);
} else if (dev->bus->resume) {
pm_dev_dbg(dev, state, "legacy ");
error = legacy_resume(dev, dev->bus->resume);
}
}

End:
device_unlock(dev);
complete_all(&dev->power.completion);
Expand Down Expand Up @@ -644,19 +633,18 @@ static void device_complete(struct device *dev, pm_message_t state)
dev->pwr_domain->ops.complete(dev);
}

if (dev->class && dev->class->pm && dev->class->pm->complete) {
pm_dev_dbg(dev, state, "completing class ");
dev->class->pm->complete(dev);
}

if (dev->type && dev->type->pm && dev->type->pm->complete) {
if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "completing type ");
dev->type->pm->complete(dev);
}

if (dev->bus && dev->bus->pm && dev->bus->pm->complete) {
if (dev->type->pm->complete)
dev->type->pm->complete(dev);
} else if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "completing class ");
if (dev->class->pm->complete)
dev->class->pm->complete(dev);
} else if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "completing ");
dev->bus->pm->complete(dev);
if (dev->bus->pm->complete)
dev->bus->pm->complete(dev);
}

device_unlock(dev);
Expand Down Expand Up @@ -741,36 +729,31 @@ static pm_message_t resume_event(pm_message_t sleep_state)
*/
static int device_suspend_noirq(struct device *dev, pm_message_t state)
{
int error = 0;

if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "LATE class ");
error = pm_noirq_op(dev, dev->class->pm, state);
if (error)
goto End;
}
int error;

if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "LATE type ");
error = pm_noirq_op(dev, dev->type->pm, state);
if (error)
goto End;
}

if (dev->bus && dev->bus->pm) {
return error;
} else if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "LATE class ");
error = pm_noirq_op(dev, dev->class->pm, state);
if (error)
return error;
} else if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "LATE ");
error = pm_noirq_op(dev, dev->bus->pm, state);
if (error)
goto End;
return error;
}

if (dev->pwr_domain) {
pm_dev_dbg(dev, state, "LATE power domain ");
pm_noirq_op(dev, &dev->pwr_domain->ops, state);
}

End:
return error;
return 0;
}

/**
Expand Down Expand Up @@ -857,25 +840,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
goto End;
}

if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "type ");
error = pm_op(dev, dev->type->pm, state);
goto Domain;
}

if (dev->class) {
if (dev->class->pm) {
pm_dev_dbg(dev, state, "class ");
error = pm_op(dev, dev->class->pm, state);
goto Domain;
} else if (dev->class->suspend) {
pm_dev_dbg(dev, state, "legacy class ");
error = legacy_suspend(dev, state, dev->class->suspend);
goto Domain;
}
if (error)
goto End;
}

if (dev->type) {
if (dev->type->pm) {
pm_dev_dbg(dev, state, "type ");
error = pm_op(dev, dev->type->pm, state);
}
if (error)
goto End;
}

if (dev->bus) {
Expand All @@ -886,11 +866,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
pm_dev_dbg(dev, state, "legacy ");
error = legacy_suspend(dev, state, dev->bus->suspend);
}
if (error)
goto End;
}

if (dev->pwr_domain) {
Domain:
if (!error && dev->pwr_domain) {
pm_dev_dbg(dev, state, "power domain ");
pm_op(dev, &dev->pwr_domain->ops, state);
}
Expand Down Expand Up @@ -985,28 +964,27 @@ static int device_prepare(struct device *dev, pm_message_t state)

device_lock(dev);

if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
pm_dev_dbg(dev, state, "preparing ");
error = dev->bus->pm->prepare(dev);
suspend_report_result(dev->bus->pm->prepare, error);
if (error)
goto End;
}

if (dev->type && dev->type->pm && dev->type->pm->prepare) {
if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "preparing type ");
error = dev->type->pm->prepare(dev);
if (dev->type->pm->prepare)
error = dev->type->pm->prepare(dev);
suspend_report_result(dev->type->pm->prepare, error);
if (error)
goto End;
}

if (dev->class && dev->class->pm && dev->class->pm->prepare) {
} else if (dev->class && dev->class->pm) {
pm_dev_dbg(dev, state, "preparing class ");
error = dev->class->pm->prepare(dev);
if (dev->class->pm->prepare)
error = dev->class->pm->prepare(dev);
suspend_report_result(dev->class->pm->prepare, error);
if (error)
goto End;
} 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);
if (error)
goto End;
}

if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {
Expand Down
18 changes: 9 additions & 9 deletions trunk/drivers/base/power/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,12 @@ static int rpm_idle(struct device *dev, int rpmflags)

dev->power.idle_notification = true;

if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle)
callback = dev->bus->pm->runtime_idle;
else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle)
if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_idle;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_idle;
else if (dev->bus && dev->bus->pm)
callback = dev->bus->pm->runtime_idle;
else
callback = NULL;

Expand Down Expand Up @@ -382,12 +382,12 @@ static int rpm_suspend(struct device *dev, int rpmflags)

__update_runtime_status(dev, RPM_SUSPENDING);

if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
callback = dev->bus->pm->runtime_suspend;
else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend)
if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_suspend;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_suspend;
else if (dev->bus && dev->bus->pm)
callback = dev->bus->pm->runtime_suspend;
else
callback = NULL;

Expand Down Expand Up @@ -584,12 +584,12 @@ static int rpm_resume(struct device *dev, int rpmflags)
if (dev->pwr_domain)
rpm_callback(dev->pwr_domain->ops.runtime_resume, dev);

if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
callback = dev->bus->pm->runtime_resume;
else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume)
if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_resume;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_resume;
else if (dev->bus && dev->bus->pm)
callback = dev->bus->pm->runtime_resume;
else
callback = NULL;

Expand Down

0 comments on commit 6c225c3

Please sign in to comment.