--- /dev/null
+/*
+ * PASS (Power Aware System Service) Resource Monitor
+ *
+ * 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.h"
+#include "pass-hal.h"
+#include "pass-resmon.h"
+#include "pass-resmon-internal.h"
+
+uint64 available_resmon_timer[] = {
+ [PASS_RESOURCE_UNKNOWN] = 0,
+ [PASS_RESOURCE_CPU_ID] = RESMON_SRC_THERMAL
+ | RESMON_SRC_CPUHP,
+ [PASS_RESOURCE_BUS_ID] = 0,
+ [PASS_RESOURCE_GPU_ID] = RESMON_SRC_THERMAL,
+ [PASS_RESOURCE_MEMORY_ID] = 0,
+ [PASS_RESOURCE_NONSTANDARD_ID] = 0
+};
+
+static bool resmon_is_supported(unsigned int res_type,
+ enum resmon_src_type src_type)
+{
+ return !!(available_resmon_timer[res_type] & src_type);
+}
+
+static bool resmon_is_created(struct pass_resmon *resmon,
+ enum resmon_src_type src_type)
+{
+ return !!(resmon->timer_state & src_type);
+}
+
+static gint __compare_monitor_type(gconstpointer data, gconstpointer input)
+{
+ struct resmon *monitor = (struct resmon *)data;
+ enum resmon_src_type *src_type = (enum resmon_src_type *)input;
+
+ if (monitor->src_type == *src_type)
+ return 0;
+ return -1;
+}
+
+static struct resmon *resmon_find_monitor(struct pass_resmon *resmon,
+ enum resmon_src_type src_type)
+{
+ GList *node = g_list_find_custom(resmon->timer_list, &src_type,
+ __compare_monitor_type);
+ if (!node)
+ return NULL;
+ return (struct resmon *)node->data;
+}
+
+static gboolean resmon_timer_func(gpointer data);
+static int resmon_timer_add(struct resmon *monitor, unsigned int interval)
+{
+ struct pass_resmon *resmon = monitor->resmon;
+ int ret;
+
+ /* Add new timer-based resmon to timer_list if it's not created */
+ if (!resmon_is_created(resmon, monitor->src_type)) {
+ resmon->timer_list =
+ g_list_append(resmon->timer_list,
+ (gpointer)monitor);
+ resmon->timer_state |= monitor->src_type;
+
+ if (monitor->ops && monitor->ops->init) {
+ ret = monitor->ops->init(monitor);
+ if (ret < 0)
+ return ret;
+ }
+ /*
+ * Remove the registered timer-based resmon in order to update interval
+ * of timer-based resmon if it's already created.
+ */
+ } else {
+ g_source_remove(monitor->timer_id);
+ }
+
+ /* Add timer-based resmon with new interval to update the interval */
+ monitor->timer_id = g_timeout_add((guint)interval,
+ (GSourceFunc)resmon_timer_func,
+ (gpointer)monitor);
+ if (!monitor->timer_id) {
+ resmon->timer_list = g_list_remove(resmon->timer_list,
+ (gpointer)monitor);
+ resmon->timer_state &= ~monitor->src_type;
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int resmon_timer_delete(struct resmon *monitor)
+{
+ struct pass_resmon *resmon = monitor->resmon;
+ int ret;
+
+ g_source_remove(monitor->timer_id);
+
+ if (monitor->ops && monitor->ops->exit) {
+ ret = monitor->ops->exit(monitor);
+ if (ret < 0)
+ return ret;
+ }
+
+ resmon->timer_state &= ~(monitor->src_type);
+ resmon->timer_list = g_list_remove(resmon->timer_list,
+ (gpointer)monitor);
+
+ return 0;
+}
+
+static gboolean resmon_timer_func(gpointer data)
+{
+ struct resmon *monitor = data;
+ struct pass_resmon *resmon = monitor->resmon;
+ struct pass_resource *res
+ = container_of(resmon, struct pass_resource, resmon);;
+ int ret = 0;
+
+ if (!monitor->result)
+ return false;
+
+ /* Collect resource data according to enum resmon_src_type */
+ if (monitor->ops && monitor->ops->timer_handler) {
+ ret = monitor->ops->timer_handler(monitor, monitor->result);
+ if (ret < 0) {
+ _E("failed to invoke timer_handler " \
+ "(res_name:%s, src_type: 0x%x)\n",
+ res->config_data.res_name, monitor->src_type);
+ return false;
+ }
+ }
+
+ /* Pass collected resource data (result) to resmon's user */
+ if (monitor->user_func) {
+ ret = (monitor->user_func)(monitor->result, monitor->user_data);
+ if (ret < 0) {
+ _E("failed to invoke user_func " \
+ "(res_name:%s, src_type: 0x%x)\n",
+ res->config_data.res_name, monitor->src_type);
+ return false;
+ }
+ }
+
+ /* If monitor has oneshot mode, delete the timer-based resmon */
+ switch (monitor->timer_type) {
+ case RESMON_TIMER_ONESHOT:
+ ret = resmon_timer_delete(monitor);
+ if (ret < 0) {
+ _E("failed to delete timer " \
+ "(res_name:%s, src_type: 0x%x)\n",
+ res->config_data.res_name, monitor->src_type);
+ return false;
+ }
+
+ free(monitor);
+ monitor = NULL;
+ break;
+ case RESMON_TIMER_PERIODIC:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * pass_resmon_register_timer - Register timer-based resource monitor
+ *
+ * @res: the instance of struct pass_resource.
+ * @src_type: the type of resource monitor among 'enum resmon_src_type'.
+ * @timer_type: the type of timer among 'enum resmon_timer_type'.
+ * @timer_interval: the interval of timer (unit: millisecond).
+ * @user_func: the callback function when timer is expired.
+ * @user_data: the passed user user_data.
+ */
+int pass_resmon_register_timer(struct pass_resource *res,
+ enum resmon_src_type src_type,
+ enum resmon_timer_type timer_type,
+ unsigned int timer_interval,
+ int (*user_func)(void *result, void *user_data),
+ void *user_data)
+{
+ struct pass_resmon *resmon;
+ struct resmon *monitor;
+ int res_type;
+ int ret;
+
+ if (!res || src_type == 0 || timer_type == 0 || user_func == NULL)
+ return -EINVAL;
+
+ resmon = &res->resmon;
+
+ /* Check whether the resource monitor is supported or not */
+ res_type = res->config_data.res_type;
+ if (!resmon_is_supported(res_type, src_type)) {
+ _E("invalid value (res_type: %d, src_type: 0x%x)\n",
+ res_type, src_type);
+ return -EINVAL;
+ }
+
+ /* Prevent the monitoring of already required type */
+ if (resmon_is_created(resmon, src_type)) {
+ _E("timer is already created (res_type: %d, src_type: 0x%x)\n",
+ res_type, src_type);
+ return -EBUSY;
+ }
+
+ /* Allocate the memory for resource monitor */
+ monitor = calloc(1, sizeof(struct resmon));
+ if (!monitor)
+ return -ENOMEM;
+
+ monitor->resmon = resmon;
+ monitor->src_type = src_type;
+ monitor->timer_type = timer_type;
+ monitor->timer_interval = timer_interval;
+ monitor->user_func = user_func;
+ monitor->user_data = user_data;
+
+ /* TODO: Get instance of struct resmon_ops accoring to resmon_src_type */
+
+ /* Add timer-based resource monitor */
+ ret = resmon_timer_add(monitor, timer_interval);
+ if (ret < 0) {
+ _E("failed to add monitor (res_type: %d, src_type: 0x%x)\n",
+ res_type, src_type);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ free(monitor);
+ monitor = NULL;
+
+ return ret;
+}
+
+/*
+ * pass_resmon_unregister_timer - Unregister timer-based resource monitor
+ *
+ * @res: the instance of struct pass_resource
+ * @src_type: the type of resource monitor among 'enum resmon_src_type'.
+ */
+int pass_resmon_unregister_timer(struct pass_resource *res,
+ enum resmon_src_type src_type)
+{
+ struct resmon *monitor;
+ int ret;
+
+ if (!res || src_type == 0)
+ return -EINVAL;
+
+ monitor = resmon_find_monitor(&res->resmon, src_type);
+ if (!monitor) {
+ _E("failed to find monitor (res_type: %d, src_type: 0x%x)\n",
+ res->config_data.res_type, src_type);
+ return -EINVAL;
+ }
+
+ /* Delete timer-based resource monitor */
+ ret = resmon_timer_delete(monitor);
+ if (ret < 0) {
+ _E("failed to delete monitor (res_type: %d, src_type: 0x%x)\n",
+ res->config_data.res_type, src_type);
+ }
+
+ /* Free the memory of resource monitor */
+ free(monitor);
+ monitor = NULL;
+
+ return 0;
+}
+
+/*
+ * pass_resmon_update_interval - Update the period of timer
+ *
+ * @res: the instance of struct pass_resource.
+ * @src_type: the type of resource monitor among 'enum resmon_src_type'.
+ * @timer_interval: the interval of timer (unit: millisecond).
+ */
+int pass_resmon_update_timer_interval(struct pass_resource *res,
+ enum resmon_src_type src_type,
+ int timer_interval)
+{
+ struct resmon *monitor;
+ int ret;
+
+ if (!res)
+ return -EINVAL;
+
+ /* Find registered timer-based resmon */
+ monitor = resmon_find_monitor(&res->resmon, src_type);
+ if (!monitor) {
+ _E("failed to find monitor (res_type:%d, src_type: 0x%x)\n",
+ res->config_data.res_type, src_type);
+ return -EINVAL;
+ }
+
+ /* Update new interval of timer-based resmon */
+ ret = resmon_timer_add(monitor, timer_interval);
+ if (ret < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int pass_resmon_init(struct pass_resource *res)
+{
+ struct pass_resmon *resmon;
+
+ if (!res)
+ return -EINVAL;
+ if (res->resmon.state == PASS_ON)
+ return -EINVAL;
+
+ resmon = &res->resmon;
+
+ resmon->timer_list = NULL;
+ resmon->timer_state = 0;
+
+ resmon->state = PASS_ON;
+
+ return 0;
+}
+
+int pass_resmon_exit(struct pass_resource *res)
+{
+ struct pass_resmon *resmon;
+
+ if (!res)
+ return -EINVAL;
+ if (res->resmon.state == PASS_OFF)
+ return -EINVAL;
+
+ resmon = &res->resmon;
+
+ g_list_free(resmon->timer_list);
+ resmon->timer_list = NULL;
+ resmon->timer_state = 0;
+
+ resmon->state = PASS_OFF;
+
+ return 0;
+}
--- /dev/null
+/*
+ * PASS (Power Aware System Service) Header file of Resource Monitor
+ *
+ * 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.
+ */
+
+#ifndef __PASS_RESMON__
+#define __PASS_RESMON__
+
+/*
+ * enum resmon_timer_type - Represents the type of timer-based resource monitor.
+ * - RESMON_TIMER_PERIODIC: Periodic timer with the regular interval.
+ * - RESMON_TIMER_ONESHOT: Oneshot timer after the interval.
+ */
+enum resmon_timer_type {
+ RESMON_TIMER_PERIODIC = 1,
+ RESMON_TIMER_ONESHOT,
+};
+
+/*
+ * enum resmon_src_type - Represents the source type of resource-monitor.
+ * - RESMON_THERMAL: Monitor the 'thermal' info of h/w resource.
+ * - RESMON_CPUHP: Monitor the 'CPU h/w resource' as following:
+ * CPU utilization/frequency/the number of running tasks. But this type
+ * is using nonstandard linux kernel interface. It should be replaced with
+ * the linux kernel standard interface.
+ */
+enum resmon_src_type {
+ RESMON_SRC_UNKNOWN = 0x0,
+ RESMON_SRC_THERMAL = 0x1,
+ RESMON_SRC_CPUHP = 0x2,
+};
+
+/*
+ * pass_resmon_register_timer - Register timer-based resource monitor.
+ *
+ * @res: the instance of struct pass_resource.
+ * @src_type: the type of resource monitor among 'enum resmon_src_type'.
+ * @timer_type: the type of timer among 'enum resmon_timer_type'.
+ * @timer_interval: the interval of timer (unit: millisecond).
+ * @user_func: the callback function when timer is expired.
+ * @user_data: the passed user user_data.
+ */
+int pass_resmon_register_timer(struct pass_resource *res,
+ enum resmon_src_type src_type,
+ enum resmon_timer_type timer_type,
+ unsigned int timer_interval,
+ int (*user_func)(void *result, void *user_data),
+ void *user_data);
+
+/*
+ * pass_resmon_unregister_timer - Unregister timer-based resource monitor.
+ *
+ * @res: the instance of struct pass_resource.
+ * @src_type: the type of resource monitor among 'enum resmon_src_type'.
+ */
+int pass_resmon_unregister_timer(struct pass_resource *res,
+ enum resmon_src_type src_type);
+
+/*
+ * pass_resmon_update_timer_interval - Update interval of timer-based monitor.
+ *
+ * @res: the instance of struct pass_resource.
+ * @src_type: the type of resource monitor among 'enum resmon_src_type'.
+ * @timer_interval: the interval of timer (unit: millisecond).
+ */
+int pass_resmon_update_timer_interval(struct pass_resource *res,
+ enum resmon_src_type src_type,
+ int timer_interval);
+
+#endif /* __PASS_RESMON__ */