diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2009-12-17 19:57:31 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2009-12-17 19:57:31 -0500 |
commit | 875ab0b74e85d6801a49392447d26e0b28688d86 (patch) | |
tree | 03762971d57d0657a12a99f1a73473878c2c7ada /drivers/base/power/main.c | |
parent | b8a7f3cd7e8212e5c572178ff3b5a514861036a5 (diff) |
PM: Make the initcall_debug style timing for suspend/resume complete
Commit f2511774863487e61b56a97da07ebf8dd61d7836
(PM: Add initcall_debug style timing for suspend/resume) introduced
basic timing instrumentation, needed for a scritps/bootgraph.pl
equivalent or humans, but it missed the fact that bus types and
device classes which haven't been switched to using struct dev_pm_ops
objects yet need special handling. As a result, the suspend/resume
timing information is only available for devices whose bus types or
device classes use struct dev_pm_ops objects, so the majority of
devices is not covered.
Fix this by adding basic suspend/resume timing instrumentation for
devices whose bus types and device classes still don't use struct
dev_pm_ops objects for power management. To reduce code duplication
move the timing code to helper functions.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r-- | drivers/base/power/main.c | 97 |
1 files changed, 77 insertions, 20 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1a216c114a0f..c448d5972a0b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -161,6 +161,32 @@ void device_pm_move_last(struct device *dev) | |||
161 | list_move_tail(&dev->power.entry, &dpm_list); | 161 | list_move_tail(&dev->power.entry, &dpm_list); |
162 | } | 162 | } |
163 | 163 | ||
164 | static ktime_t initcall_debug_start(struct device *dev) | ||
165 | { | ||
166 | ktime_t calltime = ktime_set(0, 0); | ||
167 | |||
168 | if (initcall_debug) { | ||
169 | pr_info("calling %s+ @ %i\n", | ||
170 | dev_name(dev), task_pid_nr(current)); | ||
171 | calltime = ktime_get(); | ||
172 | } | ||
173 | |||
174 | return calltime; | ||
175 | } | ||
176 | |||
177 | static void initcall_debug_report(struct device *dev, ktime_t calltime, | ||
178 | int error) | ||
179 | { | ||
180 | ktime_t delta, rettime; | ||
181 | |||
182 | if (initcall_debug) { | ||
183 | rettime = ktime_get(); | ||
184 | delta = ktime_sub(rettime, calltime); | ||
185 | pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), | ||
186 | error, (unsigned long long)ktime_to_ns(delta) >> 10); | ||
187 | } | ||
188 | } | ||
189 | |||
164 | /** | 190 | /** |
165 | * pm_op - Execute the PM operation appropriate for given PM event. | 191 | * pm_op - Execute the PM operation appropriate for given PM event. |
166 | * @dev: Device to handle. | 192 | * @dev: Device to handle. |
@@ -172,13 +198,9 @@ static int pm_op(struct device *dev, | |||
172 | pm_message_t state) | 198 | pm_message_t state) |
173 | { | 199 | { |
174 | int error = 0; | 200 | int error = 0; |
175 | ktime_t calltime, delta, rettime; | 201 | ktime_t calltime; |
176 | 202 | ||
177 | if (initcall_debug) { | 203 | calltime = initcall_debug_start(dev); |
178 | pr_info("calling %s+ @ %i\n", | ||
179 | dev_name(dev), task_pid_nr(current)); | ||
180 | calltime = ktime_get(); | ||
181 | } | ||
182 | 204 | ||
183 | switch (state.event) { | 205 | switch (state.event) { |
184 | #ifdef CONFIG_SUSPEND | 206 | #ifdef CONFIG_SUSPEND |
@@ -227,12 +249,7 @@ static int pm_op(struct device *dev, | |||
227 | error = -EINVAL; | 249 | error = -EINVAL; |
228 | } | 250 | } |
229 | 251 | ||
230 | if (initcall_debug) { | 252 | initcall_debug_report(dev, calltime, error); |
231 | rettime = ktime_get(); | ||
232 | delta = ktime_sub(rettime, calltime); | ||
233 | pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), | ||
234 | error, (unsigned long long)ktime_to_ns(delta) >> 10); | ||
235 | } | ||
236 | 253 | ||
237 | return error; | 254 | return error; |
238 | } | 255 | } |
@@ -309,8 +326,9 @@ static int pm_noirq_op(struct device *dev, | |||
309 | if (initcall_debug) { | 326 | if (initcall_debug) { |
310 | rettime = ktime_get(); | 327 | rettime = ktime_get(); |
311 | delta = ktime_sub(rettime, calltime); | 328 | delta = ktime_sub(rettime, calltime); |
312 | printk("initcall %s_i+ returned %d after %Ld usecs\n", dev_name(dev), | 329 | printk("initcall %s_i+ returned %d after %Ld usecs\n", |
313 | error, (unsigned long long)ktime_to_ns(delta) >> 10); | 330 | dev_name(dev), error, |
331 | (unsigned long long)ktime_to_ns(delta) >> 10); | ||
314 | } | 332 | } |
315 | 333 | ||
316 | return error; | 334 | return error; |
@@ -408,6 +426,26 @@ void dpm_resume_noirq(pm_message_t state) | |||
408 | EXPORT_SYMBOL_GPL(dpm_resume_noirq); | 426 | EXPORT_SYMBOL_GPL(dpm_resume_noirq); |
409 | 427 | ||
410 | /** | 428 | /** |
429 | * legacy_resume - Execute a legacy (bus or class) resume callback for device. | ||
430 | * dev: Device to resume. | ||
431 | * cb: Resume callback to execute. | ||
432 | */ | ||
433 | static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) | ||
434 | { | ||
435 | int error; | ||
436 | ktime_t calltime; | ||
437 | |||
438 | calltime = initcall_debug_start(dev); | ||
439 | |||
440 | error = cb(dev); | ||
441 | suspend_report_result(cb, error); | ||
442 | |||
443 | initcall_debug_report(dev, calltime, error); | ||
444 | |||
445 | return error; | ||
446 | } | ||
447 | |||
448 | /** | ||
411 | * device_resume - Execute "resume" callbacks for given device. | 449 | * device_resume - Execute "resume" callbacks for given device. |
412 | * @dev: Device to handle. | 450 | * @dev: Device to handle. |
413 | * @state: PM transition of the system being carried out. | 451 | * @state: PM transition of the system being carried out. |
@@ -427,7 +465,7 @@ static int device_resume(struct device *dev, pm_message_t state) | |||
427 | error = pm_op(dev, dev->bus->pm, state); | 465 | error = pm_op(dev, dev->bus->pm, state); |
428 | } else if (dev->bus->resume) { | 466 | } else if (dev->bus->resume) { |
429 | pm_dev_dbg(dev, state, "legacy "); | 467 | pm_dev_dbg(dev, state, "legacy "); |
430 | error = dev->bus->resume(dev); | 468 | error = legacy_resume(dev, dev->bus->resume); |
431 | } | 469 | } |
432 | if (error) | 470 | if (error) |
433 | goto End; | 471 | goto End; |
@@ -448,7 +486,7 @@ static int device_resume(struct device *dev, pm_message_t state) | |||
448 | error = pm_op(dev, dev->class->pm, state); | 486 | error = pm_op(dev, dev->class->pm, state); |
449 | } else if (dev->class->resume) { | 487 | } else if (dev->class->resume) { |
450 | pm_dev_dbg(dev, state, "legacy class "); | 488 | pm_dev_dbg(dev, state, "legacy class "); |
451 | error = dev->class->resume(dev); | 489 | error = legacy_resume(dev, dev->class->resume); |
452 | } | 490 | } |
453 | } | 491 | } |
454 | End: | 492 | End: |
@@ -648,6 +686,27 @@ int dpm_suspend_noirq(pm_message_t state) | |||
648 | EXPORT_SYMBOL_GPL(dpm_suspend_noirq); | 686 | EXPORT_SYMBOL_GPL(dpm_suspend_noirq); |
649 | 687 | ||
650 | /** | 688 | /** |
689 | * legacy_suspend - Execute a legacy (bus or class) suspend callback for device. | ||
690 | * dev: Device to suspend. | ||
691 | * cb: Suspend callback to execute. | ||
692 | */ | ||
693 | static int legacy_suspend(struct device *dev, pm_message_t state, | ||
694 | int (*cb)(struct device *dev, pm_message_t state)) | ||
695 | { | ||
696 | int error; | ||
697 | ktime_t calltime; | ||
698 | |||
699 | calltime = initcall_debug_start(dev); | ||
700 | |||
701 | error = cb(dev, state); | ||
702 | suspend_report_result(cb, error); | ||
703 | |||
704 | initcall_debug_report(dev, calltime, error); | ||
705 | |||
706 | return error; | ||
707 | } | ||
708 | |||
709 | /** | ||
651 | * device_suspend - Execute "suspend" callbacks for given device. | 710 | * device_suspend - Execute "suspend" callbacks for given device. |
652 | * @dev: Device to handle. | 711 | * @dev: Device to handle. |
653 | * @state: PM transition of the system being carried out. | 712 | * @state: PM transition of the system being carried out. |
@@ -664,8 +723,7 @@ static int device_suspend(struct device *dev, pm_message_t state) | |||
664 | error = pm_op(dev, dev->class->pm, state); | 723 | error = pm_op(dev, dev->class->pm, state); |
665 | } else if (dev->class->suspend) { | 724 | } else if (dev->class->suspend) { |
666 | pm_dev_dbg(dev, state, "legacy class "); | 725 | pm_dev_dbg(dev, state, "legacy class "); |
667 | error = dev->class->suspend(dev, state); | 726 | error = legacy_suspend(dev, state, dev->class->suspend); |
668 | suspend_report_result(dev->class->suspend, error); | ||
669 | } | 727 | } |
670 | if (error) | 728 | if (error) |
671 | goto End; | 729 | goto End; |
@@ -686,8 +744,7 @@ static int device_suspend(struct device *dev, pm_message_t state) | |||
686 | error = pm_op(dev, dev->bus->pm, state); | 744 | error = pm_op(dev, dev->bus->pm, state); |
687 | } else if (dev->bus->suspend) { | 745 | } else if (dev->bus->suspend) { |
688 | pm_dev_dbg(dev, state, "legacy "); | 746 | pm_dev_dbg(dev, state, "legacy "); |
689 | error = dev->bus->suspend(dev, state); | 747 | error = legacy_suspend(dev, state, dev->bus->suspend); |
690 | suspend_report_result(dev->bus->suspend, error); | ||
691 | } | 748 | } |
692 | } | 749 | } |
693 | End: | 750 | End: |