pass: thermal: Add support of Thermal Monitor of each h/w resource 70/174370/7
authorChanwoo Choi <cw00.choi@samsung.com>
Thu, 22 Mar 2018 10:57:07 +0000 (19:57 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Fri, 6 Apr 2018 06:00:59 +0000 (15:00 +0900)
In order to use Thermal Monitor, each h/w resource (e.g. CPU/GPU) monitors
the thermal information with timer-based and uevent-based resource monitors.

If the monitored temperature is included in the range of defined
thermal scenario, it send the notification to Thermal Monitor module.
The pass-thermal.c is the developerment for each h/w resource.

Change-Id: I0dbf77202e1c3d7bc54803b064c9d29d687b661b
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
CMakeLists.txt
src/pass/pass-thermal.c [new file with mode: 0644]
src/pass/pass.c
src/pass/pass.h

index b57486a..6ed9f45 100644 (file)
@@ -72,6 +72,7 @@ SET(SRCS
        src/pass/pass-resmon.c
        src/pass/pass-resmon-source.c
        src/pass/pass-pmqos.c
+       src/pass/pass-thermal.c
        src/pmqos/pmqos.c
        src/pmqos/pmqos-parser.c
        src/thermal/thermal.c
diff --git a/src/pass/pass-thermal.c b/src/pass/pass-thermal.c
new file mode 100644 (file)
index 0000000..4de164b
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * PASS (Power Aware System Service) Thermal Monitor with RESMON
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <pass/log.h>
+#include <pass/hal/hal.h>
+#include <pass/device-notifier.h>
+
+#include "pass.h"
+#include "pass-resmon.h"
+
+#define DEFAULT_TEMPERATURE            (-1000)
+
+static int thermal_monitor_func(void *result, void *user_data)
+{
+       struct pass_resource *res = user_data;
+       struct resmon_result_src_thermal *thermal_result = result;
+       struct pass_thermal *thermal;
+       int timer_interval_of_scenario, timer_interval;
+       int curr_temp, prev_temp;
+       int temp;
+       int ret;
+       int i, scenario_idx;
+
+       if (!res || !thermal_result) {
+               _E("invalid parameter for thermal monitor\n");
+               return -EINVAL;
+       }
+
+       thermal = &res->thermal;
+       prev_temp = thermal->curr_temp;
+       curr_temp = thermal_result->temp;
+
+       if (prev_temp == curr_temp)
+               return 0;
+
+       scenario_idx = -1;
+       for (i = 0; i < thermal->num_scenarios; i++) {
+               temp = thermal->scenarios[i].thermal.temperature;
+
+               if (thermal->scenarios[i].state != PASS_ON)
+                       continue;
+
+               if (scenario_idx < 0 && curr_temp < temp)
+                       scenario_idx = i;
+               else if (temp <= curr_temp)
+                       scenario_idx = i;
+       }
+
+       /*
+        * If temperature is lower than defined temperature in configuration
+        * or if there are no scearnio with 'support=yes',
+        * just return without notification.
+        */
+       if (scenario_idx < 0)
+               return 0;
+
+       if (thermal->curr_scenario_idx == scenario_idx)
+               return 0;
+
+       /*
+        * Send notification with thermal scenario name according to
+        * measured temperature of each h/w resource.
+        */
+       device_notify(DEVICE_NOTIFIER_THERMAL,
+                               (void *)thermal->scenarios[scenario_idx].name);
+
+       _I("Monitor '%s' scenario for '%s' resource ('%d' degrees Celsius)\n",
+                               thermal->scenarios[scenario_idx].name,
+                               res->config_data.res_name, curr_temp);
+
+       /* Get the new timer interval of each scenario */
+       timer_interval_of_scenario
+               = thermal->scenarios[scenario_idx].thermal.timer_interval;
+       if (timer_interval_of_scenario > 0)
+               timer_interval = timer_interval_of_scenario;
+       else
+               timer_interval = res->thermal.timer_interval;
+
+       ret = pass_resmon_update_timer_interval(res, RESMON_SRC_THERMAL,
+                               timer_interval);
+       if (ret < 0) {
+               _W("failed to update interval of timer-based monitor " \
+                       "(res_name:%s, src_type: 0x%x)\n",
+                       res->config_data.res_name, RESMON_SRC_THERMAL);
+       }
+
+       thermal->curr_temp = curr_temp;
+       thermal->curr_scenario_idx = scenario_idx;
+
+       return 0;
+}
+
+int pass_thermal_init(struct pass_resource *res)
+{
+       int ret;
+
+       if (!res)
+               return -EINVAL;
+       if (res->thermal.state != PASS_ON)
+               return 0;
+
+       /*
+        * Register timer-based resource monitor to monitor thermal info.
+        * Have to do the first monitoring as soon as possible. Register
+        * timer-based resource monitor with 1000 millisecond and then
+        * update the timer interval with the required value
+        * after first monitoring is finished.
+        */
+       ret = pass_resmon_register_timer(res, RESMON_SRC_THERMAL,
+                       RESMON_TIMER_PERIODIC, 1000,
+                       thermal_monitor_func, res);
+       if (ret < 0) {
+               _E("failed to register timer-based monitor " \
+                       "(res_name:%s, src_type: 0x%x)\n",
+                       res->config_data.res_name, RESMON_SRC_THERMAL);
+               return -EINVAL;
+       }
+
+       /* Register uevent-based resource monitor to monitor thermal info. */
+       ret = pass_resmon_register_uevent(res, RESMON_SRC_THERMAL,
+                       thermal_monitor_func, res);
+       if (ret < 0) {
+               _E("failed to register uevent-based monitor " \
+                       "(res_name:%s, src_type: 0x%x)\n",
+                       res->config_data.res_name, RESMON_SRC_THERMAL);
+               goto err_timer;
+       }
+
+       /* Initialize the default scenario index */
+       res->thermal.curr_scenario_idx = -1;
+       res->thermal.curr_temp = DEFAULT_TEMPERATURE;
+
+       return 0;
+
+err_timer:
+       ret = pass_resmon_unregister_timer(res, RESMON_SRC_THERMAL);
+       if (ret < 0) {
+               _E("failed to unregister timer-based monitor " \
+                       "(res_name:%s, src_type: 0x%x)\n",
+                       res->config_data.res_name, RESMON_SRC_THERMAL);
+       }
+
+       return -EINVAL;
+}
+
+int pass_thermal_exit(struct pass_resource *res)
+{
+       int ret;
+
+       if (!res)
+               return -EINVAL;
+       if (res->thermal.state != PASS_ON)
+               return -EINVAL;
+
+       ret = pass_resmon_unregister_uevent(res, RESMON_SRC_THERMAL);
+       if (ret < 0) {
+               _E("failed to unregister uevent-based monitor " \
+                       "(res_name:%s, src_type: 0x%x)\n",
+                       res->config_data.res_name, RESMON_SRC_THERMAL);
+       }
+
+       ret = pass_resmon_unregister_timer(res, RESMON_SRC_THERMAL);
+       if (ret < 0) {
+               _E("failed to unregister timer-based monitor " \
+                       "(res_name:%s, src_type: 0x%x)\n",
+                       res->config_data.res_name, RESMON_SRC_THERMAL);
+       }
+
+       /* Initialize the default scenario index */
+       res->thermal.curr_scenario_idx = -1;
+       res->thermal.curr_temp = DEFAULT_TEMPERATURE;
+
+       return 0;
+}
index b599787..aa86b14 100644 (file)
@@ -44,7 +44,8 @@ static uint64 supported_module[] = {
                                        | PASS_MODULE_RESCON
                                        | PASS_MODULE_RESMON
                                        | PASS_MODULE_PMQOS
-                                       | PASS_MODULE_CPUHP,
+                                       | PASS_MODULE_CPUHP
+                                       | PASS_MODULE_THERMAL,
 
        [PASS_RESOURCE_BUS_ID]          = PASS_MODULE_PARSER
                                        | PASS_MODULE_RESCON
@@ -54,7 +55,8 @@ static uint64 supported_module[] = {
        [PASS_RESOURCE_GPU_ID]          = PASS_MODULE_PARSER
                                        | PASS_MODULE_RESCON
                                        | PASS_MODULE_RESMON
-                                       | PASS_MODULE_PMQOS,
+                                       | PASS_MODULE_PMQOS
+                                       | PASS_MODULE_THERMAL,
 
        [PASS_RESOURCE_MEMORY_ID]       = PASS_MODULE_PARSER
                                        | PASS_MODULE_RESCON
@@ -73,6 +75,8 @@ extern int pass_cpuhp_init(struct pass_resource *res);
 extern int pass_cpuhp_exit(struct pass_resource *res);
 extern int pass_pmqos_init(struct pass_resource *res);
 extern int pass_pmqos_exit(struct pass_resource *res);
+extern int pass_thermal_init(struct pass_resource *res);
+extern int pass_thermal_exit(struct pass_resource *res);
 
 static struct pass g_pass;
 static SystemPassCore *g_gdbus_instance = NULL;
@@ -207,8 +211,20 @@ static int pass_init_resource(struct pass_resource *res)
                }
        }
 
+       if (is_supported_module(res, PASS_MODULE_THERMAL)) {
+               ret = pass_thermal_init(res);
+               if (ret < 0) {
+                       _E("cannot initialize PASS Thermal Monitor");
+                       goto err_thermal;
+               }
+       }
+
        return 0;
 
+err_thermal:
+       if (is_supported_module(res, PASS_MODULE_PMQOS))
+               if (pass_pmqos_exit(res) < 0)
+                       _E("cannot exit PASS PMQoS");
 err_pmqos:
        if (is_supported_module(res, PASS_MODULE_CPUHP))
                if (pass_cpuhp_exit(res) < 0)
@@ -248,6 +264,14 @@ static int pass_exit_resource(struct pass_resource *res)
                }
        }
 
+       if (is_supported_module(res, PASS_MODULE_THERMAL)) {
+               ret = pass_thermal_exit(res);
+               if (ret < 0) {
+                       _E("cannot exit PASS Thermal Monitor");
+                       return ret;
+               }
+       }
+
        /*
         * Have to exit ResCon (Resource-Controller) and ResMon
         * (Resource Monitor) after called exit() function of modules.
index 55c147a..8a07cf8 100644 (file)
@@ -41,6 +41,7 @@ struct pass_cpuhp_governor;
  * PASS_MODULE_RESMON: Represents the Resource Controller module
  * PASS_MODULE_PMQOS: Represents the Scenario-based PMQoS module
  * PASS_MODULE_CPUHP: Represents the CPU Hotplug Manager module
+ * PASS_MODULE_THERMAL: Represents the Thermal Monitor module
  */
 enum pass_module_type {
        PASS_MODULE_UNKNOWN             = 0x0,
@@ -50,6 +51,7 @@ enum pass_module_type {
        PASS_MODULE_RESMON              = 0x4,
        PASS_MODULE_PMQOS               = 0x8,
        PASS_MODULE_CPUHP               = 0x10,
+       PASS_MODULE_THERMAL             = 0x20,
 };
 
 /*