thermal: add containers with thermal zones
authorLukasz Luba <l.luba@partner.samsung.com>
Tue, 14 Aug 2018 13:04:20 +0000 (15:04 +0200)
committerLukasz Luba <l.luba@partner.samsung.com>
Fri, 17 May 2019 07:15:36 +0000 (09:15 +0200)
This patch adds a new concept of a container thermal zone,
which agregates subzones. There is only one level allowed.
It relays on virtual temperature sensor which calculates
the temp based on real sensors from subzones.

Signed-off-by: Lukasz Luba <l.luba@partner.samsung.com>
drivers/thermal/of-thermal.c
drivers/thermal/thermal_core.h
include/linux/thermal.h

index 4f28165592056d5ec90309c5bff737f5ba66ea0b..1825d30e9b0b410b7232642fa8918fa88a5d3ec5 100644 (file)
@@ -801,7 +801,7 @@ static int thermal_of_populate_trip(struct device_node *np,
  * check the return value with help of IS_ERR() helper.
  */
 static struct __thermal_zone
-__init *thermal_of_build_thermal_zone(struct device_node *np)
+__init *thermal_of_build_thermal_zone(struct device_node *np, bool container)
 {
        struct device_node *child = NULL, *gchild;
        struct __thermal_zone *tz;
@@ -813,6 +813,15 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
                return ERR_PTR(-EINVAL);
        }
 
+       /*
+        * Make sure we are populating the right zone type in the
+        * right phase
+        */
+       if (of_property_read_bool(np, "container") ^ container) {
+               return ERR_PTR(-EAGAIN);
+       }
+
+
        tz = kzalloc(sizeof(*tz), GFP_KERNEL);
        if (!tz)
                return ERR_PTR(-ENOMEM);
@@ -931,6 +940,69 @@ static inline void of_thermal_free_zone(struct __thermal_zone *tz)
        kfree(tz);
 }
 
+static int thermal_add_subzone(struct thermal_zone_device *container,
+                              struct thermal_zone_device *zone,
+                              u32 capacitance)
+{
+       if (IS_ERR_OR_NULL(container) || IS_ERR_OR_NULL(zone))
+               return -EINVAL;
+
+       mutex_lock(&zone->lock);
+       zone->capacitance = capacitance;
+       mutex_unlock(&zone->lock);
+
+       mutex_lock(&container->lock);
+       list_add_tail(&zone->subzones, &container->subzones);
+       mutex_unlock(&container->lock);
+
+       return 0;
+}
+
+static int thermal_build_subzones(struct thermal_zone_device *zone,
+                                 struct device_node *np)
+{
+       int i = 0;
+       int ret = 0;
+
+       INIT_LIST_HEAD(&zone->subzones);
+
+       for ( ;; i++) {
+               struct thermal_zone_device *tz;
+               struct of_phandle_args zone_specs;
+               struct device_node *child;
+               u32 capacitance;
+
+               ret = of_parse_phandle_with_fixed_args(np, "subzones", 1, i,
+                                                &zone_specs);
+               if (ret) {
+                       of_node_put(zone_specs.np);
+                       break;
+               }
+
+
+               tz = thermal_zone_get_zone_by_name(zone_specs.np->name);
+               if (IS_ERR_OR_NULL(tz)) {
+                       pr_warn("Parsing thermal subzone %s failed %d\n",
+                               of_node_full_name(zone_specs.np), ret);
+                       of_node_put(zone_specs.np);
+                       continue;
+               }
+
+               if (zone_specs.args_count == 1)
+                       capacitance = zone_specs.args[0];
+               else
+                       capacitance = THERMAL_SUBZONE_DEFAULT_CAPACITANCE;
+
+
+               ret = thermal_add_subzone(zone, tz, capacitance);
+
+               of_node_put(zone_specs.np);
+
+       }
+
+       return ret;
+}
+
 /**
  * of_parse_thermal_zones - parse device tree thermal data
  *
@@ -943,11 +1015,12 @@ static inline void of_thermal_free_zone(struct __thermal_zone *tz)
  * Return: 0 on success, proper error code otherwise
  *
  */
-int __init of_parse_thermal_zones(void)
+int __init of_parse_thermal_zones_containers(bool container)
 {
        struct device_node *np, *child;
        struct __thermal_zone *tz;
        struct thermal_zone_device_ops *ops;
+       int ret;
 
        np = of_find_node_by_name(NULL, "thermal-zones");
        if (!np) {
@@ -961,11 +1034,12 @@ int __init of_parse_thermal_zones(void)
                int i, mask = 0;
                u32 prop;
 
-               tz = thermal_of_build_thermal_zone(child);
+               tz = thermal_of_build_thermal_zone(child, container);
                if (IS_ERR(tz)) {
-                       pr_err("failed to build thermal zone %s: %ld\n",
-                              child->name,
-                              PTR_ERR(tz));
+                       if (tz != ERR_PTR(-EAGAIN))
+                               pr_err("failed to build thermal zone %s: %ld\n",
+                                      child->name,
+                                      PTR_ERR(tz));
                        continue;
                }
 
@@ -1005,7 +1079,13 @@ int __init of_parse_thermal_zones(void)
                        of_thermal_free_zone(tz);
                        /* attempting to build remaining zones still */
                }
+
+               zone->container = container;
+               if (container) {
+                       ret = thermal_build_subzones(zone, child);
+               }
        }
+
        of_node_put(np);
 
        return 0;
@@ -1021,6 +1101,18 @@ exit_free:
        return -ENOMEM;
 }
 
+
+int __init of_parse_thermal_zones(void)
+{
+       int ret;
+
+       /* First parse normal zones, then containers */
+       ret = of_parse_thermal_zones_containers(false);
+       if (ret)
+               return ret;
+       return of_parse_thermal_zones_containers(true);
+}
+
 /**
  * of_thermal_destroy_zones - remove all zones parsed and allocated resources
  *
index f6ccd8fc2ba520beeadf4d7c545db75b2f5b015f..66527810a06c5c5442267bde71c0079312cab927 100644 (file)
@@ -14,6 +14,7 @@
 
 /* Initial state of a cooling device during binding */
 #define THERMAL_NO_TARGET -1UL
+#define THERMAL_SUBZONE_DEFAULT_CAPACITANCE 1
 
 /*
  * This structure is used to describe the behavior of
index 6c944ab78d176ffb3eb2bfc62c0eb27720eefb88..0b47cb72b96e8f5ea9f48f2b128f89ee607b1107 100644 (file)
@@ -218,6 +218,9 @@ struct thermal_zone_device {
        struct mutex lock;
        struct list_head node;
        struct delayed_work poll_queue;
+       bool container;
+       struct list_head subzones;
+       u32 capacitance;
        enum thermal_notify_event notify_event;
 };