cpufreq: acme: disable cluster-wide power mode while getting/setting frequency
authorPark Bumgyu <bumgyu.park@samsung.com>
Wed, 14 Mar 2018 10:45:28 +0000 (19:45 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:30:42 +0000 (17:30 +0900)
Change-Id: I0d999d112d4785544e3f89b41055e51f55bf1921
Signed-off-by: Park Bumgyu <bumgyu.park@samsung.com>
drivers/cpufreq/exynos-acme.c
drivers/soc/samsung/exynos-cpupm.c
include/soc/samsung/exynos-cpupm.h

index 204306e05d60744fe652ba9abbe8f416d7406cb2..763c5482b8e355ac0eba2f2c4e1afeea0ef05b06 100644 (file)
@@ -26,6 +26,7 @@
 #include <soc/samsung/exynos-dm.h>
 #include <soc/samsung/ect_parser.h>
 #include <soc/samsung/exynos-cpu_hotplug.h>
+#include <soc/samsung/exynos-cpupm.h>
 
 #include "exynos-acme.h"
 
@@ -134,13 +135,24 @@ static unsigned int index_to_freq(struct cpufreq_frequency_table *table,
 /*********************************************************************
  *                         FREQUENCY SCALING                         *
  *********************************************************************/
+/*
+ * Depending on cluster structure, it cannot be possible to get/set
+ * cpu frequency while cluster is off. For this, disable cluster-wide
+ * power mode while getting/setting frequency.
+ */
 static unsigned int get_freq(struct exynos_cpufreq_domain *domain)
 {
-       unsigned int freq = (unsigned int)cal_dfs_get_rate(domain->cal_id);
+       unsigned int freq;
+
+       disable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
 
-       /* On changing state, CAL returns 0 */
-       if (!freq)
-               return domain->old;
+       freq = (unsigned int)cal_dfs_get_rate(domain->cal_id);
+       if (!freq) {
+               /* On changing state, CAL returns 0 */
+               freq = domain->old;
+       }
+
+       enable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
 
        return freq;
 }
@@ -150,6 +162,8 @@ static int set_freq(struct exynos_cpufreq_domain *domain,
 {
        int err;
 
+       disable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
+
        exynos_ss_printk("ID %d: %d -> %d (%d)\n",
                domain->id, domain->old, target_freq, ESS_FLAG_IN);
 
@@ -161,6 +175,8 @@ static int set_freq(struct exynos_cpufreq_domain *domain,
        exynos_ss_printk("ID %d: %d -> %d (%d)\n",
                domain->id, domain->old, target_freq, ESS_FLAG_OUT);
 
+       enable_power_mode(cpumask_any(&domain->cpus), POWERMODE_TYPE_CLUSTER);
+
        return err;
 }
 
index 55f6721f3f927df9a24afe98001059f7cfafa96b..fb6ff4025503c11f7c99b47511884860dc6f4dde 100644 (file)
@@ -440,7 +440,7 @@ static void awake_cpus(const struct cpumask *cpus)
        struct cpumask mask;
 
        cpumask_and(&mask, cpus, cpu_online_mask);
-       smp_call_function_many(&mask, do_nothing, NULL, 0);
+       smp_call_function_single(cpumask_any(&mask), do_nothing, NULL, 1);
 }
 
 /*
@@ -455,13 +455,19 @@ 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) {
                if (IS_NULL(mode))
                        break;
 
+               /*
+                * There are no entry allowed cpus, it means that mode is
+                * disabled, skip awaking cpus.
+                */
+               if (cpumask_empty(&mode->entry_allowed))
+                       continue;
+
                if (mode->type == type) {
                        /*
                         * The first mode disable request wakes the cpus to
@@ -471,7 +477,6 @@ void disable_power_mode(int cpu, int type)
                                awake_cpus(&mode->siblings);
                }
        }
-       spin_unlock(&cpupm_lock);
 }
 
 void enable_power_mode(int cpu, int type)
@@ -480,7 +485,6 @@ 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) {
@@ -490,7 +494,6 @@ 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 */
index 460628c5014cce13a1629a8fd1e56e8c83245cdb..0914f0557062e3ff9396e94f6adf097b45f7ca8b 100644 (file)
@@ -17,8 +17,8 @@ enum {
        POWERMODE_TYPE_SYSTEM,
 };
 
-extern void disable_mode(int cpu, int type);
-extern void enable_mode(int cpu, int type);
+extern void disable_power_mode(int cpu, int type);
+extern void enable_power_mode(int cpu, int type);
 
 #ifdef CONFIG_CPU_IDLE
 void exynos_update_ip_idle_status(int index, int idle);