From: Soohyun Kim Date: Fri, 30 Mar 2018 10:16:27 +0000 (+0900) Subject: cpufreq: acme: fix race contidion when set/get freq. X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=4640368983989ec7c72dc24e8342405d65a6c9e3;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git cpufreq: acme: fix race contidion when set/get freq. Change-Id: I7a7d59366d81ae4544760548dbb8fac4fed5abe0 Signed-off-by: Soohyun Kim --- diff --git a/drivers/cpufreq/exynos-acme.c b/drivers/cpufreq/exynos-acme.c index a5af5b602c81..58661b628ca9 100644 --- a/drivers/cpufreq/exynos-acme.c +++ b/drivers/cpufreq/exynos-acme.c @@ -144,8 +144,9 @@ static unsigned int get_freq(struct exynos_cpufreq_domain *domain) { unsigned int freq; - if (domain->need_awake) - disable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER); + if (domain->need_awake && + check_powerdown_state(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER)) + return domain->old; freq = (unsigned int)cal_dfs_get_rate(domain->cal_id); if (!freq) { @@ -153,9 +154,6 @@ static unsigned int get_freq(struct exynos_cpufreq_domain *domain) freq = domain->old; } - if (domain->need_awake) - enable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER); - return freq; } diff --git a/drivers/soc/samsung/exynos-cpupm.c b/drivers/soc/samsung/exynos-cpupm.c index 5eb9f67ce4d3..a25bea07a7af 100644 --- a/drivers/soc/samsung/exynos-cpupm.c +++ b/drivers/soc/samsung/exynos-cpupm.c @@ -422,6 +422,25 @@ struct exynos_cpupm { static DEFINE_PER_CPU(struct exynos_cpupm, cpupm); +int check_powerdown_state(int cpu, int type) +{ + struct exynos_cpupm *pm; + struct power_mode *mode; + int pos; + + pm = &per_cpu(cpupm, cpu); + + for_each_mode(mode, pm->modes, pos) { + if (IS_NULL(mode)) + break; + + if (mode->type == type) + return check_state_powerdown(mode); + } + + return 0; +} + /* * State of each cpu is managed by a structure declared by percpu, so there * is no need for protection for synchronization. However, when entering @@ -455,6 +474,8 @@ void disable_power_mode(int cpu, int type) struct power_mode *mode; int pos; + spin_lock(&cpupm_lock); + pm = &per_cpu(cpupm, cpu); for_each_mode(mode, pm->modes, pos) { @@ -473,10 +494,14 @@ void disable_power_mode(int cpu, int type) * The first mode disable request wakes the cpus to * exit power mode */ - if (atomic_inc_return(&mode->disable) == 1) + if (atomic_inc_return(&mode->disable) == 1) { + spin_unlock(&cpupm_lock); awake_cpus(&mode->siblings); + return; + } } } + spin_unlock(&cpupm_lock); } void enable_power_mode(int cpu, int type) @@ -485,6 +510,7 @@ void enable_power_mode(int cpu, int type) struct power_mode *mode; int pos; + spin_lock(&cpupm_lock); pm = &per_cpu(cpupm, cpu); for_each_mode(mode, pm->modes, pos) { @@ -494,6 +520,7 @@ void enable_power_mode(int cpu, int type) if (mode->type == type) atomic_dec(&mode->disable); } + spin_unlock(&cpupm_lock); } /* get sleep length of given cpu from tickless framework */ diff --git a/include/soc/samsung/exynos-cpupm.h b/include/soc/samsung/exynos-cpupm.h index 0914f0557062..9610b14face7 100644 --- a/include/soc/samsung/exynos-cpupm.h +++ b/include/soc/samsung/exynos-cpupm.h @@ -19,6 +19,7 @@ enum { extern void disable_power_mode(int cpu, int type); extern void enable_power_mode(int cpu, int type); +extern int check_powerdown_state(int cpu, int type); #ifdef CONFIG_CPU_IDLE void exynos_update_ip_idle_status(int index, int idle);