Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f939aeb authored by Mahesh Sivasubramanian's avatar Mahesh Sivasubramanian
Browse files

msm: lpm-levels: Add support for reporting statistics.



The pm-stats drivers is rearchitected to support multiple clusters and
report the statistics of individual resources. Add support to invoke the
new APIs to appropriately report the pm-stats for clusters and cpus

Change-Id: Ibcae9e79a2df39a74247968fce89c72a996d9ad3
Signed-off-by: default avatarMahesh Sivasubramanian <msivasub@codeaurora.org>
parent 1ade5c36
Loading
Loading
Loading
Loading
+62 −12
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <soc/qcom/pm.h>
#include <soc/qcom/rpm-notifier.h>
#include <soc/qcom/event_timer.h>
#include <soc/qcom/lpm-stats.h>
#include <asm/cputype.h>
#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
@@ -69,7 +70,6 @@ struct lpm_debug {
static struct lpm_cluster *lpm_root_node;
static DEFINE_PER_CPU(struct lpm_cluster*, cpu_cluster);
static bool suspend_in_progress;
static int64_t suspend_time;
static struct hrtimer lpm_hrtimer;
static struct lpm_debug *lpm_debug;
static phys_addr_t lpm_debug_phys;
@@ -443,6 +443,7 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
		msm_mpm_enter_sleep((uint32_t)us, from_idle, &nextcpu);
	}
	cluster->last_level = idx;
	lpm_stats_cluster_enter(cluster->stats, idx);
	spin_unlock(&cluster->sync_lock);
	return 0;

@@ -534,6 +535,8 @@ static void cluster_unprepare(struct lpm_cluster *cluster,
	if (!first_cpu || cluster->last_level == cluster->default_level)
		goto unlock_return;

	lpm_stats_cluster_exit(cluster->stats, cluster->last_level, true);

	level = &cluster->levels[cluster->last_level];
	if (level->notify_rpm) {
		msm_rpm_exit_sleep();
@@ -544,6 +547,7 @@ static void cluster_unprepare(struct lpm_cluster *cluster,
			cluster->num_childs_in_sync.bits[0],
			cluster->child_cpus.bits[0], from_idle);

	last_level = cluster->last_level;
	cluster->last_level = cluster->default_level;

	for (i = 0; i < cluster->ndevices; i++) {
@@ -596,6 +600,7 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev,
{
	struct lpm_cluster *cluster = per_cpu(cpu_cluster, dev->cpu);
	int64_t time = ktime_to_ns(ktime_get());
	bool success = true;
	int idx = cpu_power_select(dev, cluster->cpu, &index);
	const struct cpumask *cpumask = get_cpu_mask(dev->cpu);

@@ -606,7 +611,9 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev,
	cpu_prepare(cluster, idx, true);

	cluster_prepare(cluster, cpumask, idx, true);
	msm_cpu_pm_enter_sleep(cluster->cpu->levels[idx].mode, true);
	lpm_stats_cpu_enter(idx);
	success = msm_cpu_pm_enter_sleep(cluster->cpu->levels[idx].mode, true);
	lpm_stats_cpu_exit(idx, success);
	cluster_unprepare(cluster, cpumask, idx, true);
	cpu_unprepare(cluster, idx, true);

@@ -708,27 +715,69 @@ static int cluster_cpuidle_register(struct lpm_cluster *cl)
	return 0;
}

static int lpm_suspend_prepare(void)
static void register_cpu_lpm_stats(struct lpm_cpu *cpu,
		struct lpm_cluster *parent)
{
	const char **level_name;
	int i;

	level_name = kzalloc(cpu->nlevels * sizeof(*level_name), GFP_KERNEL);

	if (!level_name)
		return;

	for (i = 0; i < cpu->nlevels; i++)
		level_name[i] = cpu->levels[i].name;

	lpm_stats_config_level("cpu", level_name, cpu->nlevels,
			parent->stats, &parent->child_cpus);
}

static void register_cluster_lpm_stats(struct lpm_cluster *cl,
		struct lpm_cluster *parent)
{
	struct timespec ts;
	const char **level_name;
	int i;
	struct lpm_cluster *child;

	if (!cl)
		return;

	getnstimeofday(&ts);
	suspend_time = timespec_to_ns(&ts);
	level_name = kzalloc(cl->nlevels * sizeof(*level_name), GFP_KERNEL);

	if (!level_name)
		return;

	for (i = 0; i < cl->nlevels; i++)
		level_name[i] = cl->levels[i].level_name;

	cl->stats = lpm_stats_config_level(cl->cluster_name, level_name,
			cl->nlevels, parent ? parent->stats : NULL, NULL);

	kfree(level_name);

	if (cl->cpu) {
		register_cpu_lpm_stats(cl->cpu, cl);
		return;
	}

	list_for_each_entry(child, &cl->child, list)
		register_cluster_lpm_stats(child, cl);
}

static int lpm_suspend_prepare(void)
{
	suspend_in_progress = true;
	msm_mpm_suspend_prepare();
	lpm_stats_suspend_enter();

	return 0;
}

static void lpm_suspend_wake(void)
{
	struct timespec ts;

	getnstimeofday(&ts);
	suspend_time = timespec_to_ns(&ts) - suspend_time;
	msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
	msm_mpm_suspend_wake();
	suspend_in_progress = false;
	lpm_stats_suspend_exit();
}

static int lpm_suspend_enter(suspend_state_t state)
@@ -816,6 +865,7 @@ static int lpm_probe(struct platform_device *pdev)
	size = num_dbg_elements * sizeof(struct lpm_debug);
	lpm_debug = dma_alloc_coherent(&pdev->dev, size,
			&lpm_debug_phys, GFP_KERNEL);
	register_cluster_lpm_stats(lpm_root_node, NULL);

	ret = cluster_cpuidle_register(lpm_root_node);
	if (ret) {
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ struct lpm_cluster {
	struct cpumask child_cpus;
	struct cpumask num_childs_in_sync;
	struct lpm_cluster *parent;
	struct lpm_stats *stats;
	bool no_saw_devices;
};

+13 −40
Original line number Diff line number Diff line
@@ -120,13 +120,13 @@ static bool msm_pm_is_L1_writeback(void)
#endif
}

static enum msm_pm_time_stats_id msm_pm_swfi(bool from_idle)
static bool msm_pm_swfi(bool from_idle)
{
	msm_arch_idle();
	return MSM_PM_STAT_IDLE_WFI;
	return true;
}

static enum msm_pm_time_stats_id msm_pm_retention(bool from_idle)
static bool msm_pm_retention(bool from_idle)
{
	int ret = 0;
	unsigned int cpu = smp_processor_id();
@@ -157,7 +157,7 @@ static enum msm_pm_time_stats_id msm_pm_retention(bool from_idle)
	cpumask_clear_cpu(cpu, &retention_cpus);
bailout:
	spin_unlock(&retention_lock);
	return MSM_PM_STAT_RETENTION;
	return true;
}

static inline void msm_pc_inc_debug_count(uint32_t cpu,
@@ -269,7 +269,7 @@ static bool __ref msm_pm_spm_power_collapse(
	return collapsed;
}

static enum msm_pm_time_stats_id msm_pm_power_collapse_standalone(
static bool msm_pm_power_collapse_standalone(
		bool from_idle)
{
	unsigned int cpu = smp_processor_id();
@@ -285,8 +285,7 @@ static enum msm_pm_time_stats_id msm_pm_power_collapse_standalone(

	avs_set_avsdscr(avsdscr);
	avs_set_avscsr(avscsr);
	return collapsed ? MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE :
		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
	return collapsed;
}

static int ramp_down_last_cpu(int cpu)
@@ -329,7 +328,7 @@ static int ramp_up_first_cpu(int cpu, int saved_rate)
	return rc;
}

static enum msm_pm_time_stats_id msm_pm_power_collapse(bool from_idle)
static bool msm_pm_power_collapse(bool from_idle)
{
	unsigned int cpu = smp_processor_id();
	unsigned long saved_acpuclk_rate = 0;
@@ -372,8 +371,7 @@ static enum msm_pm_time_stats_id msm_pm_power_collapse(bool from_idle)

	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
		pr_info("CPU%u: %s: return\n", cpu, __func__);
	return collapsed ? MSM_PM_STAT_IDLE_POWER_COLLAPSE :
		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
	return collapsed;
}
/******************************************************************************
 * External Idle/Suspend Functions
@@ -429,7 +427,7 @@ static inline void msm_pm_ftrace_lpm_exit(unsigned int cpu,
	}
}

static enum msm_pm_time_stats_id (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
static bool (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = msm_pm_swfi,
	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
		msm_pm_power_collapse_standalone,
@@ -449,10 +447,9 @@ static enum msm_pm_time_stats_id (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
 * low power is to be executed.
 *
 */
void msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
{
	int64_t time = 0;
	enum msm_pm_time_stats_id exit_stat = 0;
	bool exit_stat = false;
	unsigned int cpu = smp_processor_id();

	if ((!from_idle  && cpu_online(cpu))
@@ -460,17 +457,10 @@ void msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
		pr_info("CPU%u:%s mode:%d during %s\n", cpu, __func__,
				mode, from_idle ? "idle" : "suspend");

	if (from_idle)
		time = sched_clock();

	if (execute[mode])
		exit_stat = execute[mode](from_idle);

	if (from_idle) {
		time = sched_clock() - time;
		if (exit_stat >= 0)
			msm_pm_add_stat(exit_stat, time);
	}
	return exit_stat;
}

/**
@@ -675,23 +665,6 @@ static struct platform_driver msm_cpu_pm_snoc_client_driver = {
	},
};

static int msm_pm_init(void)
{
	enum msm_pm_time_stats_id enable_stats[] = {
		MSM_PM_STAT_IDLE_WFI,
		MSM_PM_STAT_RETENTION,
		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
		MSM_PM_STAT_SUSPEND,
	};
	msm_pm_mode_sysfs_add(KBUILD_MODNAME);
	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));

	return 0;
}

struct msm_pc_debug_counters_buffer {
	void __iomem *reg;
	u32 len;
@@ -868,7 +841,7 @@ static int msm_cpu_pm_probe(struct platform_device *pdev)
		}
	}

	msm_pm_init();
	msm_pm_mode_sysfs_add(KBUILD_MODNAME);
	if (pdev->dev.of_node)
		of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);

+4 −1
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ void arch_idle(void)
	cpu_do_idle();
}

void msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle) {}
bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
{
	return false;
}

void msm_pm_enable_retention(bool enable) {}
+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ struct msm_pm_cpr_ops {
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
void msm_pm_enable_retention(bool enable);
bool msm_pm_retention_enabled(void);
void msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);

#ifdef CONFIG_MSM_PM
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);