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: Jonathan Avila <avilaj@codeaurora.org>
This commit is contained in:
Jonathan Avila 2018-05-02 08:52:08 -07:00
parent 8c5ca64d7e
commit 5a6ca65348

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2018, 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
@ -43,6 +43,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);
@ -212,6 +213,39 @@ err_start:
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;
@ -233,6 +267,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++) {
@ -331,6 +377,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);