--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2012 - 2017 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "pass.h"
+#include "hal/hal.h"
+#include "pass-hal.h"
+
+#include "core/common.h"
+
+static struct pass_resource_dvfs_ops *get_dvfs(struct pass_resource *res, int id)
+{
+ struct pass_resource_dvfs_ops *dvfs = NULL;
+
+ switch (id) {
+ case PASS_RESOURCE_CPU_ID:
+ dvfs = &(res->hw.cpu->dvfs);
+ break;
+ case PASS_RESOURCE_BUS_ID:
+ dvfs = &(res->hw.bus->dvfs);
+ break;
+ case PASS_RESOURCE_GPU_ID:
+ dvfs = &(res->hw.gpu->dvfs);
+ break;
+ }
+
+ return dvfs;
+}
+
+static struct pass_resource_tmu_ops *get_tmu(struct pass_resource *res, int id)
+{
+ struct pass_resource_tmu_ops *tmu = NULL;
+
+ switch (id) {
+ case PASS_RESOURCE_CPU_ID:
+ tmu = &(res->hw.cpu->tmu);
+ break;
+ case PASS_RESOURCE_BUS_ID:
+ tmu = &(res->hw.bus->tmu);
+ break;
+ case PASS_RESOURCE_GPU_ID:
+ tmu = &(res->hw.gpu->tmu);
+ break;
+ }
+
+ return tmu;
+}
+
+static struct pass_resource_hotplug_ops *get_hotplug(struct pass_resource *res,
+ int id)
+{
+ struct pass_resource_hotplug_ops *hotplug = NULL;
+
+ switch (id) {
+ case PASS_RESOURCE_CPU_ID:
+ hotplug = &(res->hw.cpu->hotplug);
+ break;
+ case PASS_RESOURCE_BUS_ID:
+ case PASS_RESOURCE_GPU_ID:
+ hotplug = NULL;
+ break;
+ }
+
+ return hotplug;
+}
+
+/* Get and set the current governor for DVFS resource. */
+int pass_get_curr_governor(struct pass_resource *res, char *governor)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res || !governor)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->get_curr_governor || !res_name)
+ return -EINVAL;
+
+ return dvfs->get_curr_governor(res_name, governor);
+}
+
+int pass_set_curr_governor(struct pass_resource *res, char *governor)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->set_curr_governor || !res_name)
+ return -EINVAL;
+
+ return dvfs->set_curr_governor(res_name, governor);
+}
+
+/* Get and set the current/min/max frequency for DVFS resource. */
+int pass_get_curr_freq(struct pass_resource *res)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->get_curr_freq || !res_name)
+ return -EINVAL;
+
+ return dvfs->get_curr_freq(res_name);
+}
+
+
+int pass_get_min_freq(struct pass_resource *res)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->get_min_freq || !res_name)
+ return -EINVAL;
+
+ return dvfs->get_min_freq(res_name);
+}
+
+int pass_set_min_freq(struct pass_resource *res, int freq)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res || freq <= 0)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->set_min_freq || !res_name)
+ return -EINVAL;
+
+ return dvfs->set_min_freq(res_name, freq);
+}
+
+int pass_get_max_freq(struct pass_resource *res)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->get_max_freq || !res_name)
+ return -EINVAL;
+
+ return dvfs->get_max_freq(res_name);
+}
+
+int pass_set_max_freq(struct pass_resource *res, int freq)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res || freq <= 0)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->set_max_freq || !res_name)
+ return -EINVAL;
+
+ return dvfs->set_max_freq(res_name, freq);
+}
+
+/* Get and set the up_threshold for DVFS resource. */
+int pass_get_up_threshold(struct pass_resource *res)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->get_up_threshold || !res_name)
+ return -EINVAL;
+
+ return dvfs->get_up_threshold(res_name);
+}
+
+int pass_set_up_threshold(struct pass_resource *res, int up_threshold)
+{
+ struct pass_resource_dvfs_ops *dvfs;
+ char *res_name;
+ int id;
+
+ if (!res || up_threshold <= 0)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ dvfs = get_dvfs(res, id);
+ if (!dvfs)
+ return -EINVAL;
+
+ if (!dvfs->set_up_threshold || !res_name)
+ return -EINVAL;
+
+ return dvfs->set_up_threshold(res_name, up_threshold);
+}
+
+/* Get and set the online state of HOTPLUG resource (e.g., CPU). */
+int pass_get_online_state(struct pass_resource *res, int cpu)
+{
+ struct pass_resource_hotplug_ops *hotplug;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ hotplug = get_hotplug(res, id);
+ if (!hotplug)
+ return -EINVAL;
+
+ if (!hotplug->get_online_state || !res_name)
+ return -EINVAL;
+
+ return hotplug->get_online_state(res_name, cpu);
+}
+
+int pass_set_online_state(struct pass_resource *res, int cpu, int on)
+{
+ struct pass_resource_hotplug_ops *hotplug;
+ char *res_name;
+ int id;
+
+ if (!res || on < 0)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ hotplug = get_hotplug(res, id);
+ if (!hotplug)
+ return -EINVAL;
+
+ if (!hotplug->set_online_state || !res_name)
+ return -EINVAL;
+
+ return hotplug->set_online_state(res_name, cpu, on);
+}
+
+/* Get the temperature and thermal policy for Thermal resource. */
+int pass_get_temp(struct pass_resource *res)
+{
+ struct pass_resource_tmu_ops *tmu;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ tmu = get_tmu(res, id);
+ if (!tmu)
+ return -EINVAL;
+
+ if (!tmu->get_temp || !res_name)
+ return -EINVAL;
+
+ return tmu->get_temp(res_name);
+}
+
+int pass_get_policy(struct pass_resource *res, char *policy)
+{
+ struct pass_resource_tmu_ops *tmu;
+ char *res_name;
+ int id;
+
+ if (!res)
+ return -EINVAL;
+
+ res_name = res->cdata.res_name;
+ id = res->cdata.res_type;
+
+ tmu = get_tmu(res, id);
+ if (!tmu)
+ return -EINVAL;
+
+ if (!tmu->get_policy || !res_name)
+ return -EINVAL;
+
+ return tmu->get_policy(res_name, policy);
+}
+
+int pass_get_resource(struct pass *pass)
+{
+ struct pass_resource_info *info;
+ int i, ret;
+
+ for (i = 0; i < pass->num_resources; i++) {
+ struct pass_resource *pass_res = &pass->res[i];
+ struct pass_conf_data *cdata = &pass_res->cdata;
+ int res_type = cdata->res_type;
+ char name[10];
+
+ switch (res_type) {
+ case PASS_RESOURCE_CPU_ID:
+ strncpy(name, PASS_RESOURCE_CPU_NAME,
+ strlen(PASS_RESOURCE_CPU_NAME));
+ break;
+ case PASS_RESOURCE_BUS_ID:
+ strncpy(name, PASS_RESOURCE_BUS_NAME,
+ strlen(PASS_RESOURCE_BUS_NAME));
+ break;
+ case PASS_RESOURCE_GPU_ID:
+ strncpy(name, PASS_RESOURCE_GPU_NAME,
+ strlen(PASS_RESOURCE_GPU_NAME));
+ break;
+ default:
+ _E("Unsupported resource type (type: %d)\n", res_type);
+ return -EINVAL;
+ };
+
+ ret = pass_get_hw_info(name,
+ (const struct pass_resource_info **)&info);
+ if (ret < 0) {
+ _E("Failed to get h/w info\n");
+ return -EINVAL;
+ }
+
+ if (!info->open || !info->close) {
+ _E("Failed to open %s h/w device\n", name);
+ return -EPERM;
+ }
+
+ switch (res_type) {
+ case PASS_RESOURCE_CPU_ID:
+ ret = info->open(info,
+ (struct pass_resource_common**)&pass_res->hw.cpu);
+ break;
+ case PASS_RESOURCE_BUS_ID:
+ ret = info->open(info,
+ (struct pass_resource_common**)&pass_res->hw.bus);
+ break;
+ case PASS_RESOURCE_GPU_ID:
+ ret = info->open(info,
+ (struct pass_resource_common**)&pass_res->hw.gpu);
+ break;
+ };
+
+ if (ret < 0) {
+ _E("Failed to open %s h/w resource\n", name);
+ return -EINVAL;
+ }
+
+ _D("Complete the loading for %s h/w resource\n", name);
+ }
+
+ return 0;
+}
+
+/*
+ * FXIME: Following function is not standard interface.
+ * Following functions will be altered by the standard interface on later.
+ *
+ * - int pass_get_num_cpus(void)
+ * - int pass_get_cpu_stats(struct pass_policy *policy)
+ * - int64_t pass_get_time_ms(void)
+ */
+int pass_get_num_cpus(void)
+{
+ int num_cpus;
+ int ret;
+
+ ret = sys_get_int("/sys/devices/system/cpu/kernel_max", &num_cpus);
+ if (ret < 0)
+ return -EAGAIN;
+
+ /*
+ * Return the number of cpus with plus 1 because of index
+ * of first CPU is 0 (zero). (e.g., Octa cores have the '7' value
+ * of "/sys/devices/system/cpu/kernel_max").
+ */
+ return (num_cpus + 1);
+}
+
+/* Get the load_table of each resource to estimate the system load. */
+#define BUFF_MAX 255
+int pass_get_cpu_stats(struct pass_policy *policy)
+{
+ struct pass_cpu_stats *stats = policy->pass_cpu_stats;
+ char str[BUFF_MAX];
+ FILE *fp_stats = NULL;
+ int i, j, ret;
+
+ if (!policy || !policy->cluster.path_load_table || !stats) {
+ _E("invalid parameter of structure pass_cpu_stats");
+ return -EINVAL;
+ }
+
+ fp_stats = fopen(policy->cluster.path_load_table, "r");
+ if (fp_stats == NULL)
+ return -EIO;
+
+ /* Read the title and drop the buffer because it is not used */
+ if (!fgets(str, BUFF_MAX, fp_stats))
+ return -EIO;
+
+ for (i = 0; i < policy->num_pass_cpu_stats; i++) {
+ ret = fscanf(fp_stats, "%lld %d %d %d",
+ &stats[i].time,
+ &stats[i].freq,
+ &stats[i].freq_new,
+ &stats[i].nr_runnings);
+ if (ret < 0)
+ return -EIO;
+
+ for (j = 0; j < policy->cpufreq.num_nr_cpus; j++) {
+ ret = fscanf(fp_stats, "%d", &stats[i].load[j]);
+ if (ret < 0)
+ return -EIO;
+ }
+ }
+ fclose(fp_stats);
+
+ return 0;
+}
+
+/* Return current time (unit: millisecond) */
+int64_t pass_get_time_ms(void)
+{
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ return (int64_t)(now.tv_sec * 1000 + now.tv_usec / 1000);
+}
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2012 - 2017 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_HAL__
+#define __PASS_HAL__
+
+#include "hal/hal.h"
+
+/* Get and the current governor. */
+int pass_get_curr_governor(struct pass_resource *res, char *governor);
+int pass_set_curr_governor(struct pass_resource *res, char *governor);
+
+/* Get the current frequency. */
+int pass_get_curr_freq(struct pass_resource *res);
+
+/* Get and set the minimum frequency. */
+int pass_get_min_freq(struct pass_resource *res);
+int pass_set_min_freq(struct pass_resource *res, int freq);
+
+/* Get and set the maximum frequency. */
+int pass_get_max_freq(struct pass_resource *res);
+int pass_set_max_freq(struct pass_resource *res, int freq);
+
+/* Get and set the up_threshold to support boosting. */
+int pass_get_up_threshold(struct pass_resource *res);
+int pass_set_up_threshold(struct pass_resource *res, int up_threshold);
+
+/* Get and set online state of cpu. */
+int pass_get_online_state(struct pass_resource *res, int cpu);
+int pass_set_online_state(struct pass_resource *res, int cpu, int on);
+
+/* Get the temperature and policy of thermal unit on specific h/w. */
+int pass_get_temp(struct pass_resource *res);
+int pass_get_policy(struct pass_resource *res, char *policy);
+
+/* Load the h/w resource. */
+int pass_get_resource(struct pass *pass);
+
+/*
+ * FXIME: Following function is not standard interface.
+ * These functions will be altered by the standard interface on later.
+ */
+int pass_get_num_cpus(void);
+int pass_get_cpu_stats(struct pass_policy *policy);
+int64_t pass_get_time_ms(void);
+
+#endif /* __PASS_HAL__ */
struct pass_cluster_data cluster;
};
+
+/******************************************************
+ * PASS resource *
+ ******************************************************/
+/*
+ * struct pass_conf_data - Parsed data for each h/w resource from
+ * configuration file (pass.conf).
+ *
+ * Mandatory:
+ * @res_type: the unique id for each h/w resource. The id can have
+ * the one value among following defined resource id.
+ * - 1: PASS_RESOURCE_CPU_ID
+ * - 2: PASS_RESOURCE_BUS_ID
+ * - 3: PASS_RESOURCE_GPU_ID
+ * @res_name: the unique name of sysfs entry.
+ * - In case of /sys/devices/system/cpu/cpu0, res_name is 'cpu0'
+ * - In case of /sys/devices/system/cpu/cpu4, res_name is 'cpu4'
+ * - In case of /sys/class/devfreq/devfreq3, res_name is 'devfreq3'
+ * - In case of /sys/class/devfreq/mali.11400000, res_name is 'mali.11400000'
+ * @path_conf_file: the path for PASS configuration file
+ * @path_load_table: the path for load_table entry from kernel
+ *
+ * Optional:
+ * @num_cpus: the number of supported cpus in the same cluster.
+ * @cpu: the index of first cpu in the same cluster.
+ */
+struct pass_conf_data {
+ unsigned int res_type;
+ char res_name[128];
+ char path_conf_file[128];
+ char path_load_table[128];
+
+ unsigned int num_cpus;
+ unsigned int cpu;
+};
+
+/*
+ * struct pass_resource - Represent the each h/w resource.
+ *
+ * @cdata: the parsed data from configuration file (pass.conf).
+ * @hw: the resource instance of each h/w resource from pass_get_hw_info().
+ * - If res_type of cdata is PASS_RESOURCE_CPU_ID, hw.cpu will be used.
+ * - If res_type of cdata is PASS_RESOURCE_BUS_ID, hw.bus will be used.
+ * - If res_type of cdata is PASS_RESOURCE_GPU_ID, hw.gpu will be used.
+ * @policy: the policy data to handle the h/w resource
+ */
+struct pass_resource {
+ struct pass_conf_data cdata;
+ struct pass_policy policy;
+
+ union {
+ struct pass_resource_cpu *cpu;
+ struct pass_resource_bus *bus;
+ struct pass_resource_gpu *gpu;
+ } hw;
+};
+
+struct pass {
+ unsigned int num_resources;
+ struct pass_resource *res;
+};
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define to_pass_resource(policy) \
+ container_of(policy, struct pass_resource, policy)
+
#endif /* __pass__ */