From 8ab3e6a08a98f7ff18c6814065eb30ba2e000233 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 2 Jan 2013 15:29:39 +0000 Subject: thermal: Use thermal zone device id in netlink messages This patch changes the function thermal_generate_netlink_event to receive a thermal zone device instead of a originator id. This way, the messages will always be bound to a thermal zone. Signed-off-by: Eduardo Valentin Reviewed-by: Durgadoss R Signed-off-by: Zhang Rui --- drivers/thermal/thermal_sys.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 8c8ce806180f..d85f51f433be 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -1711,7 +1711,8 @@ static struct genl_multicast_group thermal_event_mcgrp = { .name = THERMAL_GENL_MCAST_GROUP_NAME, }; -int thermal_generate_netlink_event(u32 orig, enum events event) +int thermal_generate_netlink_event(struct thermal_zone_device *tz, + enum events event) { struct sk_buff *skb; struct nlattr *attr; @@ -1721,6 +1722,9 @@ int thermal_generate_netlink_event(u32 orig, enum events event) int result; static unsigned int thermal_event_seqnum; + if (!tz) + return -EINVAL; + /* allocate memory */ size = nla_total_size(sizeof(struct thermal_genl_event)) + nla_total_size(0); @@ -1755,7 +1759,7 @@ int thermal_generate_netlink_event(u32 orig, enum events event) memset(thermal_event, 0, sizeof(struct thermal_genl_event)); - thermal_event->orig = orig; + thermal_event->orig = tz->id; thermal_event->event = event; /* send multicast genetlink message */ -- cgit v1.2.3 From ba38bb8c72fc259a8e3f2f1feb5761ae6f5858f0 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 2 Jan 2013 15:29:40 +0000 Subject: thermal: remove unnecessary include No need for spinlocks in this file, then removing its header. Signed-off-by: Eduardo Valentin Reviewed-by: Durgadoss R Signed-off-by: Zhang Rui --- drivers/thermal/thermal_sys.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index d85f51f433be..70ce100d34af 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 923e0b1e8dbe0939d9fc41c226dfc5d53884d8c6 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 2 Jan 2013 15:29:41 +0000 Subject: thermal: cleanup: use dev_* helper functions Change the logging messages to used dev_* helper functions. Signed-off-by: Eduardo Valentin Reviewed-by: Durgadoss R Signed-off-by: Zhang Rui --- drivers/thermal/thermal_sys.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 70ce100d34af..fba27c36d707 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -354,8 +354,9 @@ static void handle_critical_trips(struct thermal_zone_device *tz, tz->ops->notify(tz, trip, trip_type); if (trip_type == THERMAL_TRIP_CRITICAL) { - pr_emerg("Critical temperature reached(%d C),shutting down\n", - tz->temperature / 1000); + dev_emerg(&tz->device, + "critical temperature reached(%d C),shutting down\n", + tz->temperature / 1000); orderly_poweroff(true); } } @@ -386,7 +387,8 @@ static void update_temperature(struct thermal_zone_device *tz) ret = tz->ops->get_temp(tz, &temp); if (ret) { - pr_warn("failed to read out thermal zone %d\n", tz->id); + dev_warn(&tz->device, "failed to read out thermal zone %d\n", + tz->id); goto exit; } @@ -1770,7 +1772,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz, result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC); if (result) - pr_info("failed to send netlink event:%d\n", result); + dev_err(&tz->device, "Failed to send netlink event:%d", result); return result; } -- cgit v1.2.3 From 6b2aa51d698492e8dc0a0ce6ce5b3193ccaec269 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 2 Jan 2013 15:29:42 +0000 Subject: thermal: check for invalid trip setup when registering thermal device This patch adds an extra check in the data structure while registering a thermal device. The check is to avoid registering zones with a number of trips greater than zero, but with no .get_trip_temp nor .get_trip_type callbacks. Receiving such data structure may end in wrong data access. Signed-off-by: Eduardo Valentin Reviewed-by: Durgadoss R Signed-off-by: Zhang Rui --- drivers/thermal/thermal_sys.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index fba27c36d707..0a1bf6b032ea 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -1530,6 +1530,9 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, if (!ops || !ops->get_temp) return ERR_PTR(-EINVAL); + if (trips > 0 && !ops->get_trip_type) + return ERR_PTR(-EINVAL); + tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); if (!tz) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From e6e238c38bd4d42d5e2cddb2165e1a46e0fb1200 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Mon, 4 Feb 2013 00:30:15 +0000 Subject: thermal: sysfs: Add a new sysfs node emul_temp for thermal emulation This patch adds support to set the emulated temperature method in thermal zone (sensor). After setting this feature thermal zone may report this temperature and not the actual temperature. The emulation implementation may be based on sensor capability through platform specific handler or pure software emulation if no platform handler defined. This is useful in debugging different temperature threshold and its associated cooling action. Critical threshold's cannot be emulated. Writing 0 on this node should disable emulation. Signed-off-by: Amit Daniel Kachhap Acked-by: Kukjin Kim Signed-off-by: Zhang Rui --- Documentation/thermal/sysfs-api.txt | 13 ++++++ drivers/thermal/Kconfig | 8 ++++ drivers/thermal/thermal_sys.c | 79 +++++++++++++++++++++++++++++++------ include/linux/thermal.h | 2 + 4 files changed, 91 insertions(+), 11 deletions(-) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index 526d4b90d6c1..6859661c9d31 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt @@ -55,6 +55,8 @@ temperature) and throttle appropriate devices. .get_trip_type: get the type of certain trip point. .get_trip_temp: get the temperature above which the certain trip point will be fired. + .set_emul_temp: set the emulation temperature which helps in debugging + different threshold temperature points. 1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) @@ -153,6 +155,7 @@ Thermal zone device sys I/F, created once it's registered: |---trip_point_[0-*]_temp: Trip point temperature |---trip_point_[0-*]_type: Trip point type |---trip_point_[0-*]_hyst: Hysteresis value for this trip point + |---emul_temp: Emulated temperature set node Thermal cooling device sys I/F, created once it's registered: /sys/class/thermal/cooling_device[0-*]: @@ -252,6 +255,16 @@ passive Valid values: 0 (disabled) or greater than 1000 RW, Optional +emul_temp + Interface to set the emulated temperature method in thermal zone + (sensor). After setting this temperature, the thermal zone may pass + this temperature to platform emulation function if registered or + cache it locally. This is useful in debugging different temperature + threshold and its associated cooling action. This is write only node + and writing 0 on this node should disable emulation. + Unit: millidegree Celsius + WO, Optional + ***************************** * Cooling device attributes * ***************************** diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index faf38c522fa8..e4cf7fbc3a59 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -78,6 +78,14 @@ config CPU_THERMAL and not the ACPI interface. If you want this support, you should say Y here. +config THERMAL_EMULATION + bool "Thermal emulation mode support" + help + Enable this option to make a emul_temp sysfs node in thermal zone + directory to support temperature emulation. With emulation sysfs node, + user can manually input temperature and test the different trip + threshold behaviour for simulation purpose. + config SPEAR_THERMAL bool "SPEAr thermal sensor driver" depends on PLAT_SPEAR diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 0a1bf6b032ea..0675687c6de8 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -378,24 +378,54 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) monitor_thermal_zone(tz); } +static int thermal_zone_get_temp(struct thermal_zone_device *tz, + unsigned long *temp) +{ + int ret = 0, count; + unsigned long crit_temp = -1UL; + enum thermal_trip_type type; + + mutex_lock(&tz->lock); + + ret = tz->ops->get_temp(tz, temp); +#ifdef CONFIG_THERMAL_EMULATION + if (!tz->emul_temperature) + goto skip_emul; + + 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; + } + } + + if (ret) + goto skip_emul; + + if (*temp < crit_temp) + *temp = tz->emul_temperature; +skip_emul: +#endif + mutex_unlock(&tz->lock); + return ret; +} + static void update_temperature(struct thermal_zone_device *tz) { long temp; int ret; - mutex_lock(&tz->lock); - - ret = tz->ops->get_temp(tz, &temp); + ret = thermal_zone_get_temp(tz, &temp); if (ret) { dev_warn(&tz->device, "failed to read out thermal zone %d\n", tz->id); - goto exit; + return; } + mutex_lock(&tz->lock); tz->last_temperature = tz->temperature; tz->temperature = temp; - -exit: mutex_unlock(&tz->lock); } @@ -438,10 +468,7 @@ temp_show(struct device *dev, struct device_attribute *attr, char *buf) long temperature; int ret; - if (!tz->ops->get_temp) - return -EPERM; - - ret = tz->ops->get_temp(tz, &temperature); + ret = thermal_zone_get_temp(tz, &temperature); if (ret) return ret; @@ -701,6 +728,31 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf) return sprintf(buf, "%s\n", tz->governor->name); } +#ifdef CONFIG_THERMAL_EMULATION +static ssize_t +emul_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 ret = 0; + unsigned long temperature; + + if (kstrtoul(buf, 10, &temperature)) + return -EINVAL; + + if (!tz->ops->set_emul_temp) { + mutex_lock(&tz->lock); + tz->emul_temperature = temperature; + mutex_unlock(&tz->lock); + } else { + ret = tz->ops->set_emul_temp(tz, temperature); + } + + return ret ? ret : count; +} +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store); +#endif/*CONFIG_THERMAL_EMULATION*/ + static DEVICE_ATTR(type, 0444, type_show, NULL); static DEVICE_ATTR(temp, 0444, temp_show, NULL); static DEVICE_ATTR(mode, 0644, mode_show, mode_store); @@ -843,7 +895,7 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) temp_input); struct thermal_zone_device *tz = temp->tz; - ret = tz->ops->get_temp(tz, &temperature); + ret = thermal_zone_get_temp(tz, &temperature); if (ret) return ret; @@ -1596,6 +1648,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, goto unregister; } +#ifdef CONFIG_THERMAL_EMULATION + result = device_create_file(&tz->device, &dev_attr_emul_temp); + if (result) + goto unregister; +#endif /* Create policy attribute */ result = device_create_file(&tz->device, &dev_attr_policy); if (result) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 9b78f8c6f773..f0bd7f90a90d 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -123,6 +123,7 @@ struct thermal_zone_device_ops { int (*set_trip_hyst) (struct thermal_zone_device *, int, unsigned long); int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *); + int (*set_emul_temp) (struct thermal_zone_device *, unsigned long); int (*get_trend) (struct thermal_zone_device *, int, enum thermal_trend *); int (*notify) (struct thermal_zone_device *, int, @@ -165,6 +166,7 @@ struct thermal_zone_device { int polling_delay; int temperature; int last_temperature; + int emul_temperature; int passive; unsigned int forced_passive; const struct thermal_zone_device_ops *ops; -- cgit v1.2.3 From 5e20b2e51dd13c569ea1ff65c2a57d00a84a81b0 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 6 Feb 2013 14:02:12 +0800 Subject: Thermal: fix a build warning when CONFIG_THERMAL_EMULATION cleared Signed-off-by: Zhang Rui --- drivers/thermal/thermal_sys.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 0675687c6de8..6472e7e9f969 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -381,9 +381,12 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) static int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp) { - int ret = 0, count; + int ret = 0; +#ifdef CONFIG_THERMAL_EMULATION + int count; unsigned long crit_temp = -1UL; enum thermal_trip_type type; +#endif mutex_lock(&tz->lock); -- cgit v1.2.3 From da28d966f6aa942ae836d09729f76a1647932309 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 12 Feb 2013 19:39:44 +0000 Subject: thermal: return an error on failure to register thermal class The return code from the registration of the thermal class is used to unallocate resources, but this failure isn't passed back to the caller of thermal_init. Return this failure back to the caller. This bug was introduced in changeset 4cb18728 which overwrote the return code when the variable was re-used to catch the return code of the registration of the genetlink thermal socket family. Signed-off-by: Richard Guy Briggs Signed-off-by: Zhang Rui --- drivers/thermal/thermal_sys.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/thermal/thermal_sys.c') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 6472e7e9f969..1a19a2f4ba27 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -1875,6 +1875,7 @@ static int __init thermal_init(void) idr_destroy(&thermal_cdev_idr); mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); + return result; } result = genetlink_init(); return result; -- cgit v1.2.3