From dc1bc98362ef5358502d8b2ce6606d2431db856e Mon Sep 17 00:00:00 2001 From: Wook Song Date: Wed, 8 Feb 2017 14:57:22 +0900 Subject: [PATCH] pass-hal: tm2: Add implementation of HAL for CPU This patch adds an implementation of the PASS HAL for CPU. Change-Id: I74afc0c021ad462e1630d84bbe922ee3fac52b6e Signed-off-by: Wook Song --- CMakeLists.txt | 2 + packaging/pass-hal-tm2.spec | 6 + src/cpu/CMakeLists.txt | 24 +++ src/cpu/cpu.c | 403 ++++++++++++++++++++++++++++++++++++++++++++ src/shared/sysfs.c | 110 ++++++++++++ src/shared/sysfs.h | 6 + 6 files changed, 551 insertions(+) create mode 100644 src/cpu/CMakeLists.txt create mode 100644 src/cpu/cpu.c create mode 100644 src/shared/sysfs.c create mode 100644 src/shared/sysfs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 78f784c..116648e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,3 +14,5 @@ ENDFOREACH(flag) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(DEST_DIR ${LIB_INSTALL_DIR}/pass) + +ADD_SUBDIRECTORY(src/cpu) diff --git a/packaging/pass-hal-tm2.spec b/packaging/pass-hal-tm2.spec index 68f4213..2752cf8 100644 --- a/packaging/pass-hal-tm2.spec +++ b/packaging/pass-hal-tm2.spec @@ -28,9 +28,15 @@ cp %{SOURCE1} . make %{?jobs:-j%jobs} +%install +rm -rf %{buildroot} + +%make_install + %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %manifest %{name}.manifest +%{_libdir}/pass/*.so diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt new file mode 100644 index 0000000..3cd62b8 --- /dev/null +++ b/src/cpu/CMakeLists.txt @@ -0,0 +1,24 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(cpu C) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED dlog glib-2.0) + +#HAL version +string(REPLACE "." ";" HAL_VERSION_LIST ${HAL_VERSION}) +list(GET HAL_VERSION_LIST 0 HAL_VERSION_MAJOR) +list(GET HAL_VERSION_LIST 1 HAL_VERSION_MINOR) +list(GET HAL_VERSION_LIST 2 HAL_VERSION_REVISION) +list(GET HAL_VERSION_LIST 3 HAL_VERSION_RELEASE) +add_definitions(-DVER_MAJOR=${HAL_VERSION_MAJOR} -DVER_MINOR=${HAL_VERSION_MINOR}) +add_definitions(-DVER_REVISION=${HAL_VERSION_REVISION} -DVER_RELEASE=${HAL_VERSION_RELEASE}) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +SET(SRCS ${PROJECT_NAME}.c + ../shared/sysfs.c) + +ADD_LIBRARY(${PROJECT_NAME} MODULE ${SRCS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${DEST_DIR} COMPONENT RuntimeLibraries) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c new file mode 100644 index 0000000..a9e23bc --- /dev/null +++ b/src/cpu/cpu.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../shared/sysfs.h" + +/* TODO: Version! */ +#define HAL_VERSION MAKE_2B_CODE_4(VER_MAJOR,VER_MINOR,VER_REVISION,VER_RELEASE) +#define DEV_VERSION_CPU MAKE_2B_CODE_2(1,0) + +#define CPUFREQ_PATH_PREFIX "/sys/devices/system/cpu/" +#define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_governor" +#define CPUFREQ_AVAIL_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_available_governors" + +/* + * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy + * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy. + */ +#define CPUFREQ_CURR_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_cur_freq" +#define CPUFREQ_MIN_FREQ_PATH_SUFFIX "/cpufreq/scaling_min_freq" +#define CPUFREQ_MAX_FREQ_PATH_SUFFIX "/cpufreq/scaling_max_freq" +#define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX "/cpufreq/ondemand/up_threshold" + +#define LOADTABLE_PATH_PREFIX "/sys/kernel/debug/cpufreq/" +#define LOADTABLE_PATH_SUFFIX "/load_table" + +#define CPU_ONLINE_PATH_PREFIX "/sys/devices/system/cpu/cpu" +#define CPU_ONLINE_PATH_SUFFIX "/online" +#define CPU_ONLINE_STATE_ON 1 +#define CPU_ONLINE_STATE_OFF 0 + +#define TMU_PATH_PREFIX "/sys/class/thermal/thermal_zone" +#define TMU_TEMP_PATH_SUFFIX "/temp" +#define TMU_POLICY_PATH_SUFFIX "/policy" + +#define TM2_CPU_MIN_NUM 0 +#define TM2_CPU_MAX_NUM 7 + +#define TM2_CPU_LITTLE_RESNAME "cpu0" +#define TM2_CPU_BIG_RESNAME "cpu4" +#define TM2_CPU_LITTLE_THERMAL_ZONE_NUM 3 +#define TM2_CPU_BIG_THERMAL_ZONE_NUM 0 + + +static int tm2_dvfs_get_curr_governor(char *res_name, char *governor) +{ + char path[PATH_MAX]; + int ret; + + if ((!res_name) || (!governor)) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX); + + ret = sysfs_read_str(path, governor, BUFF_MAX); + if (ret < 0) + return ret; + + return 0; +} + +static int tm2_dvfs_set_curr_governor(char *res_name, char *governor) +{ + char path[PATH_MAX]; + int ret; + + if ((!res_name) || (!governor)) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX); + + ret = sysfs_write_str(path, governor); + if (ret < 0) + return ret; + + return 0; +} + +static int tm2_dvfs_get_curr_freq(char *res_name) +{ + char path[PATH_MAX]; + int freq, ret; + + if (!res_name) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_CURR_FREQ_PATH_SUFFIX); + + ret = sysfs_read_int(path, &freq); + if (ret < 0) + return ret; + + return freq; +} + +static int tm2_dvfs_get_min_freq(char *res_name) +{ + char path[PATH_MAX]; + int freq, ret; + + if (!res_name) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_MIN_FREQ_PATH_SUFFIX); + + ret = sysfs_read_int(path, &freq); + if (ret < 0) + return ret; + + return freq; +} + +static int tm2_dvfs_set_min_freq(char *res_name, int freq) +{ + char path[PATH_MAX]; + int ret; + + if ((!res_name) || (freq < 0)) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_MIN_FREQ_PATH_SUFFIX); + + ret = sysfs_write_int(path, freq); + if (ret < 0) + return ret; + + return 0; +} + +static int tm2_dvfs_get_max_freq(char *res_name) +{ + char path[PATH_MAX]; + int freq, ret; + + if (!res_name) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_MAX_FREQ_PATH_SUFFIX); + + ret = sysfs_read_int(path, &freq); + if (ret < 0) + return ret; + + return freq; +} + +static int tm2_dvfs_set_max_freq(char *res_name, int freq) +{ + char path[PATH_MAX]; + int ret; + + if ((!res_name) || (freq < 0)) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_MAX_FREQ_PATH_SUFFIX); + + ret = sysfs_write_int(path, freq); + if (ret < 0) + return ret; + return 0; +} + +static int tm2_dvfs_get_up_threshold(char *res_name) +{ + char path[PATH_MAX]; + int val, ret; + + if (!res_name) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_UP_THRESHOLD_PATH_SUFFIX); + + ret = sysfs_read_int(path, &val); + if (ret < 0) + return ret; + + return val; +} + +static int tm2_dvfs_set_up_threshold(char *res_name, int up_threshold) +{ + char path[PATH_MAX]; + int ret; + + if ((!res_name) || (up_threshold < 0)) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%s%s", + CPUFREQ_PATH_PREFIX, + res_name, + CPUFREQ_UP_THRESHOLD_PATH_SUFFIX); + + ret = sysfs_write_int(path, up_threshold); + if (ret < 0) + return ret; + + return 0; +} + +static int tm2_dvfs_get_load_table(char *res_name, void *pass_cpu_load_table) +{ + return 0; +} + +static struct pass_resource_dvfs_ops tm2_cpu_dvfs_ops = { + .get_curr_governor = tm2_dvfs_get_curr_governor, + .set_curr_governor = tm2_dvfs_set_curr_governor, + .get_avail_governor = NULL, + .get_curr_freq = tm2_dvfs_get_curr_freq, + .get_min_freq = tm2_dvfs_get_min_freq, + .set_min_freq = tm2_dvfs_set_min_freq, + .get_max_freq = tm2_dvfs_get_max_freq, + .set_max_freq = tm2_dvfs_set_max_freq, + .get_up_threshold = tm2_dvfs_get_up_threshold, + .set_up_threshold = tm2_dvfs_set_up_threshold, + .get_load_table = tm2_dvfs_get_load_table, +}; + +static int tm2_hotplug_get_online_state(char *res_name, int cpu) +{ + char path[PATH_MAX]; + int ret, online; + + if ((!res_name)) + return -EINVAL; + if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM)) + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%d%s", + CPU_ONLINE_PATH_PREFIX, + cpu, + CPU_ONLINE_PATH_SUFFIX); + + ret = sysfs_read_int(path, &online); + if (ret < 0) + return ret; + + return online; +} + +static int tm2_hotplug_set_online_state(char *res_name, int cpu, int on) +{ + char path[PATH_MAX]; + int ret; + + + if ((!res_name)) + return -EINVAL; + if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM)) + return -EINVAL; + if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF)) + return -EINVAL; + + /* TODO: Can we turn off CPU0? */ + + snprintf(path, PATH_MAX, "%s%d%s", + CPU_ONLINE_PATH_PREFIX, + cpu, + CPU_ONLINE_PATH_SUFFIX); + + ret = sysfs_write_int(path, on); + if (ret < 0) + return ret; + + return 0; +} + +static struct pass_resource_hotplug_ops tm2_cpu_hotplus_ops = { + .get_online_state = tm2_hotplug_get_online_state, + .set_online_state = tm2_hotplug_set_online_state, +}; + +static int tm2_tmu_get_temp(char *res_name) +{ + char path[PATH_MAX]; + int tz_num, temp; + int ret; + + if (!res_name) + return -EINVAL; + + if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME)) + tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM; + else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME)) + tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM; + else + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%d%s", + TMU_PATH_PREFIX, + tz_num, + TMU_TEMP_PATH_SUFFIX); + + ret = sysfs_read_int(path, &temp); + if (ret < 0) + return ret; + + return temp; +} + +static int tm2_tmu_get_policy(char *res_name, char *policy) +{ + char path[PATH_MAX]; + int ret, tz_num; + + if ((!res_name) || (!policy)) + return -EINVAL; + + if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME)) + tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM; + else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME)) + tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM; + else + return -EINVAL; + + snprintf(path, PATH_MAX, "%s%d%s", + TMU_PATH_PREFIX, + tz_num, + TMU_POLICY_PATH_SUFFIX); + + ret = sysfs_read_str(path, policy, BUFF_MAX); + if (ret < 0) + return ret; + + return 0; +} + +static struct pass_resource_tmu_ops tm2_cpu_tmu_ops = { + .get_temp = tm2_tmu_get_temp, + .get_policy = tm2_tmu_get_policy, +}; + +static int tm2_cpu_open(struct pass_resource_info *info, + struct pass_resource_common **common) +{ + struct pass_resource_cpu *cpu_res; + + if (!info) + return -EINVAL; + + /* TODO: Possibility of a memory leak */ + cpu_res = calloc(1, sizeof(struct pass_resource_cpu)); + if (!cpu_res) + return -ENOMEM; + + cpu_res->common.info = info; + cpu_res->dvfs = tm2_cpu_dvfs_ops; + cpu_res->hotplug = tm2_cpu_hotplus_ops; + cpu_res->tmu = tm2_cpu_tmu_ops; + + *common = (struct pass_resource_common *) cpu_res; + + return 0; +} + +static int tm2_cpu_close(struct pass_resource_common *common) +{ + if (!common) + return -EINVAL; + + free(common); + + return 0; +} + +HAL_MODULE_STRUCTURE = { + .magic = HAL_INFO_TAG, + .hal_version = HAL_VERSION, + .device_version = DEV_VERSION_CPU, + .id = PASS_RESOURCE_CPU_ID, + .name = PASS_RESOURCE_CPU_NAME, + .author = "Wook Song ", + .open = tm2_cpu_open, + .close = tm2_cpu_close, +}; diff --git a/src/shared/sysfs.c b/src/shared/sysfs.c new file mode 100644 index 0000000..9217b40 --- /dev/null +++ b/src/shared/sysfs.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include + +#include "sysfs.h" + +static int sysfs_read_buf(char *path, char *buf, int len) +{ + int r, fd; + + if ((!path) || (!buf) || (len < 0)) + return -EINVAL; + + fd = open(path, O_RDONLY); + if (fd == -1) + return -ENOENT; + + r = read(fd, buf, len + 1); + close(fd); + + if ((r < 0) || (r > len)) + return -EIO; + + buf[r] = '\0'; + + return 0; +} + +static int sysfs_write_buf(char *path, char *buf) +{ + int w, fd; + + if ((!path) || (!buf)) + return -EINVAL; + + fd = open(path, O_WRONLY); + if (fd == -1) + return -ENOENT; + + w = write(fd, buf, strlen(buf)); + close(fd); + + if (w < 0) + return -EIO; + + return 0; +} + +int sysfs_read_int(char *path, int *val) +{ + char buf[MAX_BUF_SIZE]; + int r; + + if ((!path) || (!val)) + return -EINVAL; + + r = sysfs_read_buf(path, buf, MAX_BUF_SIZE); + if (r < 0) + return r; + + *val = atoi(buf); + return 0; +} + +int sysfs_read_str(char *path, char *str, int len) +{ + int r; + + if ((!path) || (!str) || (len <= 0)) + return -EINVAL; + + r = sysfs_read_buf(path, str, len); + if (r < 0) + return r; + + return 0; +} + +int sysfs_write_int(char *path, int val) +{ + char buf[MAX_BUF_SIZE]; + int w; + + if (!path) + return -EINVAL; + + snprintf(buf, MAX_BUF_SIZE, "%d", val); + w = sysfs_write_buf(path, buf); + if (w < 0) + return w; + + return 0; +} + +int sysfs_write_str(char *path, char *str) +{ + int w; + + if ((!path) || (!str)) + return -EINVAL; + + w = sysfs_write_buf(path, str); + if (w < 0) + return w; + + return 0; +} diff --git a/src/shared/sysfs.h b/src/shared/sysfs.h new file mode 100644 index 0000000..174804f --- /dev/null +++ b/src/shared/sysfs.h @@ -0,0 +1,6 @@ +#define MAX_BUF_SIZE 255 + +int sysfs_read_int(char *path, int *val); +int sysfs_read_str(char *path, char *str, int len); +int sysfs_write_int(char *path, int val); +int sysfs_write_str(char *path, char *str); -- 2.7.4