diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c index f7d213a27983..584a8d06239e 100644 --- a/drivers/devfreq/governor_memlat.c +++ b/drivers/devfreq/governor_memlat.c @@ -1,6 +1,6 @@ // 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); @@ -199,6 +200,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; @@ -220,6 +254,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++) { @@ -322,6 +368,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 < 0) { + 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 < 0) { + 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);