thermal : Add throttle hotplug function.
authorPark Chungwoo <cww.park@samsung.com>
Tue, 15 Mar 2016 08:09:10 +0000 (17:09 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:09:16 +0000 (17:09 +0900)
Resolved migration conflicts from kernel 4.9 to 4.14.

Change-Id: I594d154e791f420a036731ddc3238b7ec6c49947
Signed-off-by: Park Chungwoo <cww.park@samsung.com>
drivers/thermal/of-thermal.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
include/linux/thermal.h

index 1fb527a169c3ab25d17ec7b32668a7770ba1d388..b5108cf614a99ce21d1774fd5497d6cd9f25ad1f 100644 (file)
@@ -112,6 +112,29 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,
        return data->ops->set_trips(data->sensor_data, low, high);
 }
 
+/**
+ * of_thermal_throttle_hotplug - function to throttle hotplug cpu core.
+ *
+ * @tz: pointer to a thermal zone
+ *
+ * This function call throttle_cpu_hotplug function in exynos thermal.
+ *
+ * Return: do not exist function callback, -EINVAL when data not available
+ */
+static int of_thermal_throttle_hotplug(struct thermal_zone_device *tz)
+{
+       struct __thermal_zone *data = tz->devdata;
+       int ret = 0;
+
+       if (!data->ops->throttle_cpu_hotplug)
+               return -EINVAL;
+
+       ret = data->ops->throttle_cpu_hotplug(data->sensor_data, tz->temperature);
+
+       return ret;
+}
+
+
 /**
  * of_thermal_get_ntrips - function to export number of available trip
  *                        points.
@@ -432,6 +455,7 @@ thermal_zone_of_add_sensor(struct device_node *zone,
        if (ops->set_emul_temp)
                tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 
+       tzd->ops->throttle_hotplug = of_thermal_throttle_hotplug;
        mutex_unlock(&tzd->lock);
 
        return tzd;
index 03988c90ceddf755dbedbe5c605c8e63d90a9627..764a475642f9cd9bb255f5f7c2723c975f8b2f39 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/cpufreq.h>
 #include <linux/suspend.h>
+#include <linux/pm_qos.h>
+#include <linux/threads.h>
+#include <linux/thermal.h>
+#include <soc/samsung/cpufreq.h>
 
 #include "exynos_tmu.h"
 #include "../thermal_core.h"
 #define MCELSIUS       1000
 
 static bool suspended;
+static bool is_cpu_hotplugged_out;
 static DEFINE_MUTEX (thermal_suspend_lock);
 
 /* list of multiple instance for each thermal sensor */
@@ -125,6 +130,10 @@ static LIST_HEAD(dtm_dev_list);
  */
 struct exynos_tmu_data {
        int id;
+       /* Throttle hotplug related variables */
+       bool hotplug_enable;
+       int hotplug_in_threshold;
+       int hotplug_out_threshold;
        struct exynos_tmu_platform_data *pdata;
        void __iomem *base;
        int irq;
@@ -653,6 +662,21 @@ static int exynos_map_dt_data(struct platform_device *pdev)
                return -EADDRNOTAVAIL;
        }
 
+       data->hotplug_enable = of_property_read_bool(pdev->dev.of_node,
+                                                       "hotplug_enable");
+       if (data->hotplug_enable) {
+               dev_info(&pdev->dev, "thermal zone use hotplug function \n");
+               of_property_read_u32(pdev->dev.of_node, "hotplug_in_threshold",
+                                       &data->hotplug_in_threshold);
+               if (!data->hotplug_in_threshold)
+                       dev_err(&pdev->dev, "No input hotplug_in_threshold \n");
+
+               of_property_read_u32(pdev->dev.of_node, "hotplug_out_threshold",
+                                       &data->hotplug_out_threshold);
+               if (!data->hotplug_out_threshold)
+                       dev_err(&pdev->dev, "No input hotplug_out_threshold \n");
+       }
+
        pdata = devm_kzalloc(&pdev->dev,
                             sizeof(struct exynos_tmu_platform_data),
                             GFP_KERNEL);
@@ -679,6 +703,48 @@ static int exynos_map_dt_data(struct platform_device *pdev)
        return 0;
 }
 
+struct pm_qos_request thermal_cpu_hotplug_request;
+static int exynos_throttle_cpu_hotplug(void *p, int temp)
+{
+       struct exynos_tmu_data *data = p;
+       struct cpufreq_cooling_device *cpufreq_cdev = (struct cpufreq_cooling_device *)data->cool_dev->devdata;
+       int ret = 0;
+
+       temp = temp / MCELSIUS;
+
+       if (is_cpu_hotplugged_out) {
+               if (temp < data->hotplug_in_threshold) {
+                       /*
+                        * If current temperature is lower than low threshold,
+                        * call cluster1_cores_hotplug(false) for hotplugged out cpus.
+                        */
+                       pm_qos_update_request(&thermal_cpu_hotplug_request,
+                                               NR_CPUS);
+                       is_cpu_hotplugged_out = false;
+                       cpufreq_cdev->cpufreq_state = 0;
+               }
+       } else {
+               if (temp >= data->hotplug_out_threshold) {
+                       /*
+                        * If current temperature is higher than high threshold,
+                        * call cluster1_cores_hotplug(true) to hold temperature down.
+                        */
+                       is_cpu_hotplugged_out = true;
+
+                       pm_qos_update_request(&thermal_cpu_hotplug_request,
+                                               NR_CLUST1_CPUS);
+               }
+       }
+
+       return ret;
+}
+
+static const struct thermal_zone_of_device_ops exynos_hotplug_sensor_ops = {
+       .get_temp = exynos_get_temp,
+       .set_emul_temp = exynos_tmu_set_emulation,
+       .throttle_cpu_hotplug = exynos_throttle_cpu_hotplug,
+};
+
 static const struct thermal_zone_of_device_ops exynos_sensor_ops = {
        .get_temp = exynos_get_temp,
        .set_emul_temp = exynos_tmu_set_emulation,
@@ -755,7 +821,14 @@ static int exynos_tmu_probe(struct platform_device *pdev)
         * data->tzd must be registered before calling exynos_tmu_initialize(),
         * requesting irq and calling exynos_tmu_control().
         */
+       if(data->hotplug_enable)
+               pm_qos_add_request(&thermal_cpu_hotplug_request,
+                                       PM_QOS_CPU_ONLINE_MAX,
+                                       PM_QOS_CPU_ONLINE_MAX_DEFAULT_VALUE);
+
        data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+                                                   data->hotplug_enable ?
+                                                   &exynos_hotplug_sensor_ops :
                                                    &exynos_sensor_ops);
        if (IS_ERR(data->tzd)) {
                ret = PTR_ERR(data->tzd);
index 2b1b0ba393a4b75b827fea732ea42f510563a29e..c4eca6f9355babbb332a331468e4d54219dda13d 100644 (file)
@@ -483,6 +483,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 
        for (count = 0; count < tz->trips; count++)
                handle_thermal_trip(tz, count);
+
+       if (tz->ops->throttle_hotplug)
+               tz->ops->throttle_hotplug(tz);
 }
 EXPORT_SYMBOL_GPL(thermal_zone_device_update);
 
index 905af30d494431c71fdb8895259b07e41bfc2dfa..a85b78ed4b6c8d6dd26531e3fc5a8c94cc53e0f8 100644 (file)
@@ -128,6 +128,7 @@ struct thermal_zone_device_ops {
                          enum thermal_trend *);
        int (*notify) (struct thermal_zone_device *, int,
                       enum thermal_trip_type);
+       int (*throttle_hotplug) (struct thermal_zone_device *);
 };
 
 struct thermal_cooling_device_ops {
@@ -371,6 +372,7 @@ struct thermal_zone_of_device_ops {
        int (*set_trips)(void *, int, int);
        int (*set_emul_temp)(void *, int);
        int (*set_trip_temp)(void *, int, int);
+       int (*throttle_cpu_hotplug)(void *, int temp);
 };
 
 /**