aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTao Wang <jean.wangtao@linaro.org>2017-06-13 20:22:56 +0800
committerTao Wang <jean.wangtao@linaro.org>2017-06-13 18:03:44 +0100
commitae34468bab55de90fefe22ddeb54750ce8bdf768 (patch)
tree19492c1899536e71ceb62ff0e39cce6571138b24
parent04f7dd9659ff236671e385af185cc71d377d7b92 (diff)
thermal/cpu idle cooling: cpu idle cooling cooperate with cpu cooling
This implements precise cpu thermal control through the cooperation between cpu idle cooling and cpu cooling, avoid frequency decrease if idle injection can achieve the target power limit. This can bring a smoother temperature curve and performance improvement in some case when there are big power gaps between cpu OPPs. Signed-off-by: Tao Wang <jean.wangtao@linaro.org>
-rw-r--r--drivers/thermal/Kconfig17
-rw-r--r--drivers/thermal/cpu_cooling.c31
-rw-r--r--drivers/thermal/cpu_idle_cooling.c4
-rw-r--r--include/linux/cpu_idle_cooling.h38
4 files changed, 90 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 0e90d51563cf..4da0ef53246a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -166,6 +166,23 @@ config CPU_IDLE_THERMAL
If you want this support, you should say Y here.
+config CPU_THERMAL_COMBO
+ bool "precise cpu cooling support"
+ depends on CPU_THERMAL
+ depends on CPU_IDLE_THERMAL
+ help
+ This implements precise cpu thermal control through the cooperation
+ between idle cooling and cpu cooling.
+
+ This will prevent cpu cooling scaling down cpu frequency when idle
+ injection can meet the power budget.
+
+ This can bring a smoother temperature curve and performance
+ improvement in some case when there are big power gaps between cpu
+ OPPs.
+
+ If you want this support, you should say Y here.
+
config CLOCK_THERMAL
bool "Generic clock cooling support"
depends on COMMON_CLK
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 69d0f430b2d1..a81cd92cff18 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/cpu_cooling.h>
+#include <linux/cpu_idle_cooling.h>
#include <trace/events/thermal.h>
@@ -649,6 +650,31 @@ out:
return ret;
}
+#ifdef CONFIG_CPU_THERMAL_COMBO
+static void idle_cooling_freq_adjust(
+ struct cpufreq_cooling_device *cpufreq_device,
+ u32 power, unsigned int *target_freq)
+{
+ unsigned long target_load, max_idle_ratio;
+ unsigned int idle_freq;
+ s32 cur_dyn_power;
+
+ max_idle_ratio = get_max_idle_state(&cpufreq_device->allowed_cpus);
+ cur_dyn_power = power * 100 / (100 - max_idle_ratio);
+ idle_freq = cpu_power_to_freq(cpufreq_device, cur_dyn_power);
+
+ cur_dyn_power = cpu_freq_to_power(cpufreq_device, idle_freq);
+ target_load = (power * 100) / cur_dyn_power;
+ if (target_load < 100
+ && ((idle_freq * target_load) >= ((*target_freq) * 100))) {
+ *target_freq = idle_freq;
+ } else {
+ target_load = 100;
+ }
+ set_idle_state(&cpufreq_device->allowed_cpus, 100 - target_load);
+}
+#endif
+
/**
* cpufreq_power2state() - convert power to a cooling device state
* @cdev: &thermal_cooling_device pointer
@@ -696,6 +722,11 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
normalised_power = (dyn_power * 100) / last_load;
target_freq = cpu_power_to_freq(cpufreq_device, normalised_power);
+#ifdef CONFIG_CPU_THERMAL_COMBO
+ idle_cooling_freq_adjust(cpufreq_device,
+ normalised_power, &target_freq);
+#endif
+
*state = cpufreq_cooling_get_level(cpu, target_freq);
if (*state == THERMAL_CSTATE_INVALID) {
dev_err_ratelimited(&cdev->device,
diff --git a/drivers/thermal/cpu_idle_cooling.c b/drivers/thermal/cpu_idle_cooling.c
index 6335565b4826..6f8a75485026 100644
--- a/drivers/thermal/cpu_idle_cooling.c
+++ b/drivers/thermal/cpu_idle_cooling.c
@@ -34,7 +34,11 @@
#include <linux/wait.h>
#include <linux/sched/rt.h>
+#ifdef CONFIG_CPU_THERMAL_COMBO
+#define MAX_TARGET_RATIO (20U)
+#else
#define MAX_TARGET_RATIO (50U)
+#endif
#define DEFAULT_WINDOW_SIZE (1)
#define DEFAULT_DURATION_JIFFIES (20)
diff --git a/include/linux/cpu_idle_cooling.h b/include/linux/cpu_idle_cooling.h
new file mode 100644
index 000000000000..74c53d5347f9
--- /dev/null
+++ b/include/linux/cpu_idle_cooling.h
@@ -0,0 +1,38 @@
+/*
+ * linux/drivers/thermal/cpu_idle_cooling.h
+ *
+ * Copyright (C) 2017 Tao Wang <jean.wangtao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CPU_IDLE_COOLING_H__
+#define __CPU_IDLE_COOLING_H__
+
+#include <linux/cpumask.h>
+
+#ifdef CONFIG_CPU_IDLE_THERMAL
+extern unsigned long get_max_idle_state(const struct cpumask *clip_cpus);
+extern void set_idle_state(const struct cpumask *clip_cpus,
+ unsigned long idle_ratio);
+#else
+static inline unsigned long get_max_idle_state(const struct cpumask *clip_cpus)
+{
+ return 0;
+}
+
+static inline void set_idle_state(const struct cpumask *clip_cpus,
+ unsigned long idle_ratio) {}
+#endif /* CONFIG_CPU_IDLE_THERMAL */
+
+#endif /* __CPU_IDLE_COOLING_H__ */