[PATCH RFC v2 2/2] cpufreq: mediatek: Support vproc shared by multiple component

From: Hsin-Yi Wang
Date: Wed Jul 17 2019 - 02:13:11 EST


mt8183-cci shares vproc with small cluster. If the regulator is shared
between several devices then the lowest request voltage that meets the
system constraints will be used.

However, previous mediatek cpufreq implementation would cause race condition
if vproc is shared by multiple devices, which would crash device due to
incorrect voltage supply.

A race condition example:
cci sets vproc 90 --> vproc=90
cpu0 sets vproc 50 --> vproc=max(50,90)=90
cpu0 sets vproc 70 --> cpu0 reads vproc 90, target is lower, so decide to scale
up frequency first, but before it set voltage...
cci sets vproc 60 --> vproc=max(60,50)=60. cpu0 already set freq to 70, but
before it set voltage, vproc becomes 60, which is not
sufficient for cpu0.

Let cpu and cci manages their own previous target voltage can avoid such race.

Signed-off-by: Hsin-Yi Wang <hsinyi@xxxxxxxxxxxx>
---
drivers/cpufreq/mediatek-cpufreq.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index 7282834e8fe2..f5e737b862f0 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -46,6 +46,7 @@ struct mtk_cpu_dvfs_info {
struct notifier_block opp_nb;
int opp_cpu;
unsigned long opp_freq;
+ int old_vproc;
};

static LIST_HEAD(dvfs_info_list);
@@ -196,11 +197,16 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,

static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
{
+ int ret;
+
if (info->need_voltage_tracking)
- return mtk_cpufreq_voltage_tracking(info, vproc);
+ ret = mtk_cpufreq_voltage_tracking(info, vproc);
else
- return regulator_set_voltage(info->proc_reg, vproc,
- vproc + VOLT_TOL);
+ ret = regulator_set_voltage(info->proc_reg, vproc,
+ MAX_VOLT_LIMIT);
+ if (!ret)
+ info->old_vproc = vproc;
+ return ret;
}

static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
@@ -218,7 +224,9 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
inter_vproc = info->intermediate_voltage;

old_freq_hz = clk_get_rate(cpu_clk);
- old_vproc = regulator_get_voltage(info->proc_reg);
+ old_vproc = info->old_vproc;
+ if (old_vproc == 0)
+ old_vproc = regulator_get_voltage(info->proc_reg);
if (old_vproc < 0) {
pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
return old_vproc;
--
2.20.1