diff options
-rw-r--r-- | drivers/base/power/main.c | 77 | ||||
-rw-r--r-- | include/trace/events/power.h | 37 | ||||
-rw-r--r-- | kernel/power/suspend.c | 4 |
3 files changed, 82 insertions, 36 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5a9b6569dd74..9f098a82cf04 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
29 | #include <linux/async.h> | 29 | #include <linux/async.h> |
30 | #include <linux/suspend.h> | 30 | #include <linux/suspend.h> |
31 | #include <trace/events/power.h> | ||
31 | #include <linux/cpuidle.h> | 32 | #include <linux/cpuidle.h> |
32 | #include "../base.h" | 33 | #include "../base.h" |
33 | #include "power.h" | 34 | #include "power.h" |
@@ -56,6 +57,30 @@ static pm_message_t pm_transition; | |||
56 | 57 | ||
57 | static int async_error; | 58 | static int async_error; |
58 | 59 | ||
60 | static char *pm_verb(int event) | ||
61 | { | ||
62 | switch (event) { | ||
63 | case PM_EVENT_SUSPEND: | ||
64 | return "suspend"; | ||
65 | case PM_EVENT_RESUME: | ||
66 | return "resume"; | ||
67 | case PM_EVENT_FREEZE: | ||
68 | return "freeze"; | ||
69 | case PM_EVENT_QUIESCE: | ||
70 | return "quiesce"; | ||
71 | case PM_EVENT_HIBERNATE: | ||
72 | return "hibernate"; | ||
73 | case PM_EVENT_THAW: | ||
74 | return "thaw"; | ||
75 | case PM_EVENT_RESTORE: | ||
76 | return "restore"; | ||
77 | case PM_EVENT_RECOVER: | ||
78 | return "recover"; | ||
79 | default: | ||
80 | return "(unknown PM event)"; | ||
81 | } | ||
82 | } | ||
83 | |||
59 | /** | 84 | /** |
60 | * device_pm_sleep_init - Initialize system suspend-related device fields. | 85 | * device_pm_sleep_init - Initialize system suspend-related device fields. |
61 | * @dev: Device object being initialized. | 86 | * @dev: Device object being initialized. |
@@ -172,16 +197,21 @@ static ktime_t initcall_debug_start(struct device *dev) | |||
172 | } | 197 | } |
173 | 198 | ||
174 | static void initcall_debug_report(struct device *dev, ktime_t calltime, | 199 | static void initcall_debug_report(struct device *dev, ktime_t calltime, |
175 | int error) | 200 | int error, pm_message_t state, char *info) |
176 | { | 201 | { |
177 | ktime_t delta, rettime; | 202 | ktime_t rettime; |
203 | s64 nsecs; | ||
204 | |||
205 | rettime = ktime_get(); | ||
206 | nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime)); | ||
178 | 207 | ||
179 | if (pm_print_times_enabled) { | 208 | if (pm_print_times_enabled) { |
180 | rettime = ktime_get(); | ||
181 | delta = ktime_sub(rettime, calltime); | ||
182 | pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), | 209 | pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), |
183 | error, (unsigned long long)ktime_to_ns(delta) >> 10); | 210 | error, (unsigned long long)nsecs >> 10); |
184 | } | 211 | } |
212 | |||
213 | trace_device_pm_report_time(dev, info, nsecs, pm_verb(state.event), | ||
214 | error); | ||
185 | } | 215 | } |
186 | 216 | ||
187 | /** | 217 | /** |
@@ -309,30 +339,6 @@ static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t stat | |||
309 | return NULL; | 339 | return NULL; |
310 | } | 340 | } |
311 | 341 | ||
312 | static char *pm_verb(int event) | ||
313 | { | ||
314 | switch (event) { | ||
315 | case PM_EVENT_SUSPEND: | ||
316 | return "suspend"; | ||
317 | case PM_EVENT_RESUME: | ||
318 | return "resume"; | ||
319 | case PM_EVENT_FREEZE: | ||
320 | return "freeze"; | ||
321 | case PM_EVENT_QUIESCE: | ||
322 | return "quiesce"; | ||
323 | case PM_EVENT_HIBERNATE: | ||
324 | return "hibernate"; | ||
325 | case PM_EVENT_THAW: | ||
326 | return "thaw"; | ||
327 | case PM_EVENT_RESTORE: | ||
328 | return "restore"; | ||
329 | case PM_EVENT_RECOVER: | ||
330 | return "recover"; | ||
331 | default: | ||
332 | return "(unknown PM event)"; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info) | 342 | static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info) |
337 | { | 343 | { |
338 | dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event), | 344 | dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event), |
@@ -379,7 +385,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, | |||
379 | error = cb(dev); | 385 | error = cb(dev); |
380 | suspend_report_result(cb, error); | 386 | suspend_report_result(cb, error); |
381 | 387 | ||
382 | initcall_debug_report(dev, calltime, error); | 388 | initcall_debug_report(dev, calltime, error, state, info); |
383 | 389 | ||
384 | return error; | 390 | return error; |
385 | } | 391 | } |
@@ -1027,7 +1033,8 @@ EXPORT_SYMBOL_GPL(dpm_suspend_end); | |||
1027 | * @cb: Suspend callback to execute. | 1033 | * @cb: Suspend callback to execute. |
1028 | */ | 1034 | */ |
1029 | static int legacy_suspend(struct device *dev, pm_message_t state, | 1035 | static int legacy_suspend(struct device *dev, pm_message_t state, |
1030 | int (*cb)(struct device *dev, pm_message_t state)) | 1036 | int (*cb)(struct device *dev, pm_message_t state), |
1037 | char *info) | ||
1031 | { | 1038 | { |
1032 | int error; | 1039 | int error; |
1033 | ktime_t calltime; | 1040 | ktime_t calltime; |
@@ -1037,7 +1044,7 @@ static int legacy_suspend(struct device *dev, pm_message_t state, | |||
1037 | error = cb(dev, state); | 1044 | error = cb(dev, state); |
1038 | suspend_report_result(cb, error); | 1045 | suspend_report_result(cb, error); |
1039 | 1046 | ||
1040 | initcall_debug_report(dev, calltime, error); | 1047 | initcall_debug_report(dev, calltime, error, state, info); |
1041 | 1048 | ||
1042 | return error; | 1049 | return error; |
1043 | } | 1050 | } |
@@ -1097,7 +1104,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1097 | goto Run; | 1104 | goto Run; |
1098 | } else if (dev->class->suspend) { | 1105 | } else if (dev->class->suspend) { |
1099 | pm_dev_dbg(dev, state, "legacy class "); | 1106 | pm_dev_dbg(dev, state, "legacy class "); |
1100 | error = legacy_suspend(dev, state, dev->class->suspend); | 1107 | error = legacy_suspend(dev, state, dev->class->suspend, |
1108 | "legacy class "); | ||
1101 | goto End; | 1109 | goto End; |
1102 | } | 1110 | } |
1103 | } | 1111 | } |
@@ -1108,7 +1116,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1108 | callback = pm_op(dev->bus->pm, state); | 1116 | callback = pm_op(dev->bus->pm, state); |
1109 | } else if (dev->bus->suspend) { | 1117 | } else if (dev->bus->suspend) { |
1110 | pm_dev_dbg(dev, state, "legacy bus "); | 1118 | pm_dev_dbg(dev, state, "legacy bus "); |
1111 | error = legacy_suspend(dev, state, dev->bus->suspend); | 1119 | error = legacy_suspend(dev, state, dev->bus->suspend, |
1120 | "legacy bus "); | ||
1112 | goto End; | 1121 | goto End; |
1113 | } | 1122 | } |
1114 | } | 1123 | } |
diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 8e42410bd159..cda100d6762d 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h | |||
@@ -66,6 +66,43 @@ TRACE_EVENT(machine_suspend, | |||
66 | TP_printk("state=%lu", (unsigned long)__entry->state) | 66 | TP_printk("state=%lu", (unsigned long)__entry->state) |
67 | ); | 67 | ); |
68 | 68 | ||
69 | TRACE_EVENT(device_pm_report_time, | ||
70 | |||
71 | TP_PROTO(struct device *dev, const char *pm_ops, s64 ops_time, | ||
72 | char *pm_event_str, int error), | ||
73 | |||
74 | TP_ARGS(dev, pm_ops, ops_time, pm_event_str, error), | ||
75 | |||
76 | TP_STRUCT__entry( | ||
77 | __string(device, dev_name(dev)) | ||
78 | __string(driver, dev_driver_string(dev)) | ||
79 | __string(parent, dev->parent ? dev_name(dev->parent) : "none") | ||
80 | __string(pm_ops, pm_ops ? pm_ops : "none ") | ||
81 | __string(pm_event_str, pm_event_str) | ||
82 | __field(s64, ops_time) | ||
83 | __field(int, error) | ||
84 | ), | ||
85 | |||
86 | TP_fast_assign( | ||
87 | const char *tmp = dev->parent ? dev_name(dev->parent) : "none"; | ||
88 | const char *tmp_i = pm_ops ? pm_ops : "none "; | ||
89 | |||
90 | __assign_str(device, dev_name(dev)); | ||
91 | __assign_str(driver, dev_driver_string(dev)); | ||
92 | __assign_str(parent, tmp); | ||
93 | __assign_str(pm_ops, tmp_i); | ||
94 | __assign_str(pm_event_str, pm_event_str); | ||
95 | __entry->ops_time = ops_time; | ||
96 | __entry->error = error; | ||
97 | ), | ||
98 | |||
99 | /* ops_str has an extra space at the end */ | ||
100 | TP_printk("%s %s parent=%s state=%s ops=%snsecs=%lld err=%d", | ||
101 | __get_str(driver), __get_str(device), __get_str(parent), | ||
102 | __get_str(pm_event_str), __get_str(pm_ops), | ||
103 | __entry->ops_time, __entry->error) | ||
104 | ); | ||
105 | |||
69 | DECLARE_EVENT_CLASS(wakeup_source, | 106 | DECLARE_EVENT_CLASS(wakeup_source, |
70 | 107 | ||
71 | TP_PROTO(const char *name, unsigned int state), | 108 | TP_PROTO(const char *name, unsigned int state), |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index ece04223bb1e..62ee437b5c7e 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -210,6 +210,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
210 | goto Platform_wake; | 210 | goto Platform_wake; |
211 | } | 211 | } |
212 | 212 | ||
213 | ftrace_stop(); | ||
213 | error = disable_nonboot_cpus(); | 214 | error = disable_nonboot_cpus(); |
214 | if (error || suspend_test(TEST_CPUS)) | 215 | if (error || suspend_test(TEST_CPUS)) |
215 | goto Enable_cpus; | 216 | goto Enable_cpus; |
@@ -232,6 +233,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
232 | 233 | ||
233 | Enable_cpus: | 234 | Enable_cpus: |
234 | enable_nonboot_cpus(); | 235 | enable_nonboot_cpus(); |
236 | ftrace_start(); | ||
235 | 237 | ||
236 | Platform_wake: | 238 | Platform_wake: |
237 | if (need_suspend_ops(state) && suspend_ops->wake) | 239 | if (need_suspend_ops(state) && suspend_ops->wake) |
@@ -265,7 +267,6 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
265 | goto Close; | 267 | goto Close; |
266 | } | 268 | } |
267 | suspend_console(); | 269 | suspend_console(); |
268 | ftrace_stop(); | ||
269 | suspend_test_start(); | 270 | suspend_test_start(); |
270 | error = dpm_suspend_start(PMSG_SUSPEND); | 271 | error = dpm_suspend_start(PMSG_SUSPEND); |
271 | if (error) { | 272 | if (error) { |
@@ -285,7 +286,6 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
285 | suspend_test_start(); | 286 | suspend_test_start(); |
286 | dpm_resume_end(PMSG_RESUME); | 287 | dpm_resume_end(PMSG_RESUME); |
287 | suspend_test_finish("resume devices"); | 288 | suspend_test_finish("resume devices"); |
288 | ftrace_start(); | ||
289 | resume_console(); | 289 | resume_console(); |
290 | Close: | 290 | Close: |
291 | if (need_suspend_ops(state) && suspend_ops->end) | 291 | if (need_suspend_ops(state) && suspend_ops->end) |