summaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-13 09:00:28 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-13 09:00:28 -0800
commit9346116d148595a28fe3521f81ac8e14d93239c3 (patch)
treeb56004a1b71089e3a185464d0baad2e22c53dfa6 /drivers/thermal
parentb8d2798f32785398fcd1c48ea80c0c6c5ab88537 (diff)
parent0faf7dd5a947006978b549dfe29a01b710becf4a (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui: - Thermal core code reorganization and cleanup. Two new files are created for thermal sysfs I/F code and thermal helper functions (Eduardo Valentin). - Sanitize hotplug and locking for x86_pkg_temp driver (Thomas Gleixner) - Update MAINTAINER file for pwm-fan driver and Samsung thermal driver (Lukasz Majewski) - Fix module auto-load for max77620, tango and db8500 thermal driver (Javier Martinez Canillas) - Fix a bug that thermal hwmon sysfs I/F returns wrong critical trip point temperature value (Krzysztof Kozlowski) - Add Skylake PCH 100 series support for intel_pch_thermal driver (OGAWA Hirofumi) - Small fixes and cleanups for platform thermal drivers (Julia Lawall, Luis Henriques, Leo Yan, Stephen Boyd, Shawn Lin, Javi Merino and Lukasz Luba) * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (76 commits) MAINTAINERS: Samsung: Update maintainer for PWM FAN and SAMSUNG THERMAL thermal/x86 pkg temp: Convert to hotplug state machine thermal/x86_pkg_temp: Sanitize package management thermal/x86_pkg_temp: Move work into package struct thermal/x86_pkg_temp: Move work scheduled flag into package struct thermal/x86_pkg_temp: Sanitize locking thermal/x86_pkg_temp: Cleanup code some more thermal/x86_pkg_temp: Cleanup namespace thermal/x86_pkg_temp: Get rid of ref counting thermal/x86_pkg_temp: Sanitize callback (de)initialization thermal/x86_pkg_temp: Replace open coded cpu search thermal/x86_pkg_temp: Remove redundant package search thermal/x86_pkg_temp: Cleanup thermal interrupt handling thermal: hwmon: Properly report critical temperature in sysfs devfreq_cooling: pass a pointer to devfreq in the power model callbacks devfreq_cooling: make the structs devfreq_cooling_xxx visible for all dt-bindings: rockchip-thermal: fix the misleading description thermal: rockchip: improve the warning log thermal: db8500: Fix module autoload thermal: tango: Fix module autoload ...
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/Kconfig4
-rw-r--r--drivers/thermal/Makefile3
-rw-r--r--drivers/thermal/db8500_thermal.c1
-rw-r--r--drivers/thermal/devfreq_cooling.c5
-rw-r--r--drivers/thermal/int340x_thermal/int3400_thermal.c2
-rw-r--r--drivers/thermal/intel_pch_thermal.c64
-rw-r--r--drivers/thermal/max77620_thermal.c1
-rw-r--r--drivers/thermal/qcom-spmi-temp-alarm.c6
-rw-r--r--drivers/thermal/rockchip_thermal.c7
-rw-r--r--drivers/thermal/tango_thermal.c1
-rw-r--r--drivers/thermal/thermal_core.c1444
-rw-r--r--drivers/thermal/thermal_core.h26
-rw-r--r--drivers/thermal/thermal_helpers.c226
-rw-r--r--drivers/thermal/thermal_hwmon.c4
-rw-r--r--drivers/thermal/thermal_sysfs.c771
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c5
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c587
17 files changed, 1636 insertions, 1521 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index a13541bdc726..c2c056cc7ea5 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -177,8 +177,10 @@ config THERMAL_EMULATION
config HISI_THERMAL
tristate "Hisilicon thermal driver"
- depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST
+ depends on ARCH_HISI || COMPILE_TEST
depends on HAS_IOMEM
+ depends on OF
+ default y
help
Enable this to plug hisilicon's thermal sensor driver into the Linux
thermal framework. cpufreq is used as the cooling device to throttle
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index c92eb22a41ff..6a3d7b573036 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,7 +3,8 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
-thermal_sys-y += thermal_core.o
+thermal_sys-y += thermal_core.o thermal_sysfs.o \
+ thermal_helpers.o
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
index e776cea80cfc..f491faf16592 100644
--- a/drivers/thermal/db8500_thermal.c
+++ b/drivers/thermal/db8500_thermal.c
@@ -512,6 +512,7 @@ static const struct of_device_id db8500_thermal_match[] = {
{ .compatible = "stericsson,db8500-thermal" },
{},
};
+MODULE_DEVICE_TABLE(of, db8500_thermal_match);
#endif
static struct platform_driver db8500_thermal_driver = {
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 81631b110e17..5a737fd5f1aa 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -238,7 +238,7 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
return 0;
}
- return dfc->power_ops->get_static_power(voltage);
+ return dfc->power_ops->get_static_power(df, voltage);
}
/**
@@ -262,7 +262,8 @@ get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq,
struct devfreq_cooling_power *dfc_power = dfc->power_ops;
if (dfc_power->get_dynamic_power)
- return dfc_power->get_dynamic_power(freq, voltage);
+ return dfc_power->get_dynamic_power(dfc->devfreq, freq,
+ voltage);
freq_mhz = freq / 1000000;
power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage;
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
index 5836e5554433..9413c4abf0b9 100644
--- a/drivers/thermal/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -96,7 +96,7 @@ static ssize_t current_uuid_store(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(current_uuid, 0644, current_uuid_show, current_uuid_store);
+static DEVICE_ATTR_RW(current_uuid);
static DEVICE_ATTR_RO(available_uuids);
static struct attribute *uuid_attrs[] = {
&dev_attr_available_uuids.attr,
diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c
index 19bf2028e508..2b49e8d0fe9e 100644
--- a/drivers/thermal/intel_pch_thermal.c
+++ b/drivers/thermal/intel_pch_thermal.c
@@ -29,6 +29,7 @@
#define PCH_THERMAL_DID_HSW_2 0x8C24 /* Haswell PCH */
#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
+#define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */
/* Wildcat Point-LP PCH Thermal registers */
#define WPT_TEMP 0x0000 /* Temperature */
@@ -273,37 +274,44 @@ static struct thermal_zone_device_ops tzd_ops = {
.get_trip_temp = pch_get_trip_temp,
};
+enum board_ids {
+ board_hsw,
+ board_wpt,
+ board_skl,
+};
+
+static const struct board_info {
+ const char *name;
+ const struct pch_dev_ops *ops;
+} board_info[] = {
+ [board_hsw] = {
+ .name = "pch_haswell",
+ .ops = &pch_dev_ops_wpt,
+ },
+ [board_wpt] = {
+ .name = "pch_wildcat_point",
+ .ops = &pch_dev_ops_wpt,
+ },
+ [board_skl] = {
+ .name = "pch_skylake",
+ .ops = &pch_dev_ops_wpt,
+ },
+};
static int intel_pch_thermal_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
+ enum board_ids board_id = id->driver_data;
+ const struct board_info *bi = &board_info[board_id];
struct pch_thermal_device *ptd;
int err;
int nr_trips;
- char *dev_name;
ptd = devm_kzalloc(&pdev->dev, sizeof(*ptd), GFP_KERNEL);
if (!ptd)
return -ENOMEM;
- switch (pdev->device) {
- case PCH_THERMAL_DID_WPT:
- ptd->ops = &pch_dev_ops_wpt;
- dev_name = "pch_wildcat_point";
- break;
- case PCH_THERMAL_DID_SKL:
- ptd->ops = &pch_dev_ops_wpt;
- dev_name = "pch_skylake";
- break;
- case PCH_THERMAL_DID_HSW_1:
- case PCH_THERMAL_DID_HSW_2:
- ptd->ops = &pch_dev_ops_wpt;
- dev_name = "pch_haswell";
- break;
- default:
- dev_err(&pdev->dev, "unknown pch thermal device\n");
- return -ENODEV;
- }
+ ptd->ops = bi->ops;
pci_set_drvdata(pdev, ptd);
ptd->pdev = pdev;
@@ -331,11 +339,11 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev,
if (err)
goto error_cleanup;
- ptd->tzd = thermal_zone_device_register(dev_name, nr_trips, 0, ptd,
+ ptd->tzd = thermal_zone_device_register(bi->name, nr_trips, 0, ptd,
&tzd_ops, NULL, 0, 0);
if (IS_ERR(ptd->tzd)) {
dev_err(&pdev->dev, "Failed to register thermal zone %s\n",
- dev_name);
+ bi->name);
err = PTR_ERR(ptd->tzd);
goto error_cleanup;
}
@@ -380,10 +388,16 @@ static int intel_pch_thermal_resume(struct device *device)
}
static struct pci_device_id intel_pch_thermal_id[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1),
+ .driver_data = board_hsw, },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2),
+ .driver_data = board_hsw, },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT),
+ .driver_data = board_wpt, },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL),
+ .driver_data = board_skl, },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
+ .driver_data = board_skl, },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
diff --git a/drivers/thermal/max77620_thermal.c b/drivers/thermal/max77620_thermal.c
index 83905ff46e40..e9a1fe342760 100644
--- a/drivers/thermal/max77620_thermal.c
+++ b/drivers/thermal/max77620_thermal.c
@@ -149,6 +149,7 @@ static struct platform_device_id max77620_thermal_devtype[] = {
{ .name = "max77620-thermal", },
{},
};
+MODULE_DEVICE_TABLE(platform, max77620_thermal_devtype);
static struct platform_driver max77620_thermal_driver = {
.driver = {
diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c
index 819c6d5d7aa7..f50241962ad2 100644
--- a/drivers/thermal/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom-spmi-temp-alarm.c
@@ -200,7 +200,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
struct qpnp_tm_chip *chip;
struct device_node *node;
u8 type, subtype;
- u32 res[2];
+ u32 res;
int ret, irq;
node = pdev->dev.of_node;
@@ -215,7 +215,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
if (!chip->map)
return -ENXIO;
- ret = of_property_read_u32_array(node, "reg", res, 2);
+ ret = of_property_read_u32(node, "reg", &res);
if (ret < 0)
return ret;
@@ -228,7 +228,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
if (PTR_ERR(chip->adc) == -EPROBE_DEFER)
return PTR_ERR(chip->adc);
- chip->base = res[0];
+ chip->base = res;
ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
if (ret < 0) {
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index e227a9f0acf7..b811b0fb61b1 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -524,11 +524,6 @@ static void rk_tsadcv2_initialize(struct regmap *grf, void __iomem *regs,
regs + TSADCV2_AUTO_PERIOD_HT);
writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
-
- if (IS_ERR(grf)) {
- pr_warn("%s: Missing rockchip,grf property\n", __func__);
- return;
- }
}
/**
@@ -971,6 +966,8 @@ static int rockchip_configure_from_dt(struct device *dev,
* need this property.
*/
thermal->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(thermal->grf))
+ dev_warn(dev, "Missing rockchip,grf property\n");
return 0;
}
diff --git a/drivers/thermal/tango_thermal.c b/drivers/thermal/tango_thermal.c
index 201304aeafeb..4e67795cb6ce 100644
--- a/drivers/thermal/tango_thermal.c
+++ b/drivers/thermal/tango_thermal.c
@@ -107,6 +107,7 @@ static const struct of_device_id tango_sensor_ids[] = {
},
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, tango_sensor_ids);
static struct platform_driver tango_thermal_driver = {
.probe = tango_thermal_probe,
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 911fd964c742..641faab6e24b 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -5,22 +5,9 @@
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
*
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
* 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, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -64,6 +51,13 @@ static atomic_t in_suspend;
static struct thermal_governor *def_governor;
+/*
+ * Governor section: set of functions to handle thermal governors
+ *
+ * Functions to help in the life cycle of thermal governors within
+ * the thermal core and by the thermal governor code.
+ */
+
static struct thermal_governor *__find_governor(const char *name)
{
struct thermal_governor *pos;
@@ -142,11 +136,16 @@ int thermal_register_governor(struct thermal_governor *governor)
mutex_lock(&thermal_governor_lock);
err = -EBUSY;
- if (__find_governor(governor->name) == NULL) {
+ if (!__find_governor(governor->name)) {
+ bool match_default;
+
err = 0;
list_add(&governor->governor_list, &thermal_governor_list);
- if (!def_governor && !strncmp(governor->name,
- DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
+ match_default = !strncmp(governor->name,
+ DEFAULT_THERMAL_GOVERNOR,
+ THERMAL_NAME_LENGTH);
+
+ if (!def_governor && match_default)
def_governor = governor;
}
@@ -188,14 +187,14 @@ void thermal_unregister_governor(struct thermal_governor *governor)
mutex_lock(&thermal_governor_lock);
- if (__find_governor(governor->name) == NULL)
+ if (!__find_governor(governor->name))
goto exit;
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node) {
if (!strncasecmp(pos->governor->name, governor->name,
- THERMAL_NAME_LENGTH))
+ THERMAL_NAME_LENGTH))
thermal_set_governor(pos, NULL);
}
@@ -203,195 +202,92 @@ void thermal_unregister_governor(struct thermal_governor *governor)
list_del(&governor->governor_list);
exit:
mutex_unlock(&thermal_governor_lock);
- return;
}
-static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+int thermal_zone_device_set_policy(struct thermal_zone_device *tz,
+ char *policy)
{
- int ret;
-
- if (lock)
- mutex_lock(lock);
- ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
- if (lock)
- mutex_unlock(lock);
- if (unlikely(ret < 0))
- return ret;
- *id = ret;
- return 0;
-}
-
-static void release_idr(struct idr *idr, struct mutex *lock, int id)
-{
- if (lock)
- mutex_lock(lock);
- idr_remove(idr, id);
- if (lock)
- mutex_unlock(lock);
-}
-
-int get_tz_trend(struct thermal_zone_device *tz, int trip)
-{
- enum thermal_trend trend;
-
- if (tz->emul_temperature || !tz->ops->get_trend ||
- tz->ops->get_trend(tz, trip, &trend)) {
- if (tz->temperature > tz->last_temperature)
- trend = THERMAL_TREND_RAISING;
- else if (tz->temperature < tz->last_temperature)
- trend = THERMAL_TREND_DROPPING;
- else
- trend = THERMAL_TREND_STABLE;
- }
-
- return trend;
-}
-EXPORT_SYMBOL(get_tz_trend);
-
-struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
- struct thermal_cooling_device *cdev, int trip)
-{
- struct thermal_instance *pos = NULL;
- struct thermal_instance *target_instance = NULL;
+ struct thermal_governor *gov;
+ int ret = -EINVAL;
+ mutex_lock(&thermal_governor_lock);
mutex_lock(&tz->lock);
- mutex_lock(&cdev->lock);
- list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
- if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
- target_instance = pos;
- break;
- }
- }
+ gov = __find_governor(strim(policy));
+ if (!gov)
+ goto exit;
- mutex_unlock(&cdev->lock);
- mutex_unlock(&tz->lock);
+ ret = thermal_set_governor(tz, gov);
- return target_instance;
-}
-EXPORT_SYMBOL(get_thermal_instance);
+exit:
+ mutex_unlock(&tz->lock);
+ mutex_unlock(&thermal_governor_lock);
-static void print_bind_err_msg(struct thermal_zone_device *tz,
- struct thermal_cooling_device *cdev, int ret)
-{
- dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
- tz->type, cdev->type, ret);
+ return ret;
}
-static void __bind(struct thermal_zone_device *tz, int mask,
- struct thermal_cooling_device *cdev,
- unsigned long *limits,
- unsigned int weight)
+int thermal_build_list_of_policies(char *buf)
{
- int i, ret;
+ struct thermal_governor *pos;
+ ssize_t count = 0;
+ ssize_t size = PAGE_SIZE;
- for (i = 0; i < tz->trips; i++) {
- if (mask & (1 << i)) {
- unsigned long upper, lower;
+ mutex_lock(&thermal_governor_lock);
- upper = THERMAL_NO_LIMIT;
- lower = THERMAL_NO_LIMIT;
- if (limits) {
- lower = limits[i * 2];
- upper = limits[i * 2 + 1];
- }
- ret = thermal_zone_bind_cooling_device(tz, i, cdev,
- upper, lower,
- weight);
- if (ret)
- print_bind_err_msg(tz, cdev, ret);
- }
+ list_for_each_entry(pos, &thermal_governor_list, governor_list) {
+ size = PAGE_SIZE - count;
+ count += scnprintf(buf + count, size, "%s ", pos->name);
}
-}
+ count += scnprintf(buf + count, size, "\n");
-static void __unbind(struct thermal_zone_device *tz, int mask,
- struct thermal_cooling_device *cdev)
-{
- int i;
+ mutex_unlock(&thermal_governor_lock);
- for (i = 0; i < tz->trips; i++)
- if (mask & (1 << i))
- thermal_zone_unbind_cooling_device(tz, i, cdev);
+ return count;
}
-static void bind_cdev(struct thermal_cooling_device *cdev)
+static int __init thermal_register_governors(void)
{
- int i, ret;
- const struct thermal_zone_params *tzp;
- struct thermal_zone_device *pos = NULL;
-
- mutex_lock(&thermal_list_lock);
+ int result;
- list_for_each_entry(pos, &thermal_tz_list, node) {
- if (!pos->tzp && !pos->ops->bind)
- continue;
+ result = thermal_gov_step_wise_register();
+ if (result)
+ return result;
- if (pos->ops->bind) {
- ret = pos->ops->bind(pos, cdev);
- if (ret)
- print_bind_err_msg(pos, cdev, ret);
- continue;
- }
+ result = thermal_gov_fair_share_register();
+ if (result)
+ return result;
- tzp = pos->tzp;
- if (!tzp || !tzp->tbp)
- continue;
+ result = thermal_gov_bang_bang_register();
+ if (result)
+ return result;
- for (i = 0; i < tzp->num_tbps; i++) {
- if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
- continue;
- if (tzp->tbp[i].match(pos, cdev))
- continue;
- tzp->tbp[i].cdev = cdev;
- __bind(pos, tzp->tbp[i].trip_mask, cdev,
- tzp->tbp[i].binding_limits,
- tzp->tbp[i].weight);
- }
- }
+ result = thermal_gov_user_space_register();
+ if (result)
+ return result;
- mutex_unlock(&thermal_list_lock);
+ return thermal_gov_power_allocator_register();
}
-static void bind_tz(struct thermal_zone_device *tz)
+static void thermal_unregister_governors(void)
{
- int i, ret;
- struct thermal_cooling_device *pos = NULL;
- const struct thermal_zone_params *tzp = tz->tzp;
-
- if (!tzp && !tz->ops->bind)
- return;
-
- mutex_lock(&thermal_list_lock);
-
- /* If there is ops->bind, try to use ops->bind */
- if (tz->ops->bind) {
- list_for_each_entry(pos, &thermal_cdev_list, node) {
- ret = tz->ops->bind(tz, pos);
- if (ret)
- print_bind_err_msg(tz, pos, ret);
- }
- goto exit;
- }
-
- if (!tzp || !tzp->tbp)
- goto exit;
-
- list_for_each_entry(pos, &thermal_cdev_list, node) {
- for (i = 0; i < tzp->num_tbps; i++) {
- if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
- continue;
- if (tzp->tbp[i].match(tz, pos))
- continue;
- tzp->tbp[i].cdev = pos;
- __bind(tz, tzp->tbp[i].trip_mask, pos,
- tzp->tbp[i].binding_limits,
- tzp->tbp[i].weight);
- }
- }
-exit:
- mutex_unlock(&thermal_list_lock);
+ thermal_gov_step_wise_unregister();
+ thermal_gov_fair_share_unregister();
+ thermal_gov_bang_bang_unregister();
+ thermal_gov_user_space_unregister();
+ thermal_gov_power_allocator_unregister();
}
+/*
+ * Zone update section: main control loop applied to each zone while monitoring
+ *
+ * in polling mode. The monitoring is done using a workqueue.
+ * Same update may be done on a zone by calling thermal_zone_device_update().
+ *
+ * An update means:
+ * - Non-critical trips will invoke the governor responsible for that zone;
+ * - Hot trips will produce a notification to userspace;
+ * - Critical trip point will cause a system shutdown.
+ */
static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
int delay)
{
@@ -420,14 +316,15 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
}
static void handle_non_critical_trips(struct thermal_zone_device *tz,
- int trip, enum thermal_trip_type trip_type)
+ int trip,
+ enum thermal_trip_type trip_type)
{
tz->governor ? tz->governor->throttle(tz, trip) :
def_governor->throttle(tz, trip);
}
static void handle_critical_trips(struct thermal_zone_device *tz,
- int trip, enum thermal_trip_type trip_type)
+ int trip, enum thermal_trip_type trip_type)
{
int trip_temp;
@@ -471,105 +368,6 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
monitor_thermal_zone(tz);
}
-/**
- * thermal_zone_get_temp() - returns the temperature of a thermal zone
- * @tz: a valid pointer to a struct thermal_zone_device
- * @temp: a valid pointer to where to store the resulting temperature.
- *
- * When a valid thermal zone reference is passed, it will fetch its
- * temperature and fill @temp.
- *
- * Return: On success returns 0, an error code otherwise
- */
-int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
-{
- int ret = -EINVAL;
- int count;
- int crit_temp = INT_MAX;
- enum thermal_trip_type type;
-
- if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
- goto exit;
-
- mutex_lock(&tz->lock);
-
- ret = tz->ops->get_temp(tz, temp);
-
- if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
- for (count = 0; count < tz->trips; count++) {
- ret = tz->ops->get_trip_type(tz, count, &type);
- if (!ret && type == THERMAL_TRIP_CRITICAL) {
- ret = tz->ops->get_trip_temp(tz, count,
- &crit_temp);
- break;
- }
- }
-
- /*
- * Only allow emulating a temperature when the real temperature
- * is below the critical temperature so that the emulation code
- * cannot hide critical conditions.
- */
- if (!ret && *temp < crit_temp)
- *temp = tz->emul_temperature;
- }
-
- mutex_unlock(&tz->lock);
-exit:
- return ret;
-}
-EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
-
-void thermal_zone_set_trips(struct thermal_zone_device *tz)
-{
- int low = -INT_MAX;
- int high = INT_MAX;
- int trip_temp, hysteresis;
- int i, ret;
-
- mutex_lock(&tz->lock);
-
- if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
- goto exit;
-
- for (i = 0; i < tz->trips; i++) {
- int trip_low;
-
- tz->ops->get_trip_temp(tz, i, &trip_temp);
- tz->ops->get_trip_hyst(tz, i, &hysteresis);
-
- trip_low = trip_temp - hysteresis;
-
- if (trip_low < tz->temperature && trip_low > low)
- low = trip_low;
-
- if (trip_temp > tz->temperature && trip_temp < high)
- high = trip_temp;
- }
-
- /* No need to change trip points */
- if (tz->prev_low_trip == low && tz->prev_high_trip == high)
- goto exit;
-
- tz->prev_low_trip = low;
- tz->prev_high_trip = high;
-
- dev_dbg(&tz->device,
- "new temperature boundaries: %d < x < %d\n", low, high);
-
- /*
- * Set a temperature window. When this window is left the driver
- * must inform the thermal core via thermal_zone_device_update.
- */
- ret = tz->ops->set_trips(tz, low, high);
- if (ret)
- dev_err(&tz->device, "Failed to set trips: %d\n", ret);
-
-exit:
- mutex_unlock(&tz->lock);
-}
-EXPORT_SYMBOL_GPL(thermal_zone_set_trips);
-
static void update_temperature(struct thermal_zone_device *tz)
{
int temp, ret;
@@ -629,6 +427,24 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
+/**
+ * thermal_notify_framework - Sensor drivers use this API to notify framework
+ * @tz: thermal zone device
+ * @trip: indicates which trip point has been crossed
+ *
+ * This function handles the trip events from sensor drivers. It starts
+ * throttling the cooling devices according to the policy configured.
+ * For CRITICAL and HOT trip points, this notifies the respective drivers,
+ * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
+ * The throttling policy is based on the configured platform data; if no
+ * platform data is provided, this uses the step_wise throttling policy.
+ */
+void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
+{
+ handle_thermal_trip(tz, trip);
+}
+EXPORT_SYMBOL_GPL(thermal_notify_framework);
+
static void thermal_zone_device_check(struct work_struct *work)
{
struct thermal_zone_device *tz = container_of(work, struct
@@ -637,445 +453,12 @@ static void thermal_zone_device_check(struct work_struct *work)
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
-/* sys I/F for thermal zone */
-
-#define to_thermal_zone(_dev) \
- container_of(_dev, struct thermal_zone_device, device)
-
-static ssize_t
-type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
-
- return sprintf(buf, "%s\n", tz->type);
-}
-
-static ssize_t
-temp_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int temperature, ret;
-
- ret = thermal_zone_get_temp(tz, &temperature);
-
- if (ret)
- return ret;
-
- return sprintf(buf, "%d\n", temperature);
-}
-
-static ssize_t
-mode_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- enum thermal_device_mode mode;
- int result;
-
- if (!tz->ops->get_mode)
- return -EPERM;
-
- result = tz->ops->get_mode(tz, &mode);
- if (result)
- return result;
-
- return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
- : "disabled");
-}
-
-static ssize_t
-mode_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int result;
-
- if (!tz->ops->set_mode)
- return -EPERM;
-
- if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
- result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
- else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
- result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
- else
- result = -EINVAL;
-
- if (result)
- return result;
-
- return count;
-}
-
-static ssize_t
-trip_point_type_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- enum thermal_trip_type type;
- int trip, result;
-
- if (!tz->ops->get_trip_type)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
- return -EINVAL;
-
- result = tz->ops->get_trip_type(tz, trip, &type);
- if (result)
- return result;
-
- switch (type) {
- case THERMAL_TRIP_CRITICAL:
- return sprintf(buf, "critical\n");
- case THERMAL_TRIP_HOT:
- return sprintf(buf, "hot\n");
- case THERMAL_TRIP_PASSIVE:
- return sprintf(buf, "passive\n");
- case THERMAL_TRIP_ACTIVE:
- return sprintf(buf, "active\n");
- default:
- return sprintf(buf, "unknown\n");
- }
-}
-
-static ssize_t
-trip_point_temp_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- int temperature;
-
- if (!tz->ops->set_trip_temp)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
- return -EINVAL;
-
- if (kstrtoint(buf, 10, &temperature))
- return -EINVAL;
-
- ret = tz->ops->set_trip_temp(tz, trip, temperature);
- if (ret)
- return ret;
-
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
- return count;
-}
-
-static ssize_t
-trip_point_temp_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- int temperature;
-
- if (!tz->ops->get_trip_temp)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
- return -EINVAL;
-
- ret = tz->ops->get_trip_temp(tz, trip, &temperature);
-
- if (ret)
- return ret;
-
- return sprintf(buf, "%d\n", temperature);
-}
-
-static ssize_t
-trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- int temperature;
-
- if (!tz->ops->set_trip_hyst)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
- return -EINVAL;
-
- if (kstrtoint(buf, 10, &temperature))
- return -EINVAL;
-
- /*
- * We are not doing any check on the 'temperature' value
- * here. The driver implementing 'set_trip_hyst' has to
- * take care of this.
- */
- ret = tz->ops->set_trip_hyst(tz, trip, temperature);
-
- if (!ret)