thermal: export weight to sysfs
authorJavi Merino <javi.merino@arm.com>
Wed, 18 Feb 2015 16:04:24 +0000 (16:04 +0000)
committerEduardo Valentin <edubezval@gmail.com>
Tue, 5 May 2015 04:27:51 +0000 (21:27 -0700)
It's useful to have access to the weights for the cooling devices for
thermal zones and change them if needed.  Export them to sysfs.

Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
Signed-off-by: Javi Merino <javi.merino@arm.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
Documentation/thermal/sysfs-api.txt
drivers/thermal/thermal_core.c
drivers/thermal/thermal_core.h

index 7ec632ed976911d09bd564ddfbde51acafb2f6ee..3625453ceef6e406ae0edc0e84f28adcdb0fcf8f 100644 (file)
@@ -194,6 +194,8 @@ thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
 /sys/class/thermal/thermal_zone[0-*]:
     |---cdev[0-*]:             [0-*]th cooling device in current thermal zone
     |---cdev[0-*]_trip_point:  Trip point that cdev[0-*] is associated with
+    |---cdev[0-*]_weight:       Influence of the cooling device in
+                                this thermal zone
 
 Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
 the generic thermal driver also creates a hwmon sysfs I/F for each _type_
@@ -267,6 +269,14 @@ cdev[0-*]_trip_point
        point.
        RO, Optional
 
+cdev[0-*]_weight
+        The influence of cdev[0-*] in this thermal zone. This value
+        is relative to the rest of cooling devices in the thermal
+        zone. For example, if a cooling device has a weight double
+        than that of other, it's twice as effective in cooling the
+        thermal zone.
+        RW, Optional
+
 passive
        Attribute is only present for zones in which the passive cooling
        policy is not supported by native thermal driver. Default is zero
@@ -320,7 +330,8 @@ passive, active. If an ACPI thermal zone supports critical, passive,
 active[0] and active[1] at the same time, it may register itself as a
 thermal_zone_device (thermal_zone1) with 4 trip points in all.
 It has one processor and one fan, which are both registered as
-thermal_cooling_device.
+thermal_cooling_device. Both are considered to have the same
+effectiveness in cooling the thermal zone.
 
 If the processor is listed in _PSL method, and the fan is listed in _AL0
 method, the sys I/F structure will be built like this:
@@ -342,8 +353,10 @@ method, the sys I/F structure will be built like this:
     |---trip_point_3_type:     active1
     |---cdev0:                 --->/sys/class/thermal/cooling_device0
     |---cdev0_trip_point:      1       /* cdev0 can be used for passive */
+    |---cdev0_weight:           1024
     |---cdev1:                 --->/sys/class/thermal/cooling_device3
     |---cdev1_trip_point:      2       /* cdev1 can be used for active[0]*/
+    |---cdev1_weight:           1024
 
 |cooling_device0:
     |---type:                  Processor
index a6cb9b78b6293bc7725e5859571d5528c3a7ef97..605d6919c1b63a369e940055aa86f2a28883aed7 100644 (file)
@@ -922,6 +922,34 @@ static const struct attribute_group *cooling_device_attr_groups[] = {
        NULL,
 };
 
+static ssize_t
+thermal_cooling_device_weight_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct thermal_instance *instance;
+
+       instance = container_of(attr, struct thermal_instance, weight_attr);
+
+       return sprintf(buf, "%d\n", instance->weight);
+}
+
+static ssize_t
+thermal_cooling_device_weight_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct thermal_instance *instance;
+       int ret, weight;
+
+       ret = kstrtoint(buf, 0, &weight);
+       if (ret)
+               return ret;
+
+       instance = container_of(attr, struct thermal_instance, weight_attr);
+       instance->weight = weight;
+
+       return count;
+}
 /* Device management */
 
 /**
@@ -1016,6 +1044,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        if (result)
                goto remove_symbol_link;
 
+       sprintf(dev->weight_attr_name, "cdev%d_weight", dev->id);
+       sysfs_attr_init(&dev->weight_attr.attr);
+       dev->weight_attr.attr.name = dev->weight_attr_name;
+       dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO;
+       dev->weight_attr.show = thermal_cooling_device_weight_show;
+       dev->weight_attr.store = thermal_cooling_device_weight_store;
+       result = device_create_file(&tz->device, &dev->weight_attr);
+       if (result)
+               goto remove_trip_file;
+
        mutex_lock(&tz->lock);
        mutex_lock(&cdev->lock);
        list_for_each_entry(pos, &tz->thermal_instances, tz_node)
@@ -1033,6 +1071,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        if (!result)
                return 0;
 
+       device_remove_file(&tz->device, &dev->weight_attr);
+remove_trip_file:
        device_remove_file(&tz->device, &dev->attr);
 remove_symbol_link:
        sysfs_remove_link(&tz->device.kobj, dev->name);
index 7a465e9d456c84d7e1734379759025f271dd54b9..faebe881f062339ada072627ce56c98adc187f35 100644 (file)
@@ -46,6 +46,8 @@ struct thermal_instance {
        unsigned long target;   /* expected cooling state */
        char attr_name[THERMAL_NAME_LENGTH];
        struct device_attribute attr;
+       char weight_attr_name[THERMAL_NAME_LENGTH];
+       struct device_attribute weight_attr;
        struct list_head tz_node; /* node in tz->thermal_instances */
        struct list_head cdev_node; /* node in cdev->thermal_instances */
        unsigned int weight; /* The weight of the cooling device */