|
@@ -12,6 +12,8 @@
|
|
|
#include <linux/string.h>
|
|
|
#include <linux/resume-trace.h>
|
|
|
#include <linux/workqueue.h>
|
|
|
+#include <linux/debugfs.h>
|
|
|
+#include <linux/seq_file.h>
|
|
|
|
|
|
#include "power.h"
|
|
|
|
|
@@ -133,6 +135,101 @@ power_attr(pm_test);
|
|
|
|
|
|
#endif /* CONFIG_PM_SLEEP */
|
|
|
|
|
|
+#ifdef CONFIG_DEBUG_FS
|
|
|
+static char *suspend_step_name(enum suspend_stat_step step)
|
|
|
+{
|
|
|
+ switch (step) {
|
|
|
+ case SUSPEND_FREEZE:
|
|
|
+ return "freeze";
|
|
|
+ case SUSPEND_PREPARE:
|
|
|
+ return "prepare";
|
|
|
+ case SUSPEND_SUSPEND:
|
|
|
+ return "suspend";
|
|
|
+ case SUSPEND_SUSPEND_NOIRQ:
|
|
|
+ return "suspend_noirq";
|
|
|
+ case SUSPEND_RESUME_NOIRQ:
|
|
|
+ return "resume_noirq";
|
|
|
+ case SUSPEND_RESUME:
|
|
|
+ return "resume";
|
|
|
+ default:
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int suspend_stats_show(struct seq_file *s, void *unused)
|
|
|
+{
|
|
|
+ int i, index, last_dev, last_errno, last_step;
|
|
|
+
|
|
|
+ last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
|
|
|
+ last_dev %= REC_FAILED_NUM;
|
|
|
+ last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
|
|
|
+ last_errno %= REC_FAILED_NUM;
|
|
|
+ last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
|
|
|
+ last_step %= REC_FAILED_NUM;
|
|
|
+ seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
|
|
|
+ "%s: %d\n%s: %d\n%s: %d\n%s: %d\n",
|
|
|
+ "success", suspend_stats.success,
|
|
|
+ "fail", suspend_stats.fail,
|
|
|
+ "failed_freeze", suspend_stats.failed_freeze,
|
|
|
+ "failed_prepare", suspend_stats.failed_prepare,
|
|
|
+ "failed_suspend", suspend_stats.failed_suspend,
|
|
|
+ "failed_suspend_noirq",
|
|
|
+ suspend_stats.failed_suspend_noirq,
|
|
|
+ "failed_resume", suspend_stats.failed_resume,
|
|
|
+ "failed_resume_noirq",
|
|
|
+ suspend_stats.failed_resume_noirq);
|
|
|
+ seq_printf(s, "failures:\n last_failed_dev:\t%-s\n",
|
|
|
+ suspend_stats.failed_devs[last_dev]);
|
|
|
+ for (i = 1; i < REC_FAILED_NUM; i++) {
|
|
|
+ index = last_dev + REC_FAILED_NUM - i;
|
|
|
+ index %= REC_FAILED_NUM;
|
|
|
+ seq_printf(s, "\t\t\t%-s\n",
|
|
|
+ suspend_stats.failed_devs[index]);
|
|
|
+ }
|
|
|
+ seq_printf(s, " last_failed_errno:\t%-d\n",
|
|
|
+ suspend_stats.errno[last_errno]);
|
|
|
+ for (i = 1; i < REC_FAILED_NUM; i++) {
|
|
|
+ index = last_errno + REC_FAILED_NUM - i;
|
|
|
+ index %= REC_FAILED_NUM;
|
|
|
+ seq_printf(s, "\t\t\t%-d\n",
|
|
|
+ suspend_stats.errno[index]);
|
|
|
+ }
|
|
|
+ seq_printf(s, " last_failed_step:\t%-s\n",
|
|
|
+ suspend_step_name(
|
|
|
+ suspend_stats.failed_steps[last_step]));
|
|
|
+ for (i = 1; i < REC_FAILED_NUM; i++) {
|
|
|
+ index = last_step + REC_FAILED_NUM - i;
|
|
|
+ index %= REC_FAILED_NUM;
|
|
|
+ seq_printf(s, "\t\t\t%-s\n",
|
|
|
+ suspend_step_name(
|
|
|
+ suspend_stats.failed_steps[index]));
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int suspend_stats_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ return single_open(file, suspend_stats_show, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations suspend_stats_operations = {
|
|
|
+ .open = suspend_stats_open,
|
|
|
+ .read = seq_read,
|
|
|
+ .llseek = seq_lseek,
|
|
|
+ .release = single_release,
|
|
|
+};
|
|
|
+
|
|
|
+static int __init pm_debugfs_init(void)
|
|
|
+{
|
|
|
+ debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
|
|
|
+ NULL, NULL, &suspend_stats_operations);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+late_initcall(pm_debugfs_init);
|
|
|
+#endif /* CONFIG_DEBUG_FS */
|
|
|
+
|
|
|
struct kobject *power_kobj;
|
|
|
|
|
|
/**
|
|
@@ -194,6 +291,11 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
}
|
|
|
if (state < PM_SUSPEND_MAX && *s)
|
|
|
error = enter_state(state);
|
|
|
+ if (error) {
|
|
|
+ suspend_stats.fail++;
|
|
|
+ dpm_save_failed_errno(error);
|
|
|
+ } else
|
|
|
+ suspend_stats.success++;
|
|
|
#endif
|
|
|
|
|
|
Exit:
|