Loading Documentation/devicetree/bindings/thermal/thermal.txt +15 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ of heat dissipation). For example a fan's cooling states correspond to the different fan speeds possible. Cooling states are referred to by single unsigned integers, where larger numbers mean greater heat dissipation. The precise set of cooling states associated with a device should be defined in a particular device's binding. (as referred to by the cooling-min-level and cooling-max-level properties) should be defined in a particular device's binding. For more examples of cooling devices, refer to the example sections below. Required properties: Loading @@ -68,6 +69,15 @@ Required properties: See Cooling device maps section below for more details on how consumers refer to cooling devices. Optional properties: - cooling-min-level: An integer indicating the smallest Type: unsigned cooling state accepted. Typically 0. Size: one cell - cooling-max-level: An integer indicating the largest Type: unsigned cooling state accepted. Size: one cell * Trip points The trip node is a node to describe a point in the temperature domain Loading Loading @@ -216,6 +226,8 @@ cpus { 396000 950000 198000 850000 >; cooling-min-level = <0>; cooling-max-level = <3>; #cooling-cells = <2>; /* min followed by max */ }; ... Loading @@ -229,6 +241,8 @@ cpus { */ fan0: fan@48 { ... cooling-max-level = <9>; cooling-min-level = <0>; #cooling-cells = <2>; /* min followed by max */ }; }; Loading drivers/power/supply/power_supply_core.c +13 −9 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ void power_supply_changed(struct power_supply *psy) } EXPORT_SYMBOL_GPL(power_supply_changed); static int psy_register_cooler(struct device *dev, struct power_supply *psy); /* * Notify that power supply was registered after parent finished the probing. * Loading @@ -133,6 +134,8 @@ EXPORT_SYMBOL_GPL(power_supply_changed); * calling power_supply_changed() directly from power_supply_register() * would lead to execution of get_property() function provided by the driver * too early - before the probe ends. * Also, registering cooling device from the probe will execute the * get_property() function. So register the cooling device after the probe. * * Avoid that by waiting on parent's mutex. */ Loading @@ -149,6 +152,7 @@ static void power_supply_deferred_register_work(struct work_struct *work) } } psy_register_cooler(psy->dev.parent, psy); power_supply_changed(psy); if (psy->dev.parent) Loading Loading @@ -799,7 +803,7 @@ static const struct thermal_cooling_device_ops psy_tcd_ops = { .set_cur_state = ps_set_cur_charge_cntl_limit, }; static int psy_register_cooler(struct power_supply *psy) static int psy_register_cooler(struct device *dev, struct power_supply *psy) { int i; Loading @@ -807,6 +811,12 @@ static int psy_register_cooler(struct power_supply *psy) for (i = 0; i < psy->desc->num_properties; i++) { if (psy->desc->properties[i] == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) { if (dev) psy->tcd = thermal_of_cooling_device_register( dev_of_node(dev), (char *)psy->desc->name, psy, &psy_tcd_ops); else psy->tcd = thermal_cooling_device_register( (char *)psy->desc->name, psy, &psy_tcd_ops); Loading @@ -832,7 +842,7 @@ static void psy_unregister_thermal(struct power_supply *psy) { } static int psy_register_cooler(struct power_supply *psy) static int psy_register_cooler(struct device *dev, struct power_supply *psy) { return 0; } Loading Loading @@ -914,10 +924,6 @@ __power_supply_register(struct device *parent, if (rc) goto register_thermal_failed; rc = psy_register_cooler(psy); if (rc) goto register_cooler_failed; rc = power_supply_create_triggers(psy); if (rc) goto create_triggers_failed; Loading @@ -941,8 +947,6 @@ __power_supply_register(struct device *parent, return psy; create_triggers_failed: psy_unregister_cooler(psy); register_cooler_failed: psy_unregister_thermal(psy); register_thermal_failed: device_del(dev); Loading drivers/thermal/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,16 @@ config THERMAL_GOV_USER_SPACE help Enable this to let the user space manage the platform thermals. config THERMAL_GOV_LOW_LIMITS bool "Low limits mitigation governor" help Enable this to manage platform limits using low limits governor. Enable this governor to monitor and trigger floor mitigation. This governor will monitor the limits going below a trip threshold to trigger a floor mitigation. config THERMAL_GOV_POWER_ALLOCATOR bool "Power allocator thermal governor" help Loading drivers/thermal/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o thermal_sys-$(CONFIG_THERMAL_GOV_LOW_LIMITS) += gov_low_limits.o thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += power_allocator.o # cpufreq cooling Loading Loading @@ -54,7 +55,7 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o obj-$(CONFIG_ST_THERMAL) += st/ obj-$(CONFIG_QCOM_TSENS) += qcom/ obj-$(CONFIG_ARCH_QCOM) += qcom/ obj-y += tegra/ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o Loading drivers/thermal/gov_low_limits.c 0 → 100644 +130 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ #include <linux/thermal.h> #include <trace/events/thermal.h> #include "thermal_core.h" static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { int trip_temp, trip_hyst; enum thermal_trip_type trip_type; struct thermal_instance *instance; bool throttle; int old_target; tz->ops->get_trip_temp(tz, trip, &trip_temp); tz->ops->get_trip_type(tz, trip, &trip_type); if (tz->ops->get_trip_hyst) { tz->ops->get_trip_hyst(tz, trip, &trip_hyst); trip_hyst = trip_temp + trip_hyst; } else { trip_hyst = trip_temp; } mutex_lock(&tz->lock); list_for_each_entry(instance, &tz->thermal_instances, tz_node) { if (instance->trip != trip) continue; if ((tz->temperature <= trip_temp) || (instance->target != THERMAL_NO_TARGET && tz->temperature < trip_hyst)) throttle = true; else throttle = false; dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d,hyst=%d],throttle=%d\n", trip, trip_type, trip_temp, trip_hyst, throttle); old_target = instance->target; instance->target = (throttle) ? instance->upper : THERMAL_NO_TARGET; dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); if (instance->initialized && old_target == instance->target) continue; if (!instance->initialized) { if (instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); tz->passive += 1; } } else { if (old_target == THERMAL_NO_TARGET && instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); tz->passive += 1; } else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, false); tz->passive -= 1; } } instance->initialized = true; instance->cdev->updated = false; /* cdev needs update */ } mutex_unlock(&tz->lock); } /** * low_limits_throttle - throttles devices associated with the given zone * @tz - thermal_zone_device * @trip - the trip point * * Throttling Logic: If the sensor reading goes below a trip point, the * pre-defined mitigation will be applied for the cooling device. * If the sensor reading goes above the trip hysteresis, the * mitigation will be removed. */ static int low_limits_throttle(struct thermal_zone_device *tz, int trip) { struct thermal_instance *instance; thermal_zone_trip_update(tz, trip); mutex_lock(&tz->lock); list_for_each_entry(instance, &tz->thermal_instances, tz_node) thermal_cdev_update(instance->cdev); mutex_unlock(&tz->lock); return 0; } static struct thermal_governor thermal_gov_low_limits_floor = { .name = "low_limits_floor", .throttle = low_limits_throttle, .min_state_throttle = 1, }; static struct thermal_governor thermal_gov_low_limits_cap = { .name = "low_limits_cap", .throttle = low_limits_throttle, }; int thermal_gov_low_limits_register(void) { thermal_register_governor(&thermal_gov_low_limits_cap); return thermal_register_governor(&thermal_gov_low_limits_floor); } void thermal_gov_low_limits_unregister(void) { thermal_unregister_governor(&thermal_gov_low_limits_cap); thermal_unregister_governor(&thermal_gov_low_limits_floor); } Loading
Documentation/devicetree/bindings/thermal/thermal.txt +15 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ of heat dissipation). For example a fan's cooling states correspond to the different fan speeds possible. Cooling states are referred to by single unsigned integers, where larger numbers mean greater heat dissipation. The precise set of cooling states associated with a device should be defined in a particular device's binding. (as referred to by the cooling-min-level and cooling-max-level properties) should be defined in a particular device's binding. For more examples of cooling devices, refer to the example sections below. Required properties: Loading @@ -68,6 +69,15 @@ Required properties: See Cooling device maps section below for more details on how consumers refer to cooling devices. Optional properties: - cooling-min-level: An integer indicating the smallest Type: unsigned cooling state accepted. Typically 0. Size: one cell - cooling-max-level: An integer indicating the largest Type: unsigned cooling state accepted. Size: one cell * Trip points The trip node is a node to describe a point in the temperature domain Loading Loading @@ -216,6 +226,8 @@ cpus { 396000 950000 198000 850000 >; cooling-min-level = <0>; cooling-max-level = <3>; #cooling-cells = <2>; /* min followed by max */ }; ... Loading @@ -229,6 +241,8 @@ cpus { */ fan0: fan@48 { ... cooling-max-level = <9>; cooling-min-level = <0>; #cooling-cells = <2>; /* min followed by max */ }; }; Loading
drivers/power/supply/power_supply_core.c +13 −9 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ void power_supply_changed(struct power_supply *psy) } EXPORT_SYMBOL_GPL(power_supply_changed); static int psy_register_cooler(struct device *dev, struct power_supply *psy); /* * Notify that power supply was registered after parent finished the probing. * Loading @@ -133,6 +134,8 @@ EXPORT_SYMBOL_GPL(power_supply_changed); * calling power_supply_changed() directly from power_supply_register() * would lead to execution of get_property() function provided by the driver * too early - before the probe ends. * Also, registering cooling device from the probe will execute the * get_property() function. So register the cooling device after the probe. * * Avoid that by waiting on parent's mutex. */ Loading @@ -149,6 +152,7 @@ static void power_supply_deferred_register_work(struct work_struct *work) } } psy_register_cooler(psy->dev.parent, psy); power_supply_changed(psy); if (psy->dev.parent) Loading Loading @@ -799,7 +803,7 @@ static const struct thermal_cooling_device_ops psy_tcd_ops = { .set_cur_state = ps_set_cur_charge_cntl_limit, }; static int psy_register_cooler(struct power_supply *psy) static int psy_register_cooler(struct device *dev, struct power_supply *psy) { int i; Loading @@ -807,6 +811,12 @@ static int psy_register_cooler(struct power_supply *psy) for (i = 0; i < psy->desc->num_properties; i++) { if (psy->desc->properties[i] == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) { if (dev) psy->tcd = thermal_of_cooling_device_register( dev_of_node(dev), (char *)psy->desc->name, psy, &psy_tcd_ops); else psy->tcd = thermal_cooling_device_register( (char *)psy->desc->name, psy, &psy_tcd_ops); Loading @@ -832,7 +842,7 @@ static void psy_unregister_thermal(struct power_supply *psy) { } static int psy_register_cooler(struct power_supply *psy) static int psy_register_cooler(struct device *dev, struct power_supply *psy) { return 0; } Loading Loading @@ -914,10 +924,6 @@ __power_supply_register(struct device *parent, if (rc) goto register_thermal_failed; rc = psy_register_cooler(psy); if (rc) goto register_cooler_failed; rc = power_supply_create_triggers(psy); if (rc) goto create_triggers_failed; Loading @@ -941,8 +947,6 @@ __power_supply_register(struct device *parent, return psy; create_triggers_failed: psy_unregister_cooler(psy); register_cooler_failed: psy_unregister_thermal(psy); register_thermal_failed: device_del(dev); Loading
drivers/thermal/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,16 @@ config THERMAL_GOV_USER_SPACE help Enable this to let the user space manage the platform thermals. config THERMAL_GOV_LOW_LIMITS bool "Low limits mitigation governor" help Enable this to manage platform limits using low limits governor. Enable this governor to monitor and trigger floor mitigation. This governor will monitor the limits going below a trip threshold to trigger a floor mitigation. config THERMAL_GOV_POWER_ALLOCATOR bool "Power allocator thermal governor" help Loading
drivers/thermal/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o thermal_sys-$(CONFIG_THERMAL_GOV_LOW_LIMITS) += gov_low_limits.o thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += power_allocator.o # cpufreq cooling Loading Loading @@ -54,7 +55,7 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o obj-$(CONFIG_ST_THERMAL) += st/ obj-$(CONFIG_QCOM_TSENS) += qcom/ obj-$(CONFIG_ARCH_QCOM) += qcom/ obj-y += tegra/ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o Loading
drivers/thermal/gov_low_limits.c 0 → 100644 +130 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ #include <linux/thermal.h> #include <trace/events/thermal.h> #include "thermal_core.h" static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { int trip_temp, trip_hyst; enum thermal_trip_type trip_type; struct thermal_instance *instance; bool throttle; int old_target; tz->ops->get_trip_temp(tz, trip, &trip_temp); tz->ops->get_trip_type(tz, trip, &trip_type); if (tz->ops->get_trip_hyst) { tz->ops->get_trip_hyst(tz, trip, &trip_hyst); trip_hyst = trip_temp + trip_hyst; } else { trip_hyst = trip_temp; } mutex_lock(&tz->lock); list_for_each_entry(instance, &tz->thermal_instances, tz_node) { if (instance->trip != trip) continue; if ((tz->temperature <= trip_temp) || (instance->target != THERMAL_NO_TARGET && tz->temperature < trip_hyst)) throttle = true; else throttle = false; dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d,hyst=%d],throttle=%d\n", trip, trip_type, trip_temp, trip_hyst, throttle); old_target = instance->target; instance->target = (throttle) ? instance->upper : THERMAL_NO_TARGET; dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); if (instance->initialized && old_target == instance->target) continue; if (!instance->initialized) { if (instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); tz->passive += 1; } } else { if (old_target == THERMAL_NO_TARGET && instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); tz->passive += 1; } else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, false); tz->passive -= 1; } } instance->initialized = true; instance->cdev->updated = false; /* cdev needs update */ } mutex_unlock(&tz->lock); } /** * low_limits_throttle - throttles devices associated with the given zone * @tz - thermal_zone_device * @trip - the trip point * * Throttling Logic: If the sensor reading goes below a trip point, the * pre-defined mitigation will be applied for the cooling device. * If the sensor reading goes above the trip hysteresis, the * mitigation will be removed. */ static int low_limits_throttle(struct thermal_zone_device *tz, int trip) { struct thermal_instance *instance; thermal_zone_trip_update(tz, trip); mutex_lock(&tz->lock); list_for_each_entry(instance, &tz->thermal_instances, tz_node) thermal_cdev_update(instance->cdev); mutex_unlock(&tz->lock); return 0; } static struct thermal_governor thermal_gov_low_limits_floor = { .name = "low_limits_floor", .throttle = low_limits_throttle, .min_state_throttle = 1, }; static struct thermal_governor thermal_gov_low_limits_cap = { .name = "low_limits_cap", .throttle = low_limits_throttle, }; int thermal_gov_low_limits_register(void) { thermal_register_governor(&thermal_gov_low_limits_cap); return thermal_register_governor(&thermal_gov_low_limits_floor); } void thermal_gov_low_limits_unregister(void) { thermal_unregister_governor(&thermal_gov_low_limits_cap); thermal_unregister_governor(&thermal_gov_low_limits_floor); }