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

Commit cca4b8e8 authored by Rama Aparna Mallavarapu's avatar Rama Aparna Mallavarapu
Browse files

devfreq: memlat: Add suspend/resume for mem_latency



Add suspend/resume support for the mem_latency governor. Uses hwmon driver-
defined suspend/resume calls in addition to monitor start/stop calls within
the devfreq framework.

Change-Id: I900b322a05cd0312f082d70640e21851879cb18c
Signed-off-by: default avatarJonathan Avila <avilaj@codeaurora.org>
Signed-off-by: default avatarRama Aparna Mallavarapu <aparnam@codeaurora.org>
parent 0114bf7e
Loading
Loading
Loading
Loading
+71 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2017, 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2018, 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) "mem_lat: " fmt
@@ -35,6 +35,7 @@ struct memlat_node {
	struct memlat_hwmon *hw;
	struct devfreq_governor *gov;
	struct attribute_group *attr_grp;
	unsigned long resume_freq;
};

static LIST_HEAD(memlat_list);
@@ -204,6 +205,39 @@ static int gov_start(struct devfreq *df)
	return ret;
}

static int gov_suspend(struct devfreq *df)
{
	struct memlat_node *node = df->data;
	unsigned long prev_freq = df->previous_freq;

	node->mon_started = false;
	devfreq_monitor_suspend(df);

	mutex_lock(&df->lock);
	update_devfreq(df);
	mutex_unlock(&df->lock);

	node->resume_freq = max(prev_freq, 1UL);

	return 0;
}

static int gov_resume(struct devfreq *df)
{
	struct memlat_node *node = df->data;

	mutex_lock(&df->lock);
	update_devfreq(df);
	mutex_unlock(&df->lock);

	node->resume_freq = 0;

	devfreq_monitor_resume(df);
	node->mon_started = true;

	return 0;
}

static void gov_stop(struct devfreq *df)
{
	struct memlat_node *node = df->data;
@@ -225,6 +259,18 @@ static int devfreq_memlat_get_freq(struct devfreq *df,
	unsigned long max_freq = 0;
	unsigned int ratio;

	/*
	 * node->resume_freq is set to 0 at the end of resume (after the update)
	 * and is set to df->prev_freq at the end of suspend (after the update).
	 * This function will be called as part of the update_devfreq call in
	 * both scenarios. As a result, this block will cause a 0 vote during
	 * suspend and a vote for df->prev_freq during resume.
	 */
	if (!node->mon_started) {
		*freq = node->resume_freq;
		return 0;
	}

	hw->get_cnt(hw);

	for (i = 0; i < hw->num_cores; i++) {
@@ -323,6 +369,30 @@ static int devfreq_memlat_ev_handler(struct devfreq *df,
			"Disabled Memory Latency governor\n");
		break;

	case DEVFREQ_GOV_SUSPEND:
		ret = gov_suspend(df);
		if (ret) {
			dev_err(df->dev.parent,
				"Unable to suspend memlat governor (%d)\n",
				ret);
			return ret;
		}

		dev_dbg(df->dev.parent, "Suspended memlat governor\n");
		break;

	case DEVFREQ_GOV_RESUME:
		ret = gov_resume(df);
		if (ret) {
			dev_err(df->dev.parent,
				"Unable to resume memlat governor (%d)\n",
				ret);
			return ret;
		}

		dev_dbg(df->dev.parent, "Resumed memlat governor\n");
		break;

	case DEVFREQ_GOV_INTERVAL:
		sample_ms = *(unsigned int *)data;
		sample_ms = max(MIN_MS, sample_ms);