* rtg control entry
*
* Copyright (c) 2022-2023 Huawei Technologies Co., Ltd.
*/
#include "rtg.h"
#include "rtg_ctrl.h"
#include <linux/module.h>
#include <linux/device.h>
#ifdef CONFIG_AUTHORITY_CTRL
#include <linux/sched/auth_ctrl.h>
#endif
#include <linux/miscdevice.h>
#include <linux/compat.h>
#include <trace/events/rtg.h>
atomic_t g_rtg_enable = ATOMIC_INIT(0);
static atomic_t g_rt_frame_num = ATOMIC_INIT(0);
static int g_frame_max_util = DEFAULT_MAX_UTIL;
static int g_max_rt_frames = DEFAULT_MAX_RT_FRAME;
typedef long (*rtg_ctrl_func)(int abi, void __user *arg);
static long ctrl_set_enable(int abi, void __user *uarg);
static long ctrl_set_rtg(int abi, void __user *uarg);
static long ctrl_set_rtg_attr(int abi, void __user *uarg);
static long ctrl_begin_frame(int abi, void __user *uarg);
static long ctrl_end_frame(int abi, void __user *uarg);
static long ctrl_end_scene(int abi, void __user *uarg);
static long ctrl_set_min_util(int abi, void __user *uarg);
static long ctrl_set_margin(int abi, void __user *uarg);
static long ctrl_search_rtg(int abi, void __user *uarg);
static long ctrl_get_enable(int abi, void __user *uarg);
static rtg_ctrl_func g_func_array[RTG_CTRL_MAX_NR] = {
NULL,
ctrl_set_enable,
ctrl_set_rtg,
NULL,
ctrl_set_rtg_attr,
ctrl_begin_frame,
ctrl_end_frame,
ctrl_end_scene,
ctrl_set_min_util,
ctrl_set_margin,
NULL,
NULL,
ctrl_search_rtg,
ctrl_get_enable
};
static int init_proc_state(const int *config, int len);
static void deinit_proc_state(void);
static int set_enable_config(char *config_str)
{
char *p = NULL;
char *tmp = NULL;
int value;
int config[RTG_CONFIG_NUM];
int i;
int ret = 0;
for (i = 0; i < RTG_CONFIG_NUM; i++)
config[i] = INVALID_VALUE;
for (p = strsep(&config_str, ";"); p != NULL;
p = strsep(&config_str, ";")) {
tmp = strsep(&p, ":");
if ((tmp == NULL) || (p == NULL))
continue;
if (kstrtoint((const char *)p, DECIMAL, &value))
return -INVALID_ARG;
if (!strcmp(tmp, "sched_cycle"))
config[RTG_FREQ_CYCLE] = value;
else if (!strcmp(tmp, "frame_max_util"))
config[RTG_FRAME_MAX_UTIL] = value;
else if (!strcmp(tmp, "invalid_interval"))
config[RTG_INVALID_INTERVAL] = value;
else
continue;
}
for (i = 0; i < RTG_CONFIG_NUM; i++)
pr_info("[SCHED_RTG] config[%d] = %d\n", i, config[i]);
ret = init_proc_state(config, RTG_CONFIG_NUM);
return ret;
}
static void rtg_enable(int abi, const struct rtg_enable_data *data)
{
char temp[MAX_DATA_LEN];
int ret = -1;
if (atomic_read(&g_rtg_enable) == 1) {
pr_info("[SCHED_RTG] already enabled!\n");
return;
}
if ((data->len <= 0) || (data->len >= MAX_DATA_LEN)) {
pr_err("[SCHED_RTG] %s data len invalid\n", __func__);
return;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
switch (abi) {
case IOCTL_ABI_ARM32:
ret = copy_from_user(&temp,
(void __user *)compat_ptr((compat_uptr_t)data->data), data->len);
break;
case IOCTL_ABI_AARCH64:
ret = copy_from_user(&temp, (void __user *)data->data, data->len);
break;
default:
pr_err("[SCHED_RTG] abi format error\n");
break;
}
if (ret) {
pr_err("[SCHED_RTG] %s copy user data failed\n", __func__);
return;
}
#pragma GCC diagnostic pop
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
temp[data->len] = '\0';
if (set_enable_config(&temp) != SUCC) {
pr_err("[SCHED_RTG] %s failed!\n", __func__);
return;
}
#pragma GCC diagnostic pop
atomic_set(&g_rtg_enable, 1);
pr_info("[SCHED_RTG] enabled!\n");
}
static void rtg_disable(void)
{
if (atomic_read(&g_rtg_enable) == 0) {
pr_info("[SCHED_RTG] already disabled!\n");
return;
}
pr_info("[SCHED_RTG] disabled!\n");
atomic_set(&g_rtg_enable, 0);
deinit_proc_state();
}
static inline bool is_rt_type(int type)
{
return (type >= VIP && type < NORMAL_TASK);
}
static int do_update_rt_frame_num(struct frame_info *frame_info, int new_type)
{
int old_type;
int ret = SUCC;
mutex_lock(&frame_info->lock);
old_type = frame_info->prio - DEFAULT_RT_PRIO;
if (is_rt_type(new_type) == is_rt_type(old_type))
goto out;
if (is_rt_type(old_type)) {
if (atomic_read(&g_rt_frame_num) > 0)
atomic_dec(&g_rt_frame_num);
} else if (is_rt_type(new_type)) {
if (atomic_read(&g_rt_frame_num) < g_max_rt_frames) {
atomic_inc(&g_rt_frame_num);
} else {
pr_err("[SCHED_RTG]: %s g_max_rt_frames is %d\n",
__func__, g_max_rt_frames);
ret = -INVALID_ARG;
}
}
out:
mutex_unlock(&frame_info->lock);
return ret;
}
static int update_rt_frame_num(struct frame_info *frame_info, int new_type, int cmd)
{
int ret = SUCC;
switch (cmd) {
case UPDATE_RTG_FRAME:
ret = do_update_rt_frame_num(frame_info, new_type);
break;
case ADD_RTG_FRAME:
if (is_rt_type(new_type)) {
if (atomic_read(&g_rt_frame_num) >= g_max_rt_frames) {
pr_err("[SCHED_RTG] g_max_rt_frames is %d!\n", g_max_rt_frames);
ret = -INVALID_ARG;
} else {
atomic_inc(&g_rt_frame_num);
}
}
break;
case CLEAR_RTG_FRAME:
if ((atomic_read(&g_rt_frame_num) > 0) && is_rt_type(new_type))
atomic_dec(&g_rt_frame_num);
break;
default:
return -INVALID_ARG;
}
trace_rtg_frame_sched(frame_info->rtg->id, "g_rt_frame_num", atomic_read(&g_rt_frame_num));
trace_rtg_frame_sched(frame_info->rtg->id, "g_max_rt_frames", g_max_rt_frames);
return ret;
}
static long ctrl_set_enable(int abi, void __user *uarg)
{
struct rtg_enable_data rs_enable;
if (copy_from_user(&rs_enable, uarg, sizeof(rs_enable))) {
pr_err("[SCHED_RTG] CMD_ID_SET_ENABLE copy data failed\n");
return -INVALID_ARG;
}
if (rs_enable.enable == 1)
rtg_enable(abi, &rs_enable);
else
rtg_disable();
return SUCC;
}
static long ctrl_get_enable(int abi, void __user *uarg)
{
return atomic_read(&g_rtg_enable);
}
static inline bool is_valid_type(int type)
{
return (type >= VIP && type < RTG_TYPE_MAX);
}
static int parse_rtg_attr(const struct rtg_str_data *rs_data)
{
char *p = NULL;
char *tmp = NULL;
char *data = NULL;
int value;
struct frame_info *frame_info = NULL;
int rate = -1;
int type = -1;
int ret;
if (rs_data == NULL) {
pr_err("[SCHED_RTG] rtg attr: rs_data is null!\n");
return -INVALID_ARG;
}
data = rs_data->data;
if ((data == NULL) || (rs_data->len <= 0) ||
(rs_data->len > MAX_DATA_LEN)) {
pr_err("[SCHED_RTG] rtg attr: rs_data len err!\n");
return -INVALID_ARG;
}
for (p = strsep(&data, ";"); p != NULL; p = strsep(&data, ";")) {
tmp = strsep(&p, ":");
if ((tmp == NULL) || (p == NULL))
continue;
if (kstrtoint((const char *)p, DECIMAL, &value)) {
pr_err("[SCHED_RTG] rtg attr: rs_data format err!\n");
return -INVALID_ARG;
}
if (!strcmp(tmp, "rtgId")) {
frame_info = rtg_frame_info(value);
} else if (!strcmp(tmp, "rate")) {
rate = value;
} else if (!strcmp(tmp, "type")) {
if (is_valid_type(value)) {
type = value;
} else {
pr_err("[SCHED_RTG] invalid type : %d\n", value);
return -INVALID_ARG;
}
} else {
pr_err("[SCHED_RTG] parse rtg attr failed!\n");
return -INVALID_ARG;
}
}
if (!frame_info) {
pr_err("[SCHED_RTG] rtg attr: invalid args!\n");
return -INVALID_ARG;
}
ret = set_frame_rate(frame_info, rate);
if (ret)
return ret;
if (is_valid_type(type)) {
if (update_rt_frame_num(frame_info, type, UPDATE_RTG_FRAME)) {
pr_err("[SCHED_RTG] set rtg attr failed!\n");
return -INVALID_ARG;
}
set_frame_prio(frame_info, (type == NORMAL_TASK ?
NOT_RT_PRIO : (type + DEFAULT_RT_PRIO)));
}
return SUCC;
}
static long ctrl_set_rtg_attr(int abi, void __user *uarg)
{
struct rtg_str_data rs;
char temp[MAX_DATA_LEN];
int ret;
if (uarg == NULL)
return -INVALID_ARG;
if (copy_from_user(&rs, uarg, sizeof(rs))) {
pr_err("[SCHED_RTG] CMD_ID_SET_RTG_ATTR copy data failed\n");
return -INVALID_ARG;
}
if ((rs.len <= 0) || (rs.len >= MAX_DATA_LEN)) {
pr_err("[SCHED_RTG] CMD_ID_SET_RTG_ATTR data len invalid\n");
return -INVALID_ARG;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
switch (abi) {
case IOCTL_ABI_ARM32:
ret = copy_from_user(&temp,
(void __user *)compat_ptr((compat_uptr_t)rs.data), rs.len);
break;
case IOCTL_ABI_AARCH64:
ret = copy_from_user(&temp, (void __user *)rs.data, rs.len);
break;
default:
pr_err("[SCHED_RTG] abi format error\n");
return -INVALID_ARG;
}
#pragma GCC diagnostic pop
if (ret) {
pr_err("[SCHED_RTG] CMD_ID_SET_RTG_ATTR copy rs.data failed with ret %d\n", ret);
return -INVALID_ARG;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
temp[rs.len] = '\0';
rs.data = &temp;
#pragma GCC diagnostic pop
return parse_rtg_attr(&rs);
}
static void start_frame_freq(struct frame_info *frame_info)
{
if (!frame_info)
return;
if (atomic_read(&frame_info->start_frame_freq) == 0) {
atomic_set(&frame_info->start_frame_freq, 1);
set_frame_sched_state(frame_info, true);
}
}
static int set_frame(struct frame_info *frame_info, int margin)
{
int ret;
if (!frame_info)
return -INVALID_RTG_ID;
atomic_set(&frame_info->frame_state, FRAME_DRAWING);
ret = set_frame_margin(frame_info, margin);
if (ret)
goto out;
ret = set_frame_timestamp(frame_info, FRAME_START);
if (ret)
goto out;
out:
return ret;
}
static int reset_frame(struct frame_info *frame_info)
{
if (!frame_info)
return -INVALID_RTG_ID;
if (atomic_read(&frame_info->frame_state) == FRAME_END_STATE) {
pr_debug("[SCHED_RTG]: Frame state is already reset\n");
return -INVALID_PROC_STATE;
}
atomic_set(&frame_info->frame_state, FRAME_END_STATE);
return set_frame_timestamp(frame_info, FRAME_END);
}
int update_frame_state(int grp_id, int margin, bool in_frame)
{
int ret;
struct frame_info *frame_info = NULL;
frame_info = lookup_frame_info_by_grp_id(grp_id);
if (!frame_info || !frame_info->rtg)
return -INVALID_RTG_ID;
if (in_frame) {
start_frame_freq(frame_info);
ret = set_frame(frame_info, margin);
trace_rtg_frame_sched(grp_id, "margin", margin);
} else {
ret = reset_frame(frame_info);
}
return ret;
}
static inline int curr_grp_id()
{
return sched_get_group_id(current);
}
static long ctrl_frame_state(void __user *uarg, bool is_enter)
{
struct proc_state_data state_data;
if (uarg == NULL)
return -INVALID_ARG;
if (copy_from_user(&state_data, uarg, sizeof(state_data))) {
pr_err("[SCHED_RTG] CMD_ID_FRAME_FREQ copy data failed\n");
return -INVALID_ARG;
}
return update_frame_state(curr_grp_id(), state_data.state_param, is_enter);
}
static long ctrl_begin_frame(int abi, void __user *uarg)
{
return ctrl_frame_state(uarg, true);
}
static long ctrl_end_frame(int abi, void __user *uarg)
{
return ctrl_frame_state(uarg, false);
}
static int stop_frame_freq(int gid)
{
struct frame_info *frame_info = NULL;
frame_info = lookup_frame_info_by_grp_id(gid);
if (!frame_info)
return -INVALID_RTG_ID;
atomic_set(&frame_info->start_frame_freq, 0);
set_frame_sched_state(frame_info, false);
return 0;
}
static long ctrl_end_scene(int abi, void __user *uarg)
{
int rtg_id;
if (uarg == NULL)
return -INVALID_ARG;
if (copy_from_user(&rtg_id, uarg, sizeof(int))) {
pr_err("[SCHED_RTG] CMD_ID_END_SCENE copy data failed\n");
return -INVALID_ARG;
}
return stop_frame_freq(rtg_id);
}
static int set_min_util(int gid, int min_util)
{
struct frame_info *frame_info = NULL;
frame_info = lookup_frame_info_by_grp_id(gid);
if (!frame_info)
return -FRAME_ERR_PID;
return set_frame_min_util(frame_info, min_util, false);
}
static long ctrl_set_min_util(int abi, void __user *uarg)
{
struct proc_state_data state_data;
if (uarg == NULL)
return -INVALID_ARG;
if (copy_from_user(&state_data, uarg, sizeof(state_data))) {
pr_err("[SCHED_RTG] CMD_ID_SET_MIN_UTIL copy data failed\n");
return -INVALID_ARG;
}
return set_min_util(curr_grp_id(), state_data.state_param);
}
static int set_margin(int grp_id, int margin)
{
struct frame_info *frame_info = NULL;
frame_info = lookup_frame_info_by_grp_id(grp_id);
if (!frame_info)
return -FRAME_ERR_PID;
set_frame_margin(frame_info, margin);
return SUCC;
}
static long ctrl_set_margin(int abi, void __user *uarg)
{
struct proc_state_data state_data;
if (uarg == NULL)
return -INVALID_ARG;
if (copy_from_user(&state_data, uarg, sizeof(state_data))) {
pr_err("[SCHED_RTG] CMD_ID_SET_MARGIN copy data failed\n");
return -INVALID_ARG;
}
return set_margin(curr_grp_id(), state_data.state_param);
}
static void clear_rtg_frame_thread(struct frame_info *frame_info, bool reset)
{
struct frame_thread_info frame_thread_info;
int i;
if (!reset && frame_info)
frame_thread_info.prio = frame_info->prio;
else
frame_thread_info.prio = NOT_RT_PRIO;
for (i = 0; i < MAX_TID_NUM; i++)
frame_thread_info.thread[i] = -1;
frame_thread_info.thread_num = MAX_TID_NUM;
update_frame_thread_info(frame_info, &frame_thread_info);
if (reset) {
atomic_set(&frame_info->max_rt_thread_num, DEFAULT_MAX_RT_THREAD);
atomic_set(&frame_info->frame_sched_state, 0);
trace_rtg_frame_sched(frame_info->rtg->id, "FRAME_SCHED_ENABLE", 0);
}
}
static void copy_proc_from_rsdata(struct rtg_proc_data *proc_info,
const struct rtg_grp_data *rs_data)
{
memset(proc_info, 0, sizeof(struct rtg_proc_data));
proc_info->type = VIP;
proc_info->rtcnt = DEFAULT_MAX_RT_THREAD;
if ((rs_data->grp_type > 0) && (rs_data->grp_type < RTG_TYPE_MAX))
proc_info->type = rs_data->grp_type;
if ((rs_data->rt_cnt > 0) && (rs_data->rt_cnt < DEFAULT_MAX_RT_THREAD))
proc_info->rtcnt = rs_data->rt_cnt;
}
static void init_frame_thread_info(struct frame_thread_info *frame_thread_info,
const struct rtg_proc_data *proc_info)
{
int i;
int type = proc_info->type;
frame_thread_info->prio = (type == NORMAL_TASK ? NOT_RT_PRIO : (type + DEFAULT_RT_PRIO));
for (i = 0; i < MAX_TID_NUM; i++)
frame_thread_info->thread[i] = proc_info->thread[i];
frame_thread_info->thread_num = MAX_TID_NUM;
}
static int parse_create_rtg_grp(const struct rtg_grp_data *rs_data)
{
struct rtg_proc_data proc_info;
struct frame_info *frame_info;
struct frame_thread_info frame_thread_info;
copy_proc_from_rsdata(&proc_info, rs_data);
proc_info.rtgid = alloc_multi_frame_info();
frame_info = rtg_frame_info(proc_info.rtgid);
if (!frame_info) {
pr_err("[SCHED_RTG] no free multi frame.\n");
return -NO_FREE_MULTI_FRAME;
}
atomic_set(&frame_info->max_rt_thread_num, proc_info.rtcnt);
if (update_rt_frame_num(frame_info, rs_data->grp_type, ADD_RTG_FRAME)) {
release_multi_frame_info(proc_info.rtgid);
return -NO_RT_FRAME;
}
init_frame_thread_info(&frame_thread_info, &proc_info);
update_frame_thread_info(frame_info, &frame_thread_info);
atomic_set(&frame_info->frame_sched_state, 1);
pr_info("[SCHED_RTG] %s rtgid=%d, type=%d, prio=%d, threadnum=%d, rtnum=%d\n",
__func__, proc_info.rtgid, rs_data->grp_type,
frame_thread_info.prio, frame_thread_info.thread_num, proc_info.rtcnt);
return proc_info.rtgid;
}
static int parse_add_rtg_thread(const struct rtg_grp_data *rs_data)
{
struct rtg_proc_data proc_info;
struct frame_info *frame_info;
int add_index;
int add_num;
int prio;
int fail_num = 0;
int i;
if ((rs_data->grp_id <= 0) || (rs_data->grp_id >= MAX_NUM_CGROUP_COLOC_ID))
return -INVALID_ARG;
copy_proc_from_rsdata(&proc_info, rs_data);
frame_info = lookup_frame_info_by_grp_id(rs_data->grp_id);
if (!frame_info) {
pr_err("[SCHED_RTG] grp not created yet.\n");
return -INVALID_ARG;
}
mutex_lock(&frame_info->lock);
add_num = rs_data->tid_num;
if ((frame_info->thread_num < 0) || (add_num < 0)) {
mutex_unlock(&frame_info->lock);
pr_err("[SCHED_RTG] Unexception err: frame_info num < 0.\n");
return -INVALID_RTG_ID;
}
if (frame_info->thread_num + add_num > MAX_TID_NUM) {
mutex_unlock(&frame_info->lock);
return -INVALID_RTG_ID;
}
add_index = frame_info->thread_num;
prio = (proc_info.type == NORMAL_TASK) ? NOT_RT_PRIO : frame_info->prio;
for (i = 0; i < add_num; i++) {
frame_info->thread[add_index] = update_frame_thread(frame_info, prio, prio,
rs_data->tids[i],
frame_info->thread[add_index]);
if (frame_info->thread[add_index]) {
atomic_set(&frame_info->thread_prio[add_index], prio);
frame_info->thread_num++;
add_index = frame_info->thread_num;
} else {
fail_num++;
}
}
mutex_unlock(&frame_info->lock);
return fail_num;
}
static int parse_remove_thread(const struct rtg_grp_data *rs_data)
{
pr_err("[SCHED_RTG] frame rtg not support remove single yet.\n");
return -INVALID_ARG;
}
static int do_clear_or_destroy_grp(const struct rtg_grp_data *rs_data, bool destroy)
{
struct frame_info *frame_info;
int type;
int id = rs_data->grp_id;
if (!is_frame_rtg(id)) {
pr_err("[SCHED_RTG] Failed to destroy rtg group %d!\n", id);
return -INVALID_ARG;
}
frame_info = rtg_frame_info(id);
if (!frame_info) {
pr_err("[SCHED_RTG] Failed to destroy rtg group %d: grp not exist.\n", id);
return -INVALID_ARG;
}
type = frame_info->prio - DEFAULT_RT_PRIO;
if (destroy) {
clear_rtg_frame_thread(frame_info, true);
release_multi_frame_info(id);
update_rt_frame_num(frame_info, type, CLEAR_RTG_FRAME);
} else {
clear_rtg_frame_thread(frame_info, false);
}
pr_info("[SCHED_RTG] %s clear frame(id=%d)\n", __func__, id);
return SUCC;
}
static int parse_destroy_grp(const struct rtg_grp_data *rs_data)
{
return do_clear_or_destroy_grp(rs_data, true);
}
long ctrl_set_rtg(int abi, void __user *uarg)
{
struct rtg_grp_data rs_data;
long ret;
if (copy_from_user(&rs_data, uarg, sizeof(rs_data))) {
pr_err("[SCHED_RTG] CMD_ID_SET_RTG copy data failed\n");
return -INVALID_ARG;
}
switch (rs_data.rtg_cmd) {
case CMD_CREATE_RTG_GRP:
ret = parse_create_rtg_grp(&rs_data);
break;
case CMD_ADD_RTG_THREAD:
ret = parse_add_rtg_thread(&rs_data);
break;
case CMD_REMOVE_RTG_THREAD:
ret = parse_remove_thread(&rs_data);
break;
case CMD_CLEAR_RTG_GRP:
ret = -INVALID_ARG;
break;
case CMD_DESTROY_RTG_GRP:
ret = parse_destroy_grp(&rs_data);
break;
default:
return -INVALID_ARG;
}
return ret;
}
static long ctrl_search_rtg(int abi, void __user *uarg)
{
struct proc_state_data search_data;
if (copy_from_user(&search_data, uarg, sizeof(search_data))) {
pr_err("[SCHED_RTG] CMD_ID_SEARCH_RTG copy data failed\n");
return -INVALID_ARG;
}
return search_rtg(search_data.state_param);
}
static long do_proc_rtg_ioctl(int abi, struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *uarg = (void __user *)(uintptr_t)arg;
unsigned int func_id = _IOC_NR(cmd);
#ifdef CONFIG_RTG_AUTHORITY
bool authorized = true;
#endif
if (uarg == NULL) {
pr_err("[SCHED_RTG] %s: invalid user uarg\n", __func__);
return -EINVAL;
}
if (_IOC_TYPE(cmd) != RTG_SCHED_IPC_MAGIC) {
pr_err("[SCHED_RTG] %s: RTG_SCHED_IPC_MAGIC fail, TYPE=%d\n",
__func__, _IOC_TYPE(cmd));
return -INVALID_MAGIC;
}
if (!atomic_read(&g_rtg_enable) && (func_id != SET_ENABLE) && (func_id != GET_ENABLE)) {
pr_err("[SCHED_RTG] CMD_ID %x error: Rtg not enabled yet.\n", cmd);
return -RTG_DISABLED;
}
if (func_id >= RTG_CTRL_MAX_NR) {
pr_err("[SCHED_RTG] %s: RTG_MAX_NR fail, _IOC_NR(cmd)=%d, MAX_NR=%d\n",
__func__, _IOC_NR(cmd), RTG_CTRL_MAX_NR);
return -INVALID_CMD;
}
#ifdef CONFIG_RTG_AUTHORITY
authorized = check_authorized(func_id, RTG_AUTH_FLAG);
if (!authorized) {
pr_err("[SCHED_RTG] %s: uid not authorized.\n", __func__);
return -INVALID_CMD;
}
#endif
if (g_func_array[func_id] != NULL)
return (*g_func_array[func_id])(abi, uarg);
return -EINVAL;
}
static void reset_frame_info(struct frame_info *frame_info)
{
int i;
clear_rtg_frame_thread(frame_info, true);
atomic_set(&frame_info->frame_state, -1);
atomic_set(&frame_info->curr_rt_thread_num, 0);
atomic_set(&frame_info->max_rt_thread_num, DEFAULT_MAX_RT_THREAD);
for (i = 0; i < MAX_TID_NUM; i++)
atomic_set(&frame_info->thread_prio[i], 0);
}
static int do_init_proc_state(int rtgid, const int *config, int len)
{
struct related_thread_group *grp = NULL;
struct frame_info *frame_info = NULL;
grp = lookup_related_thread_group(rtgid);
if (unlikely(!grp))
return -EINVAL;
frame_info = (struct frame_info *)grp->private_data;
if (!frame_info)
return -EINVAL;
reset_frame_info(frame_info);
if ((config[RTG_FREQ_CYCLE] >= MIN_FREQ_CYCLE) &&
(config[RTG_FREQ_CYCLE] <= MAX_FREQ_CYCLE))
sched_set_group_freq_update_interval(rtgid,
(unsigned int)config[RTG_FREQ_CYCLE]);
else
sched_set_group_freq_update_interval(rtgid,
DEFAULT_FREQ_CYCLE);
if (config[RTG_INVALID_INTERVAL] != INVALID_VALUE)
sched_set_group_util_invalid_interval(rtgid,
config[RTG_INVALID_INTERVAL]);
else
sched_set_group_util_invalid_interval(rtgid,
DEFAULT_INVALID_INTERVAL);
set_frame_max_util(frame_info, g_frame_max_util);
return SUCC;
}
static int init_proc_state(const int *config, int len)
{
int ret;
int id;
if ((config == NULL) || (len != RTG_CONFIG_NUM))
return -INVALID_ARG;
if ((config[RTG_FRAME_MAX_UTIL] > 0) &&
(config[RTG_FRAME_MAX_UTIL] < DEFAULT_MAX_UTIL))
g_frame_max_util = config[RTG_FRAME_MAX_UTIL];
for (id = MULTI_FRAME_ID; id < (MULTI_FRAME_ID + MULTI_FRAME_NUM); id++) {
ret = do_init_proc_state(id, config, len);
if (ret) {
pr_err("[SCHED_RTG] init proc state for FRAME_ID=%d failed, ret=%d\n",
id, ret);
return ret;
}
}
atomic_set(&g_rt_frame_num, 0);
return SUCC;
}
static void deinit_proc_state(void)
{
int id;
struct frame_info *frame_info = NULL;
struct related_thread_group *grp = NULL;
for (id = MULTI_FRAME_ID; id < (MULTI_FRAME_ID + MULTI_FRAME_NUM); id++) {
grp = lookup_related_thread_group(id);
if (unlikely(!grp))
return;
frame_info = (struct frame_info *)grp->private_data;
if (frame_info)
reset_frame_info(frame_info);
}
clear_multi_frame_info();
atomic_set(&g_rt_frame_num, 0);
}
int proc_rtg_open(struct inode *inode, struct file *filp)
{
return SUCC;
}
static int proc_rtg_release(struct inode *inode, struct file *filp)
{
return SUCC;
}
long proc_rtg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return do_proc_rtg_ioctl(IOCTL_ABI_AARCH64, file, cmd, arg);
}
#ifdef CONFIG_COMPAT
long proc_rtg_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return do_proc_rtg_ioctl(IOCTL_ABI_ARM32, file, cmd,
(unsigned long)(compat_ptr((compat_uptr_t)arg)));
}
#endif
static const struct file_operations rtg_ctrl_fops = {
.open = proc_rtg_open,
.release = proc_rtg_release,
.unlocked_ioctl = proc_rtg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = proc_rtg_compat_ioctl,
#endif
};
static struct miscdevice rtg_ctrl_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sched_rtg_ctrl",
.fops = &rtg_ctrl_fops,
.mode = 0666,
};
static int __init rtg_ctrl_dev_init(void)
{
return misc_register(&rtg_ctrl_device);
}
static void __exit rtg_ctrl_dev_exit(void)
{
misc_deregister(&rtg_ctrl_device);
}
module_init(rtg_ctrl_dev_init);
module_exit(rtg_ctrl_dev_exit);