lpm: Add sysfs node to display total sleep time
Add sysfs node to query the total sleep time of a cpu since debugfs node is not exposed to the userspace service. Command: cat /sys/module/lpm_stats/cpu0/total_sleep_time_secs cat /sys/module/lpm_stats/cpu1/total_sleep_time_secs cat /sys/module/lpm_stats/cpu2/total_sleep_time_secs cat /sys/module/lpm_stats/cpu3/total_sleep_time_secs CRs-fixed: 935207 Change-Id: I45be0a8be29932816aa42e097657a2a60933b986 Signed-off-by: Archana Sathyakumar <asathyak@codeaurora.org> Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
This commit is contained in:
parent
277fb0f7d0
commit
40fe32a315
1 changed files with 114 additions and 1 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -26,9 +26,15 @@
|
|||
#include <soc/qcom/pm.h>
|
||||
|
||||
#define MAX_STR_LEN 256
|
||||
#define MAX_TIME_LEN 20
|
||||
const char *lpm_stats_reset = "reset";
|
||||
const char *lpm_stats_suspend = "suspend";
|
||||
|
||||
struct lpm_sleep_time {
|
||||
struct kobj_attribute ts_attr;
|
||||
unsigned int cpu;
|
||||
};
|
||||
|
||||
struct level_stats {
|
||||
const char *name;
|
||||
struct lpm_stats *owner;
|
||||
|
@ -64,6 +70,18 @@ static struct level_stats suspend_time_stats;
|
|||
|
||||
static DEFINE_PER_CPU_SHARED_ALIGNED(struct lpm_stats, cpu_stats);
|
||||
|
||||
static uint64_t get_total_sleep_time(unsigned int cpu_id)
|
||||
{
|
||||
struct lpm_stats *stats = &per_cpu(cpu_stats, cpu_id);
|
||||
int i;
|
||||
uint64_t ret = 0;
|
||||
|
||||
for (i = 0; i < stats->num_levels; i++)
|
||||
ret += stats->time_stats[i].total_time;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void update_level_stats(struct level_stats *stats, uint64_t t,
|
||||
bool success)
|
||||
{
|
||||
|
@ -499,6 +517,94 @@ static int config_level(const char *name, const char **levels,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t total_sleep_time_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct lpm_sleep_time *cpu_sleep_time = container_of(attr,
|
||||
struct lpm_sleep_time, ts_attr);
|
||||
unsigned int cpu = cpu_sleep_time->cpu;
|
||||
uint64_t total_time = get_total_sleep_time(cpu);
|
||||
|
||||
return snprintf(buf, MAX_TIME_LEN, "%llu.%09u\n", total_time,
|
||||
do_div(total_time, NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
static struct kobject *local_module_kobject(void)
|
||||
{
|
||||
struct kobject *kobj;
|
||||
|
||||
kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
|
||||
|
||||
if (!kobj) {
|
||||
int err;
|
||||
struct module_kobject *mk;
|
||||
|
||||
mk = kzalloc(sizeof(*mk), GFP_KERNEL);
|
||||
if (!mk)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mk->mod = THIS_MODULE;
|
||||
mk->kobj.kset = module_kset;
|
||||
|
||||
err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL,
|
||||
"%s", KBUILD_MODNAME);
|
||||
|
||||
if (err) {
|
||||
kobject_put(&mk->kobj);
|
||||
kfree(mk);
|
||||
pr_err("%s: cannot create kobject for %s\n",
|
||||
__func__, KBUILD_MODNAME);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
kobject_get(&mk->kobj);
|
||||
kobj = &mk->kobj;
|
||||
}
|
||||
|
||||
return kobj;
|
||||
}
|
||||
|
||||
static int create_sysfs_node(unsigned int cpu, struct lpm_stats *stats)
|
||||
{
|
||||
struct kobject *cpu_kobj = NULL;
|
||||
struct lpm_sleep_time *ts = NULL;
|
||||
struct kobject *stats_kobj;
|
||||
char cpu_name[] = "cpuXX";
|
||||
int ret = -ENOMEM;
|
||||
|
||||
stats_kobj = local_module_kobject();
|
||||
|
||||
if (IS_ERR_OR_NULL(stats_kobj))
|
||||
return PTR_ERR(stats_kobj);
|
||||
|
||||
snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
|
||||
cpu_kobj = kobject_create_and_add(cpu_name, stats_kobj);
|
||||
if (!cpu_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
|
||||
if (!ts)
|
||||
goto failed;
|
||||
|
||||
sysfs_attr_init(&ts->ts_attr.attr);
|
||||
ts->ts_attr.attr.name = "total_sleep_time_secs";
|
||||
ts->ts_attr.attr.mode = 0444;
|
||||
ts->ts_attr.show = total_sleep_time_show;
|
||||
ts->ts_attr.store = NULL;
|
||||
ts->cpu = cpu;
|
||||
|
||||
ret = sysfs_create_file(cpu_kobj, &ts->ts_attr.attr);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(ts);
|
||||
kobject_put(cpu_kobj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct lpm_stats *config_cpu_level(const char *name,
|
||||
const char **levels, int num_levels, struct lpm_stats *parent,
|
||||
struct cpumask *mask)
|
||||
|
@ -527,6 +633,13 @@ static struct lpm_stats *config_cpu_level(const char *name,
|
|||
__func__, cpu_name);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = create_sysfs_node(cpu, stats);
|
||||
|
||||
if (ret) {
|
||||
pr_err("Could not create the sysfs node\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
|
|
Loading…
Add table
Reference in a new issue