thermal: make THERMAL_HWMON implementation fully internal
THERMAL_HWMON is implemented inside the thermal_sys driver and has no effect on drivers implementing thermal zones, so they shouldn't see anything related to it in <linux/thermal.h>. Making the THERMAL_HWMON implementation fully internal has two advantages beyond the cleaner design: * This avoids rebuilding all thermal drivers if the THERMAL_HWMON implementation changes, or if CONFIG_THERMAL_HWMON gets enabled or disabled. * This avoids breaking the thermal kABI in these cases too, which should make distributions happy. The only drawback I can see is slightly higher memory fragmentation, as the number of kzalloc() calls will increase by one per thermal zone. But I doubt it will be a problem in practice, as I've never seen a system with more than two thermal zones. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Rene Herman <rene.herman@gmail.com> Acked-by: Guenter Roeck <guenter.roeck@ericsson.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
0d97d7a494
commit
31f5396ad3
|
@ -420,6 +420,29 @@ thermal_cooling_device_trip_point_show(struct device *dev,
|
||||||
|
|
||||||
/* hwmon sys I/F */
|
/* hwmon sys I/F */
|
||||||
#include <linux/hwmon.h>
|
#include <linux/hwmon.h>
|
||||||
|
|
||||||
|
/* thermal zone devices with the same type share one hwmon device */
|
||||||
|
struct thermal_hwmon_device {
|
||||||
|
char type[THERMAL_NAME_LENGTH];
|
||||||
|
struct device *device;
|
||||||
|
int count;
|
||||||
|
struct list_head tz_list;
|
||||||
|
struct list_head node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thermal_hwmon_attr {
|
||||||
|
struct device_attribute attr;
|
||||||
|
char name[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* one temperature input for each thermal zone */
|
||||||
|
struct thermal_hwmon_temp {
|
||||||
|
struct list_head hwmon_node;
|
||||||
|
struct thermal_zone_device *tz;
|
||||||
|
struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
|
||||||
|
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
|
||||||
|
};
|
||||||
|
|
||||||
static LIST_HEAD(thermal_hwmon_list);
|
static LIST_HEAD(thermal_hwmon_list);
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
@ -437,9 +460,10 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
int ret;
|
int ret;
|
||||||
struct thermal_hwmon_attr *hwmon_attr
|
struct thermal_hwmon_attr *hwmon_attr
|
||||||
= container_of(attr, struct thermal_hwmon_attr, attr);
|
= container_of(attr, struct thermal_hwmon_attr, attr);
|
||||||
struct thermal_zone_device *tz
|
struct thermal_hwmon_temp *temp
|
||||||
= container_of(hwmon_attr, struct thermal_zone_device,
|
= container_of(hwmon_attr, struct thermal_hwmon_temp,
|
||||||
temp_input);
|
temp_input);
|
||||||
|
struct thermal_zone_device *tz = temp->tz;
|
||||||
|
|
||||||
ret = tz->ops->get_temp(tz, &temperature);
|
ret = tz->ops->get_temp(tz, &temperature);
|
||||||
|
|
||||||
|
@ -455,9 +479,10 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct thermal_hwmon_attr *hwmon_attr
|
struct thermal_hwmon_attr *hwmon_attr
|
||||||
= container_of(attr, struct thermal_hwmon_attr, attr);
|
= container_of(attr, struct thermal_hwmon_attr, attr);
|
||||||
struct thermal_zone_device *tz
|
struct thermal_hwmon_temp *temp
|
||||||
= container_of(hwmon_attr, struct thermal_zone_device,
|
= container_of(hwmon_attr, struct thermal_hwmon_temp,
|
||||||
temp_crit);
|
temp_crit);
|
||||||
|
struct thermal_zone_device *tz = temp->tz;
|
||||||
long temperature;
|
long temperature;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -485,10 +510,29 @@ thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the temperature input matching a given thermal zone */
|
||||||
|
static struct thermal_hwmon_temp *
|
||||||
|
thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
|
||||||
|
const struct thermal_zone_device *tz)
|
||||||
|
{
|
||||||
|
struct thermal_hwmon_temp *temp;
|
||||||
|
|
||||||
|
mutex_lock(&thermal_list_lock);
|
||||||
|
list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
|
||||||
|
if (temp->tz == tz) {
|
||||||
|
mutex_unlock(&thermal_list_lock);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
mutex_unlock(&thermal_list_lock);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
|
thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
|
||||||
{
|
{
|
||||||
struct thermal_hwmon_device *hwmon;
|
struct thermal_hwmon_device *hwmon;
|
||||||
|
struct thermal_hwmon_temp *temp;
|
||||||
int new_hwmon_device = 1;
|
int new_hwmon_device = 1;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -515,30 +559,36 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
|
||||||
goto free_mem;
|
goto free_mem;
|
||||||
|
|
||||||
register_sys_interface:
|
register_sys_interface:
|
||||||
tz->hwmon = hwmon;
|
temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
|
||||||
|
if (!temp) {
|
||||||
|
result = -ENOMEM;
|
||||||
|
goto unregister_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp->tz = tz;
|
||||||
hwmon->count++;
|
hwmon->count++;
|
||||||
|
|
||||||
snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
|
snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH,
|
||||||
"temp%d_input", hwmon->count);
|
"temp%d_input", hwmon->count);
|
||||||
tz->temp_input.attr.attr.name = tz->temp_input.name;
|
temp->temp_input.attr.attr.name = temp->temp_input.name;
|
||||||
tz->temp_input.attr.attr.mode = 0444;
|
temp->temp_input.attr.attr.mode = 0444;
|
||||||
tz->temp_input.attr.show = temp_input_show;
|
temp->temp_input.attr.show = temp_input_show;
|
||||||
sysfs_attr_init(&tz->temp_input.attr.attr);
|
sysfs_attr_init(&temp->temp_input.attr.attr);
|
||||||
result = device_create_file(hwmon->device, &tz->temp_input.attr);
|
result = device_create_file(hwmon->device, &temp->temp_input.attr);
|
||||||
if (result)
|
if (result)
|
||||||
goto unregister_name;
|
goto free_temp_mem;
|
||||||
|
|
||||||
if (tz->ops->get_crit_temp) {
|
if (tz->ops->get_crit_temp) {
|
||||||
unsigned long temperature;
|
unsigned long temperature;
|
||||||
if (!tz->ops->get_crit_temp(tz, &temperature)) {
|
if (!tz->ops->get_crit_temp(tz, &temperature)) {
|
||||||
snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
|
snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH,
|
||||||
"temp%d_crit", hwmon->count);
|
"temp%d_crit", hwmon->count);
|
||||||
tz->temp_crit.attr.attr.name = tz->temp_crit.name;
|
temp->temp_crit.attr.attr.name = temp->temp_crit.name;
|
||||||
tz->temp_crit.attr.attr.mode = 0444;
|
temp->temp_crit.attr.attr.mode = 0444;
|
||||||
tz->temp_crit.attr.show = temp_crit_show;
|
temp->temp_crit.attr.show = temp_crit_show;
|
||||||
sysfs_attr_init(&tz->temp_crit.attr.attr);
|
sysfs_attr_init(&temp->temp_crit.attr.attr);
|
||||||
result = device_create_file(hwmon->device,
|
result = device_create_file(hwmon->device,
|
||||||
&tz->temp_crit.attr);
|
&temp->temp_crit.attr);
|
||||||
if (result)
|
if (result)
|
||||||
goto unregister_input;
|
goto unregister_input;
|
||||||
}
|
}
|
||||||
|
@ -547,13 +597,15 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
|
||||||
mutex_lock(&thermal_list_lock);
|
mutex_lock(&thermal_list_lock);
|
||||||
if (new_hwmon_device)
|
if (new_hwmon_device)
|
||||||
list_add_tail(&hwmon->node, &thermal_hwmon_list);
|
list_add_tail(&hwmon->node, &thermal_hwmon_list);
|
||||||
list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
|
list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
|
||||||
mutex_unlock(&thermal_list_lock);
|
mutex_unlock(&thermal_list_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unregister_input:
|
unregister_input:
|
||||||
device_remove_file(hwmon->device, &tz->temp_input.attr);
|
device_remove_file(hwmon->device, &temp->temp_input.attr);
|
||||||
|
free_temp_mem:
|
||||||
|
kfree(temp);
|
||||||
unregister_name:
|
unregister_name:
|
||||||
if (new_hwmon_device) {
|
if (new_hwmon_device) {
|
||||||
device_remove_file(hwmon->device, &dev_attr_name);
|
device_remove_file(hwmon->device, &dev_attr_name);
|
||||||
|
@ -569,15 +621,30 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
|
||||||
static void
|
static void
|
||||||
thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
|
thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
|
||||||
{
|
{
|
||||||
struct thermal_hwmon_device *hwmon = tz->hwmon;
|
struct thermal_hwmon_device *hwmon;
|
||||||
|
struct thermal_hwmon_temp *temp;
|
||||||
|
|
||||||
tz->hwmon = NULL;
|
hwmon = thermal_hwmon_lookup_by_type(tz);
|
||||||
device_remove_file(hwmon->device, &tz->temp_input.attr);
|
if (unlikely(!hwmon)) {
|
||||||
|
/* Should never happen... */
|
||||||
|
dev_dbg(&tz->device, "hwmon device lookup failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = thermal_hwmon_lookup_temp(hwmon, tz);
|
||||||
|
if (unlikely(!temp)) {
|
||||||
|
/* Should never happen... */
|
||||||
|
dev_dbg(&tz->device, "temperature input lookup failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_remove_file(hwmon->device, &temp->temp_input.attr);
|
||||||
if (tz->ops->get_crit_temp)
|
if (tz->ops->get_crit_temp)
|
||||||
device_remove_file(hwmon->device, &tz->temp_crit.attr);
|
device_remove_file(hwmon->device, &temp->temp_crit.attr);
|
||||||
|
|
||||||
mutex_lock(&thermal_list_lock);
|
mutex_lock(&thermal_list_lock);
|
||||||
list_del(&tz->hwmon_node);
|
list_del(&temp->hwmon_node);
|
||||||
|
kfree(temp);
|
||||||
if (!list_empty(&hwmon->tz_list)) {
|
if (!list_empty(&hwmon->tz_list)) {
|
||||||
mutex_unlock(&thermal_list_lock);
|
mutex_unlock(&thermal_list_lock);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -85,22 +85,6 @@ struct thermal_cooling_device {
|
||||||
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
|
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
|
||||||
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
|
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
|
||||||
|
|
||||||
#if defined(CONFIG_THERMAL_HWMON)
|
|
||||||
/* thermal zone devices with the same type share one hwmon device */
|
|
||||||
struct thermal_hwmon_device {
|
|
||||||
char type[THERMAL_NAME_LENGTH];
|
|
||||||
struct device *device;
|
|
||||||
int count;
|
|
||||||
struct list_head tz_list;
|
|
||||||
struct list_head node;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct thermal_hwmon_attr {
|
|
||||||
struct device_attribute attr;
|
|
||||||
char name[16];
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct thermal_zone_device {
|
struct thermal_zone_device {
|
||||||
int id;
|
int id;
|
||||||
char type[THERMAL_NAME_LENGTH];
|
char type[THERMAL_NAME_LENGTH];
|
||||||
|
@ -120,12 +104,6 @@ struct thermal_zone_device {
|
||||||
struct mutex lock; /* protect cooling devices list */
|
struct mutex lock; /* protect cooling devices list */
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct delayed_work poll_queue;
|
struct delayed_work poll_queue;
|
||||||
#if defined(CONFIG_THERMAL_HWMON)
|
|
||||||
struct list_head hwmon_node;
|
|
||||||
struct thermal_hwmon_device *hwmon;
|
|
||||||
struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
|
|
||||||
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
/* Adding event notification support elements */
|
/* Adding event notification support elements */
|
||||||
#define THERMAL_GENL_FAMILY_NAME "thermal_event"
|
#define THERMAL_GENL_FAMILY_NAME "thermal_event"
|
||||||
|
|
Loading…
Reference in New Issue