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