--- /dev/null
+/*
+ * 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;
+}
| 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
[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
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;
}
}
+ 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)
}
}
+ 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.