diff options
Diffstat (limited to 'kernel/power/main.c')
-rw-r--r-- | kernel/power/main.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c index 6c601f871964..a52e88425a31 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/string.h> | 12 | #include <linux/string.h> |
13 | #include <linux/resume-trace.h> | 13 | #include <linux/resume-trace.h> |
14 | #include <linux/workqueue.h> | 14 | #include <linux/workqueue.h> |
15 | #include <linux/debugfs.h> | ||
16 | #include <linux/seq_file.h> | ||
15 | 17 | ||
16 | #include "power.h" | 18 | #include "power.h" |
17 | 19 | ||
@@ -131,6 +133,101 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
131 | power_attr(pm_test); | 133 | power_attr(pm_test); |
132 | #endif /* CONFIG_PM_DEBUG */ | 134 | #endif /* CONFIG_PM_DEBUG */ |
133 | 135 | ||
136 | #ifdef CONFIG_DEBUG_FS | ||
137 | static char *suspend_step_name(enum suspend_stat_step step) | ||
138 | { | ||
139 | switch (step) { | ||
140 | case SUSPEND_FREEZE: | ||
141 | return "freeze"; | ||
142 | case SUSPEND_PREPARE: | ||
143 | return "prepare"; | ||
144 | case SUSPEND_SUSPEND: | ||
145 | return "suspend"; | ||
146 | case SUSPEND_SUSPEND_NOIRQ: | ||
147 | return "suspend_noirq"; | ||
148 | case SUSPEND_RESUME_NOIRQ: | ||
149 | return "resume_noirq"; | ||
150 | case SUSPEND_RESUME: | ||
151 | return "resume"; | ||
152 | default: | ||
153 | return ""; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static int suspend_stats_show(struct seq_file *s, void *unused) | ||
158 | { | ||
159 | int i, index, last_dev, last_errno, last_step; | ||
160 | |||
161 | last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; | ||
162 | last_dev %= REC_FAILED_NUM; | ||
163 | last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; | ||
164 | last_errno %= REC_FAILED_NUM; | ||
165 | last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; | ||
166 | last_step %= REC_FAILED_NUM; | ||
167 | seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n" | ||
168 | "%s: %d\n%s: %d\n%s: %d\n%s: %d\n", | ||
169 | "success", suspend_stats.success, | ||
170 | "fail", suspend_stats.fail, | ||
171 | "failed_freeze", suspend_stats.failed_freeze, | ||
172 | "failed_prepare", suspend_stats.failed_prepare, | ||
173 | "failed_suspend", suspend_stats.failed_suspend, | ||
174 | "failed_suspend_noirq", | ||
175 | suspend_stats.failed_suspend_noirq, | ||
176 | "failed_resume", suspend_stats.failed_resume, | ||
177 | "failed_resume_noirq", | ||
178 | suspend_stats.failed_resume_noirq); | ||
179 | seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", | ||
180 | suspend_stats.failed_devs[last_dev]); | ||
181 | for (i = 1; i < REC_FAILED_NUM; i++) { | ||
182 | index = last_dev + REC_FAILED_NUM - i; | ||
183 | index %= REC_FAILED_NUM; | ||
184 | seq_printf(s, "\t\t\t%-s\n", | ||
185 | suspend_stats.failed_devs[index]); | ||
186 | } | ||
187 | seq_printf(s, " last_failed_errno:\t%-d\n", | ||
188 | suspend_stats.errno[last_errno]); | ||
189 | for (i = 1; i < REC_FAILED_NUM; i++) { | ||
190 | index = last_errno + REC_FAILED_NUM - i; | ||
191 | index %= REC_FAILED_NUM; | ||
192 | seq_printf(s, "\t\t\t%-d\n", | ||
193 | suspend_stats.errno[index]); | ||
194 | } | ||
195 | seq_printf(s, " last_failed_step:\t%-s\n", | ||
196 | suspend_step_name( | ||
197 | suspend_stats.failed_steps[last_step])); | ||
198 | for (i = 1; i < REC_FAILED_NUM; i++) { | ||
199 | index = last_step + REC_FAILED_NUM - i; | ||
200 | index %= REC_FAILED_NUM; | ||
201 | seq_printf(s, "\t\t\t%-s\n", | ||
202 | suspend_step_name( | ||
203 | suspend_stats.failed_steps[index])); | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int suspend_stats_open(struct inode *inode, struct file *file) | ||
210 | { | ||
211 | return single_open(file, suspend_stats_show, NULL); | ||
212 | } | ||
213 | |||
214 | static const struct file_operations suspend_stats_operations = { | ||
215 | .open = suspend_stats_open, | ||
216 | .read = seq_read, | ||
217 | .llseek = seq_lseek, | ||
218 | .release = single_release, | ||
219 | }; | ||
220 | |||
221 | static int __init pm_debugfs_init(void) | ||
222 | { | ||
223 | debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, | ||
224 | NULL, NULL, &suspend_stats_operations); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | late_initcall(pm_debugfs_init); | ||
229 | #endif /* CONFIG_DEBUG_FS */ | ||
230 | |||
134 | #endif /* CONFIG_PM_SLEEP */ | 231 | #endif /* CONFIG_PM_SLEEP */ |
135 | 232 | ||
136 | struct kobject *power_kobj; | 233 | struct kobject *power_kobj; |
@@ -194,6 +291,11 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
194 | } | 291 | } |
195 | if (state < PM_SUSPEND_MAX && *s) | 292 | if (state < PM_SUSPEND_MAX && *s) |
196 | error = enter_state(state); | 293 | error = enter_state(state); |
294 | if (error) { | ||
295 | suspend_stats.fail++; | ||
296 | dpm_save_failed_errno(error); | ||
297 | } else | ||
298 | suspend_stats.success++; | ||
197 | #endif | 299 | #endif |
198 | 300 | ||
199 | Exit: | 301 | Exit: |