Introduce thermal governor which has abilities to serve scheduler needs. Basic algorithm tracks current temperature and the limit. Based on this difference estimated power budget is calculated.
Signed-off-by: Lukasz Luba l.luba@partner.samsung.com --- drivers/thermal/Kconfig | 5 ++ drivers/thermal/fair_share.c | 3 +- drivers/thermal/gov_bang_bang.c | 2 +- drivers/thermal/hisi_thermal.c | 3 +- drivers/thermal/of-thermal.c | 3 +- drivers/thermal/power_allocator.c | 3 +- drivers/thermal/qoriq_thermal.c | 3 +- drivers/thermal/rcar_gen3_thermal.c | 3 +- drivers/thermal/samsung/exynos_tmu.c | 3 +- drivers/thermal/step_wise.c | 3 +- drivers/thermal/tegra/soctherm.c | 2 +- drivers/thermal/thermal_core.c | 7 +- drivers/thermal/thermal_helpers.c | 3 +- drivers/thermal/thermal_sysfs.c | 3 +- drivers/thermal/uniphier_thermal.c | 3 +- drivers/thermal/user_space.c | 3 +- include/linux/idle_inject.h | 24 +++++ .../thermal => include/linux}/thermal_core.h | 8 ++ kernel/sched/power.c | 88 +++++++++++++++++++ 19 files changed, 145 insertions(+), 27 deletions(-) rename {drivers/thermal => include/linux}/thermal_core.h (94%)
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 0e69edc77d18..208acacbc311 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -116,6 +116,11 @@ config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR
endchoice
+config THERMAL_GOV_SCHED_POWER + bool "Sched power thermal governor" + help + Enable this to manage platform thermals using sched power governor. + config THERMAL_GOV_FAIR_SHARE bool "Fair-share thermal governor" help diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c index d3469fbc5207..ecd52fee77bf 100644 --- a/drivers/thermal/fair_share.c +++ b/drivers/thermal/fair_share.c @@ -23,10 +23,9 @@ */
#include <linux/thermal.h> +#include <linux/thermal_core.h> #include <trace/events/thermal.h>
-#include "thermal_core.h" - /** * get_trip_level: - obtains the current trip level for a zone * @tz: thermal zone device diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index fc5e5057f0de..8f94e3285283 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -20,8 +20,8 @@ */
#include <linux/thermal.h> +#include <linux/thermal_core.h>
-#include "thermal_core.h"
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 761d0559c268..d79db9c04917 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -24,8 +24,7 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/of_device.h> - -#include "thermal_core.h" +#include <linux/thermal_core.h>
#define HI6220_TEMP0_LAG (0x0) #define HI6220_TEMP0_TH (0x4) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 1825d30e9b0b..f7049ee16e98 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -6,6 +6,7 @@ * Copyright (C) 2013 Eduardo Valentin eduardo.valentin@ti.com */ #include <linux/thermal.h> +#include <linux/thermal_core.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/of_device.h> @@ -14,8 +15,6 @@ #include <linux/export.h> #include <linux/string.h>
-#include "thermal_core.h" - /*** Private data structures to represent thermal device tree data ***/
/** diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index 3055f9a12a17..1e67f32613c6 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -18,12 +18,11 @@ #include <linux/rculist.h> #include <linux/slab.h> #include <linux/thermal.h> +#include <linux/thermal_core.h>
#define CREATE_TRACE_POINTS #include <trace/events/thermal_power_allocator.h>
-#include "thermal_core.h" - #define INVALID_TRIP -1
#define FRAC_BITS 10 diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c index 450ed66edf58..c8268a0b5ea7 100644 --- a/drivers/thermal/qoriq_thermal.c +++ b/drivers/thermal/qoriq_thermal.c @@ -9,8 +9,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/thermal.h> - -#include "thermal_core.h" +#include <linux/thermal_core.h>
#define SITES_MAX 16
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 7aed5337bdd3..62e793b96f0a 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -17,8 +17,7 @@ #include <linux/spinlock.h> #include <linux/sys_soc.h> #include <linux/thermal.h> - -#include "thermal_core.h" +#include <linux/thermal_core.h>
/* Register offsets */ #define REG_GEN3_IRQSTR 0x04 diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 48eef552cba4..e6c2ddd96487 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -34,11 +34,10 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/thermal_core.h>
#include <dt-bindings/thermal/thermal_exynos.h>
-#include "../thermal_core.h" - /* Exynos generic registers */ #define EXYNOS_TMU_REG_TRIMINFO 0x0 #define EXYNOS_TMU_REG_CONTROL 0x20 diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index ee047ca43084..e51c5b642e56 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -23,10 +23,9 @@ */
#include <linux/thermal.h> +#include <linux/thermal_core.h> #include <trace/events/thermal.h>
-#include "thermal_core.h" - /* * If the temperature is higher than a trip point, * a. if the trend is THERMAL_TREND_RAISING, use higher cooling diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index ed28110a3535..68ae5c235303 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -27,10 +27,10 @@ #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/thermal.h> +#include <linux/thermal_core.h>
#include <dt-bindings/thermal/tegra124-soctherm.h>
-#include "../thermal_core.h" #include "soctherm.h"
#define SENSOR_CONFIG0 0 diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index ecff9740cbf0..106601da9a20 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -17,6 +17,7 @@ #include <linux/kdev_t.h> #include <linux/idr.h> #include <linux/thermal.h> +#include <linux/thermal_core.h> #include <linux/reboot.h> #include <linux/string.h> #include <linux/sched/power.h> @@ -28,7 +29,6 @@ #define CREATE_TRACE_POINTS #include <trace/events/thermal.h>
-#include "thermal_core.h" #include "thermal_hwmon.h"
MODULE_AUTHOR("Zhang Rui"); @@ -249,6 +249,10 @@ static int __init thermal_register_governors(void) { int result;
+ result = thermal_gov_sched_power_register(); + if (result) + return result; + result = thermal_gov_step_wise_register(); if (result) return result; @@ -270,6 +274,7 @@ static int __init thermal_register_governors(void)
static void thermal_unregister_governors(void) { + thermal_gov_sched_power_unregister(); thermal_gov_step_wise_unregister(); thermal_gov_fair_share_unregister(); thermal_gov_bang_bang_unregister(); diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index 2ba756af76b7..fb6c979bf4f7 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -17,11 +17,10 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/thermal_core.h>
#include <trace/events/thermal.h>
-#include "thermal_core.h" - int get_tz_trend(struct thermal_zone_device *tz, int trip) { enum thermal_trend trend; diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 2241ceae7d7f..fb625f6522e2 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -18,8 +18,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/jiffies.h> - -#include "thermal_core.h" +#include <linux/thermal_core.h>
/* sys I/F for thermal zone */
diff --git a/drivers/thermal/uniphier_thermal.c b/drivers/thermal/uniphier_thermal.c index 55477d74d591..ee0397b9c5d3 100644 --- a/drivers/thermal/uniphier_thermal.c +++ b/drivers/thermal/uniphier_thermal.c @@ -27,8 +27,7 @@ #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/thermal.h> - -#include "thermal_core.h" +#include <linux/thermal_core.h>
/* * block registers diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c index 8e92a06ef48a..4a6a80ddb556 100644 --- a/drivers/thermal/user_space.c +++ b/drivers/thermal/user_space.c @@ -23,10 +23,9 @@ */
#include <linux/thermal.h> +#include <linux/thermal_core.h> #include <linux/slab.h>
-#include "thermal_core.h" - /** * notify_user_space - Notifies user space about thermal events * @tz - thermal_zone_device diff --git a/include/linux/idle_inject.h b/include/linux/idle_inject.h index 4c60f91ef7a2..90583e37022c 100644 --- a/include/linux/idle_inject.h +++ b/include/linux/idle_inject.h @@ -22,6 +22,7 @@ struct idle_inject_device { unsigned long int cpumask[0]; };
+#ifdef CONFIG_IDLE_INJECT struct idle_inject_device *idle_inject_register(struct cpumask *cpumask);
void idle_inject_unregister(struct idle_inject_device *ii_dev); @@ -37,4 +38,27 @@ void idle_inject_set_duration(struct idle_inject_device *ii_dev, void idle_inject_get_duration(struct idle_inject_device *ii_dev, unsigned int *run_duration_ms, unsigned int *idle_duration_ms); +#else /* CONFIG_IDLE_INJECT */ +struct idle_inject_device *idle_inject_register(struct cpumask *cpumask) +{ + return NULL; +} + +void idle_inject_unregister(struct idle_inject_device *ii_dev) {} + +int idle_inject_start(struct idle_inject_device *ii_dev) +{ + return -ENODEV; +} + +void idle_inject_stop(struct idle_inject_device *ii_dev) {} + +void idle_inject_set_duration(struct idle_inject_device *ii_dev, + unsigned int run_duration_ms, + unsigned int idle_duration_ms) {} + +void idle_inject_get_duration(struct idle_inject_device *ii_dev, + unsigned int *run_duration_ms, + unsigned int *idle_duration_ms) {} +#endif /* CONFIG_IDLE_INJECT */ #endif /* __IDLE_INJECT_H__ */ diff --git a/drivers/thermal/thermal_core.h b/include/linux/thermal_core.h similarity index 94% rename from drivers/thermal/thermal_core.h rename to include/linux/thermal_core.h index 66527810a06c..adff231eec2a 100644 --- a/drivers/thermal/thermal_core.h +++ b/include/linux/thermal_core.h @@ -76,6 +76,14 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, unsigned long new_state) {} #endif /* CONFIG_THERMAL_STATISTICS */
+#ifdef CONFIG_THERMAL_GOV_SCHED_POWER +int thermal_gov_sched_power_register(void); +void thermal_gov_sched_power_unregister(void); +#else +static inline int thermal_gov_sched_power_register(void) { return 0; } +static inline void thermal_gov_sched_power_unregister(void) {} +#endif /* CONFIG_THERMAL_GOV_SCHED_POWER */ + #ifdef CONFIG_THERMAL_GOV_STEP_WISE int thermal_gov_step_wise_register(void); void thermal_gov_step_wise_unregister(void); diff --git a/kernel/sched/power.c b/kernel/sched/power.c index 808d8db5c02d..1976e5db8efc 100644 --- a/kernel/sched/power.c +++ b/kernel/sched/power.c @@ -8,6 +8,7 @@
#include <linux/sched.h> #include <linux/thermal.h> +#include <linux/thermal_core.h> #include <linux/idle_inject.h>
#include "power.h" @@ -474,3 +475,90 @@ static int __init sched_power_init(void) return ret; } fs_initcall(sched_power_init); + + + +/////////////////thermal governor//////////////////////// + +static int cdev_get_min_power(struct thermal_cooling_device *cdev, + u64 *min_power) +{ + return 0; +} + +static u64 estimate_total_min_power(struct thermal_zone_device *tz, int trip) +{ + u64 total_min_power = 0; + u64 min_power; + struct thermal_instance *inst; + + list_for_each_entry(inst, &tz->thermal_instances, tz_node) { + cdev_get_min_power(inst->cdev, &min_power); + total_min_power += min_power; + } + + return total_min_power; +} + +static u64 calc_power_budget(struct thermal_zone_device *tz, int desire_temp) +{ + s64 temp_diff; + s64 power_budget; + + /* temperature is represented in milidegress */ + temp_diff = desire_temp - tz->temperature; + + power_budget = temp_diff; + + power_budget = max(0, power_budget); + + return power_budget; +} + +static int controller_prepare_coefficents(struct thermal_zone_device *tz, + int trip) +{ + return 0; +} + +static int sched_power_gov_throttle(struct thermal_zone_device *tz, int trip) +{ + + return 0; +} + +static int sched_power_gov_bind(struct thermal_zone_device *tz) +{ + struct thermal_instance *inst; + + list_for_each_entry(inst, &tz->thermal_instances, tz_node) { + + + } + + return 0; +} + +static void sched_power_gov_unbind(struct thermal_zone_device *tz) +{ + +} + +static struct thermal_governor sched_power_gov = { + .name = "sched_power", + .bind_to_tz = sched_power_gov_bind, + .unbind_from_tz = sched_power_gov_unbind, + .throttle = sched_power_gov_throttle, +}; + +int thermal_gov_sched_power_register(void) +{ + return thermal_register_governor(&sched_power_gov); +} + +void thermal_gov_sched_power_unregister(void) +{ + thermal_unregister_governor(&sched_power_gov); +} + +/////////////////////////////////////////////////////////