162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Frame-based load tracking for rt_frame and RTG 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Technologies Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "frame_rtg.h" 962306a36Sopenharmony_ci#include "rtg.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/sched.h> 1262306a36Sopenharmony_ci#include <trace/events/rtg.h> 1362306a36Sopenharmony_ci#include <../kernel/sched/sched.h> 1462306a36Sopenharmony_ci#include <uapi/linux/sched/types.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic struct multi_frame_id_manager g_id_manager = { 1762306a36Sopenharmony_ci .id_map = {0}, 1862306a36Sopenharmony_ci .offset = 0, 1962306a36Sopenharmony_ci .lock = __RW_LOCK_UNLOCKED(g_id_manager.lock) 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic struct frame_info g_multi_frame_info[MULTI_FRAME_NUM]; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic bool is_rtg_rt_task(struct task_struct *task) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci bool ret = false; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (!task) 2962306a36Sopenharmony_ci return ret; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci ret = ((task->prio < MAX_RT_PRIO) && 3262306a36Sopenharmony_ci (task->rtg_depth == STATIC_RTG_DEPTH)); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci return ret; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#ifdef CONFIG_SCHED_RTG_RT_THREAD_LIMIT 3862306a36Sopenharmony_cistatic atomic_t g_rtg_rt_thread_num = ATOMIC_INIT(0); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic unsigned int _get_rtg_rt_thread_num(struct related_thread_group *grp) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci unsigned int rtg_rt_thread_num = 0; 4362306a36Sopenharmony_ci struct task_struct *p = NULL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (list_empty(&grp->tasks)) 4662306a36Sopenharmony_ci goto out; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci list_for_each_entry(p, &grp->tasks, grp_list) { 4962306a36Sopenharmony_ci if (is_rtg_rt_task(p)) 5062306a36Sopenharmony_ci ++rtg_rt_thread_num; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciout: 5462306a36Sopenharmony_ci return rtg_rt_thread_num; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic unsigned int get_rtg_rt_thread_num(void) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct related_thread_group *grp = NULL; 6062306a36Sopenharmony_ci unsigned int total_rtg_rt_thread_num = 0; 6162306a36Sopenharmony_ci unsigned long flag; 6262306a36Sopenharmony_ci unsigned int i; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (i = MULTI_FRAME_ID; i < MULTI_FRAME_ID + MULTI_FRAME_NUM; i++) { 6562306a36Sopenharmony_ci grp = lookup_related_thread_group(i); 6662306a36Sopenharmony_ci if (grp == NULL) 6762306a36Sopenharmony_ci continue; 6862306a36Sopenharmony_ci raw_spin_lock_irqsave(&grp->lock, flag); 6962306a36Sopenharmony_ci total_rtg_rt_thread_num += _get_rtg_rt_thread_num(grp); 7062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&grp->lock, flag); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return total_rtg_rt_thread_num; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic void inc_rtg_rt_thread_num(void) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci atomic_inc(&g_rtg_rt_thread_num); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void dec_rtg_rt_thread_num(void) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci atomic_dec_if_positive(&g_rtg_rt_thread_num); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int test_and_read_rtg_rt_thread_num(void) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci if (atomic_read(&g_rtg_rt_thread_num) >= RTG_MAX_RT_THREAD_NUM) 8962306a36Sopenharmony_ci atomic_set(&g_rtg_rt_thread_num, get_rtg_rt_thread_num()); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return atomic_read(&g_rtg_rt_thread_num); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciint read_rtg_rt_thread_num(void) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return atomic_read(&g_rtg_rt_thread_num); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci#else 9962306a36Sopenharmony_cistatic inline void inc_rtg_rt_thread_num(void) { } 10062306a36Sopenharmony_cistatic inline void dec_rtg_rt_thread_num(void) { } 10162306a36Sopenharmony_cistatic inline int test_and_read_rtg_rt_thread_num(void) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cibool is_frame_rtg(int id) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return (id >= MULTI_FRAME_ID) && 11062306a36Sopenharmony_ci (id < (MULTI_FRAME_ID + MULTI_FRAME_NUM)); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic struct related_thread_group *frame_rtg(int id) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci if (!is_frame_rtg(id)) 11662306a36Sopenharmony_ci return NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return lookup_related_thread_group(id); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct frame_info *rtg_frame_info(int id) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (!is_frame_rtg(id)) 12462306a36Sopenharmony_ci return NULL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return rtg_active_multi_frame_info(id); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int alloc_rtg_id(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci unsigned int id_offset; 13262306a36Sopenharmony_ci int id; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci write_lock(&g_id_manager.lock); 13562306a36Sopenharmony_ci id_offset = find_next_zero_bit(g_id_manager.id_map, MULTI_FRAME_NUM, 13662306a36Sopenharmony_ci g_id_manager.offset); 13762306a36Sopenharmony_ci if (id_offset >= MULTI_FRAME_NUM) { 13862306a36Sopenharmony_ci id_offset = find_first_zero_bit(g_id_manager.id_map, 13962306a36Sopenharmony_ci MULTI_FRAME_NUM); 14062306a36Sopenharmony_ci if (id_offset >= MULTI_FRAME_NUM) { 14162306a36Sopenharmony_ci write_unlock(&g_id_manager.lock); 14262306a36Sopenharmony_ci return -EINVAL; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci set_bit(id_offset, g_id_manager.id_map); 14762306a36Sopenharmony_ci g_id_manager.offset = id_offset; 14862306a36Sopenharmony_ci id = id_offset + MULTI_FRAME_ID; 14962306a36Sopenharmony_ci write_unlock(&g_id_manager.lock); 15062306a36Sopenharmony_ci pr_debug("[FRAME_RTG] %s id_offset=%u, id=%d\n", __func__, id_offset, id); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return id; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void free_rtg_id(int id) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci unsigned int id_offset = id - MULTI_FRAME_ID; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (id_offset >= MULTI_FRAME_NUM) { 16062306a36Sopenharmony_ci pr_err("[FRAME_RTG] %s id_offset is invalid, id=%d, id_offset=%u.\n", 16162306a36Sopenharmony_ci __func__, id, id_offset); 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci pr_debug("[FRAME_RTG] %s id=%d id_offset=%u\n", __func__, id, id_offset); 16662306a36Sopenharmony_ci write_lock(&g_id_manager.lock); 16762306a36Sopenharmony_ci clear_bit(id_offset, g_id_manager.id_map); 16862306a36Sopenharmony_ci write_unlock(&g_id_manager.lock); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciint set_frame_rate(struct frame_info *frame_info, int rate) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int id; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if ((rate < MIN_FRAME_RATE) || (rate > MAX_FRAME_RATE)) { 17662306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s invalid QOS(rate) value\n", 17762306a36Sopenharmony_ci __func__); 17862306a36Sopenharmony_ci return -EINVAL; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (!frame_info || !frame_info->rtg) 18262306a36Sopenharmony_ci return -EINVAL; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci frame_info->frame_rate = (unsigned int)rate; 18562306a36Sopenharmony_ci frame_info->frame_time = div_u64(NSEC_PER_SEC, rate); 18662306a36Sopenharmony_ci frame_info->max_vload_time = 18762306a36Sopenharmony_ci div_u64(frame_info->frame_time, NSEC_PER_MSEC) + 18862306a36Sopenharmony_ci frame_info->vload_margin; 18962306a36Sopenharmony_ci id = frame_info->rtg->id; 19062306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_QOS", rate); 19162306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_MAX_TIME", frame_info->max_vload_time); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciint alloc_multi_frame_info(void) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct frame_info *frame_info = NULL; 19962306a36Sopenharmony_ci int id; 20062306a36Sopenharmony_ci int i; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci id = alloc_rtg_id(); 20362306a36Sopenharmony_ci if (id < 0) 20462306a36Sopenharmony_ci return id; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci frame_info = rtg_frame_info(id); 20762306a36Sopenharmony_ci if (!frame_info) { 20862306a36Sopenharmony_ci free_rtg_id(id); 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci set_frame_rate(frame_info, DEFAULT_FRAME_RATE); 21362306a36Sopenharmony_ci atomic_set(&frame_info->curr_rt_thread_num, 0); 21462306a36Sopenharmony_ci atomic_set(&frame_info->max_rt_thread_num, DEFAULT_MAX_RT_THREAD); 21562306a36Sopenharmony_ci for (i = 0; i < MAX_TID_NUM; i++) 21662306a36Sopenharmony_ci atomic_set(&frame_info->thread_prio[i], 0); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return id; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_civoid release_multi_frame_info(int id) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci if ((id < MULTI_FRAME_ID) || (id >= MULTI_FRAME_ID + MULTI_FRAME_NUM)) { 22462306a36Sopenharmony_ci pr_err("[FRAME_RTG] %s frame(id=%d) not found.\n", __func__, id); 22562306a36Sopenharmony_ci return; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci read_lock(&g_id_manager.lock); 22962306a36Sopenharmony_ci if (!test_bit(id - MULTI_FRAME_ID, g_id_manager.id_map)) { 23062306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 23162306a36Sopenharmony_ci return; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci pr_debug("[FRAME_RTG] %s release frame(id=%d).\n", __func__, id); 23662306a36Sopenharmony_ci free_rtg_id(id); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_civoid clear_multi_frame_info(void) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci write_lock(&g_id_manager.lock); 24262306a36Sopenharmony_ci bitmap_zero(g_id_manager.id_map, MULTI_FRAME_NUM); 24362306a36Sopenharmony_ci g_id_manager.offset = 0; 24462306a36Sopenharmony_ci write_unlock(&g_id_manager.lock); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistruct frame_info *rtg_active_multi_frame_info(int id) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct frame_info *frame_info = NULL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if ((id < MULTI_FRAME_ID) || (id >= MULTI_FRAME_ID + MULTI_FRAME_NUM)) 25262306a36Sopenharmony_ci return NULL; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci read_lock(&g_id_manager.lock); 25562306a36Sopenharmony_ci if (test_bit(id - MULTI_FRAME_ID, g_id_manager.id_map)) 25662306a36Sopenharmony_ci frame_info = &g_multi_frame_info[id - MULTI_FRAME_ID]; 25762306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 25862306a36Sopenharmony_ci if (!frame_info) 25962306a36Sopenharmony_ci pr_debug("[FRAME_RTG] %s frame %d has been released\n", 26062306a36Sopenharmony_ci __func__, id); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return frame_info; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistruct frame_info *rtg_multi_frame_info(int id) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci if ((id < MULTI_FRAME_ID) || (id >= MULTI_FRAME_ID + MULTI_FRAME_NUM)) 26862306a36Sopenharmony_ci return NULL; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return &g_multi_frame_info[id - MULTI_FRAME_ID]; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic void do_update_frame_task_prio(struct frame_info *frame_info, 27462306a36Sopenharmony_ci struct task_struct *task, int prio) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci int policy = SCHED_NORMAL; 27762306a36Sopenharmony_ci struct sched_param sp = {0}; 27862306a36Sopenharmony_ci bool is_rt_task = (prio != NOT_RT_PRIO); 27962306a36Sopenharmony_ci bool need_dec_flag = false; 28062306a36Sopenharmony_ci bool need_inc_flag = false; 28162306a36Sopenharmony_ci int err; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "rtg_rt_thread_num", 28462306a36Sopenharmony_ci read_rtg_rt_thread_num()); 28562306a36Sopenharmony_ci /* change policy to RT */ 28662306a36Sopenharmony_ci if (is_rt_task && (atomic_read(&frame_info->curr_rt_thread_num) < 28762306a36Sopenharmony_ci atomic_read(&frame_info->max_rt_thread_num))) { 28862306a36Sopenharmony_ci /* change policy from CFS to RT */ 28962306a36Sopenharmony_ci if (!is_rtg_rt_task(task)) { 29062306a36Sopenharmony_ci if (test_and_read_rtg_rt_thread_num() >= RTG_MAX_RT_THREAD_NUM) 29162306a36Sopenharmony_ci goto out; 29262306a36Sopenharmony_ci need_inc_flag = true; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci /* change RT priority */ 29562306a36Sopenharmony_ci policy = SCHED_FIFO | SCHED_RESET_ON_FORK; 29662306a36Sopenharmony_ci sp.sched_priority = MAX_USER_RT_PRIO - 1 - prio; 29762306a36Sopenharmony_ci atomic_inc(&frame_info->curr_rt_thread_num); 29862306a36Sopenharmony_ci } else { 29962306a36Sopenharmony_ci /* change policy from RT to CFS */ 30062306a36Sopenharmony_ci if (!is_rt_task && is_rtg_rt_task(task)) 30162306a36Sopenharmony_ci need_dec_flag = true; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ciout: 30462306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "rtg_rt_thread_num", 30562306a36Sopenharmony_ci read_rtg_rt_thread_num()); 30662306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "curr_rt_thread_num", 30762306a36Sopenharmony_ci atomic_read(&frame_info->curr_rt_thread_num)); 30862306a36Sopenharmony_ci err = sched_setscheduler_nocheck(task, policy, &sp); 30962306a36Sopenharmony_ci if (err == 0) { 31062306a36Sopenharmony_ci if (need_dec_flag) 31162306a36Sopenharmony_ci dec_rtg_rt_thread_num(); 31262306a36Sopenharmony_ci else if (need_inc_flag) 31362306a36Sopenharmony_ci inc_rtg_rt_thread_num(); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ciint list_rtg_group(struct rtg_info *rs_data) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci int i; 32062306a36Sopenharmony_ci int num = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci read_lock(&g_id_manager.lock); 32362306a36Sopenharmony_ci for (i = MULTI_FRAME_ID; i < MULTI_FRAME_ID + MULTI_FRAME_NUM; i++) { 32462306a36Sopenharmony_ci if (test_bit(i - MULTI_FRAME_ID, g_id_manager.id_map)) { 32562306a36Sopenharmony_ci rs_data->rtgs[num] = i; 32662306a36Sopenharmony_ci num++; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 33062306a36Sopenharmony_ci rs_data->rtg_num = num; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return num; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciint search_rtg(int pid) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct rtg_info grp_info; 33862306a36Sopenharmony_ci struct frame_info *frame_info = NULL; 33962306a36Sopenharmony_ci int i = 0; 34062306a36Sopenharmony_ci int j = 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci grp_info.rtg_num = 0; 34362306a36Sopenharmony_ci read_lock(&g_id_manager.lock); 34462306a36Sopenharmony_ci for (i = MULTI_FRAME_ID; i < MULTI_FRAME_ID + MULTI_FRAME_NUM; i++) { 34562306a36Sopenharmony_ci if (test_bit(i - MULTI_FRAME_ID, g_id_manager.id_map)) { 34662306a36Sopenharmony_ci grp_info.rtgs[grp_info.rtg_num] = i; 34762306a36Sopenharmony_ci grp_info.rtg_num++; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 35162306a36Sopenharmony_ci for (i = 0; i < grp_info.rtg_num; i++) { 35262306a36Sopenharmony_ci frame_info = lookup_frame_info_by_grp_id(grp_info.rtgs[i]); 35362306a36Sopenharmony_ci if (!frame_info) { 35462306a36Sopenharmony_ci pr_err("[FRAME_RTG] unexpected grp %d find error.", i); 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci for (j = 0; j < frame_info->thread_num; j++) { 35962306a36Sopenharmony_ci if (frame_info->thread[j] && frame_info->thread[j]->pid == pid) 36062306a36Sopenharmony_ci return grp_info.rtgs[i]; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void update_frame_task_prio(struct frame_info *frame_info, int prio) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci int i; 37062306a36Sopenharmony_ci struct task_struct *thread = NULL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* reset curr_rt_thread_num */ 37362306a36Sopenharmony_ci atomic_set(&frame_info->curr_rt_thread_num, 0); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (i = 0; i < MAX_TID_NUM; i++) { 37662306a36Sopenharmony_ci thread = frame_info->thread[i]; 37762306a36Sopenharmony_ci if (thread) 37862306a36Sopenharmony_ci do_update_frame_task_prio(frame_info, thread, prio); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_civoid set_frame_prio(struct frame_info *frame_info, int prio) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci if (!frame_info) 38562306a36Sopenharmony_ci return; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci mutex_lock(&frame_info->lock); 38862306a36Sopenharmony_ci if (frame_info->prio == prio) 38962306a36Sopenharmony_ci goto out; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci update_frame_task_prio(frame_info, prio); 39262306a36Sopenharmony_ci frame_info->prio = prio; 39362306a36Sopenharmony_ciout: 39462306a36Sopenharmony_ci mutex_unlock(&frame_info->lock); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int do_set_rtg_sched(struct task_struct *task, bool is_rtg, 39862306a36Sopenharmony_ci int grp_id, int prio) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int err; 40162306a36Sopenharmony_ci int policy = SCHED_NORMAL; 40262306a36Sopenharmony_ci int grpid = DEFAULT_RTG_GRP_ID; 40362306a36Sopenharmony_ci bool is_rt_task = (prio != NOT_RT_PRIO); 40462306a36Sopenharmony_ci struct sched_param sp = {0}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (is_rtg) { 40762306a36Sopenharmony_ci if (is_rt_task) { 40862306a36Sopenharmony_ci if (test_and_read_rtg_rt_thread_num() >= RTG_MAX_RT_THREAD_NUM) 40962306a36Sopenharmony_ci // rtg_rt_thread_num is inavailable, set policy to CFS 41062306a36Sopenharmony_ci goto skip_setpolicy; 41162306a36Sopenharmony_ci policy = SCHED_FIFO | SCHED_RESET_ON_FORK; 41262306a36Sopenharmony_ci sp.sched_priority = MAX_USER_RT_PRIO - 1 - prio; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ciskip_setpolicy: 41562306a36Sopenharmony_ci grpid = grp_id; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci err = sched_setscheduler_nocheck(task, policy, &sp); 41862306a36Sopenharmony_ci if (err < 0) { 41962306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s task:%d setscheduler err:%d\n", 42062306a36Sopenharmony_ci __func__, task->pid, err); 42162306a36Sopenharmony_ci return err; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci err = sched_set_group_id(task, grpid); 42462306a36Sopenharmony_ci if (err < 0) { 42562306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s task:%d set_group_id err:%d\n", 42662306a36Sopenharmony_ci __func__, task->pid, err); 42762306a36Sopenharmony_ci if (is_rtg) { 42862306a36Sopenharmony_ci policy = SCHED_NORMAL; 42962306a36Sopenharmony_ci sp.sched_priority = 0; 43062306a36Sopenharmony_ci sched_setscheduler_nocheck(task, policy, &sp); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci if (err == 0) { 43462306a36Sopenharmony_ci if (is_rtg) { 43562306a36Sopenharmony_ci if (policy != SCHED_NORMAL) 43662306a36Sopenharmony_ci inc_rtg_rt_thread_num(); 43762306a36Sopenharmony_ci } else { 43862306a36Sopenharmony_ci dec_rtg_rt_thread_num(); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return err; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int set_rtg_sched(struct task_struct *task, bool is_rtg, 44662306a36Sopenharmony_ci int grp_id, int prio) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci int err = -1; 44962306a36Sopenharmony_ci bool is_rt_task = (prio != NOT_RT_PRIO); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!task) 45262306a36Sopenharmony_ci return err; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (is_rt_task && is_rtg && ((prio < 0) || 45562306a36Sopenharmony_ci (prio > MAX_USER_RT_PRIO - 1))) 45662306a36Sopenharmony_ci return err; 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * original logic deny the non-cfs task st rt. 45962306a36Sopenharmony_ci * add !fair_policy(task->policy) if needed 46062306a36Sopenharmony_ci * 46162306a36Sopenharmony_ci * if CONFIG_HW_FUTEX_PI is set, task->prio and task->sched_class 46262306a36Sopenharmony_ci * may be modified by rtmutex. So we use task->policy instead. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci if (is_rtg && task->flags & PF_EXITING) 46562306a36Sopenharmony_ci return err; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (in_interrupt()) { 46862306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s is in interrupt\n", __func__); 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return do_set_rtg_sched(task, is_rtg, grp_id, prio); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic bool set_frame_rtg_thread(int grp_id, struct task_struct *task, 47662306a36Sopenharmony_ci bool is_rtg, int prio) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci int depth; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (!task) 48162306a36Sopenharmony_ci return false; 48262306a36Sopenharmony_ci depth = task->rtg_depth; 48362306a36Sopenharmony_ci if (is_rtg) 48462306a36Sopenharmony_ci task->rtg_depth = STATIC_RTG_DEPTH; 48562306a36Sopenharmony_ci else 48662306a36Sopenharmony_ci task->rtg_depth = 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (set_rtg_sched(task, is_rtg, grp_id, prio) < 0) { 48962306a36Sopenharmony_ci task->rtg_depth = depth; 49062306a36Sopenharmony_ci return false; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return true; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistruct task_struct *update_frame_thread(struct frame_info *frame_info, 49762306a36Sopenharmony_ci int old_prio, int prio, int pid, 49862306a36Sopenharmony_ci struct task_struct *old_task) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct task_struct *task = NULL; 50162306a36Sopenharmony_ci bool is_rt_task = (prio != NOT_RT_PRIO); 50262306a36Sopenharmony_ci int new_prio = prio; 50362306a36Sopenharmony_ci bool update_ret = false; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (pid > 0) { 50662306a36Sopenharmony_ci if (old_task && (pid == old_task->pid) && (old_prio == new_prio)) { 50762306a36Sopenharmony_ci if (is_rt_task && atomic_read(&frame_info->curr_rt_thread_num) < 50862306a36Sopenharmony_ci atomic_read(&frame_info->max_rt_thread_num) && 50962306a36Sopenharmony_ci (atomic_read(&frame_info->frame_sched_state) == 1)) 51062306a36Sopenharmony_ci atomic_inc(&frame_info->curr_rt_thread_num); 51162306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "curr_rt_thread_num", 51262306a36Sopenharmony_ci atomic_read(&frame_info->curr_rt_thread_num)); 51362306a36Sopenharmony_ci return old_task; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci rcu_read_lock(); 51662306a36Sopenharmony_ci task = find_task_by_vpid(pid); 51762306a36Sopenharmony_ci if (task) 51862306a36Sopenharmony_ci get_task_struct(task); 51962306a36Sopenharmony_ci rcu_read_unlock(); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "FRAME_SCHED_ENABLE", 52262306a36Sopenharmony_ci atomic_read(&frame_info->frame_sched_state)); 52362306a36Sopenharmony_ci if (atomic_read(&frame_info->frame_sched_state) == 1) { 52462306a36Sopenharmony_ci if (task && is_rt_task) { 52562306a36Sopenharmony_ci if (atomic_read(&frame_info->curr_rt_thread_num) < 52662306a36Sopenharmony_ci atomic_read(&frame_info->max_rt_thread_num)) 52762306a36Sopenharmony_ci atomic_inc(&frame_info->curr_rt_thread_num); 52862306a36Sopenharmony_ci else 52962306a36Sopenharmony_ci new_prio = NOT_RT_PRIO; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "curr_rt_thread_num", 53262306a36Sopenharmony_ci atomic_read(&frame_info->curr_rt_thread_num)); 53362306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "rtg_rt_thread_num", 53462306a36Sopenharmony_ci read_rtg_rt_thread_num()); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci set_frame_rtg_thread(frame_info->rtg->id, old_task, false, NOT_RT_PRIO); 53762306a36Sopenharmony_ci update_ret = set_frame_rtg_thread(frame_info->rtg->id, task, true, new_prio); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci if (old_task) 54062306a36Sopenharmony_ci put_task_struct(old_task); 54162306a36Sopenharmony_ci if (!update_ret) 54262306a36Sopenharmony_ci return NULL; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return task; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_civoid update_frame_thread_info(struct frame_info *frame_info, 54862306a36Sopenharmony_ci struct frame_thread_info *frame_thread_info) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci int i; 55162306a36Sopenharmony_ci int old_prio; 55262306a36Sopenharmony_ci int prio; 55362306a36Sopenharmony_ci int thread_num; 55462306a36Sopenharmony_ci int real_thread; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (!frame_info || !frame_thread_info || 55762306a36Sopenharmony_ci frame_thread_info->thread_num < 0) 55862306a36Sopenharmony_ci return; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci prio = frame_thread_info->prio; 56162306a36Sopenharmony_ci thread_num = frame_thread_info->thread_num; 56262306a36Sopenharmony_ci if (thread_num > MAX_TID_NUM) 56362306a36Sopenharmony_ci thread_num = MAX_TID_NUM; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci // reset curr_rt_thread_num 56662306a36Sopenharmony_ci atomic_set(&frame_info->curr_rt_thread_num, 0); 56762306a36Sopenharmony_ci mutex_lock(&frame_info->lock); 56862306a36Sopenharmony_ci old_prio = frame_info->prio; 56962306a36Sopenharmony_ci real_thread = 0; 57062306a36Sopenharmony_ci for (i = 0; i < thread_num; i++) { 57162306a36Sopenharmony_ci atomic_set(&frame_info->thread_prio[i], 0); 57262306a36Sopenharmony_ci frame_info->thread[i] = update_frame_thread(frame_info, old_prio, prio, 57362306a36Sopenharmony_ci frame_thread_info->thread[i], 57462306a36Sopenharmony_ci frame_info->thread[i]); 57562306a36Sopenharmony_ci if (frame_info->thread[i] && (frame_thread_info->thread[i] > 0)) 57662306a36Sopenharmony_ci real_thread++; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci frame_info->prio = prio; 57962306a36Sopenharmony_ci frame_info->thread_num = real_thread; 58062306a36Sopenharmony_ci mutex_unlock(&frame_info->lock); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic void do_set_frame_sched_state(struct frame_info *frame_info, 58462306a36Sopenharmony_ci struct task_struct *task, 58562306a36Sopenharmony_ci bool enable, int prio) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci int new_prio = prio; 58862306a36Sopenharmony_ci bool is_rt_task = (prio != NOT_RT_PRIO); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (enable && is_rt_task) { 59162306a36Sopenharmony_ci if (atomic_read(&frame_info->curr_rt_thread_num) < 59262306a36Sopenharmony_ci atomic_read(&frame_info->max_rt_thread_num)) 59362306a36Sopenharmony_ci atomic_inc(&frame_info->curr_rt_thread_num); 59462306a36Sopenharmony_ci else 59562306a36Sopenharmony_ci new_prio = NOT_RT_PRIO; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "curr_rt_thread_num", 59862306a36Sopenharmony_ci atomic_read(&frame_info->curr_rt_thread_num)); 59962306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "rtg_rt_thread_num", 60062306a36Sopenharmony_ci read_rtg_rt_thread_num()); 60162306a36Sopenharmony_ci set_frame_rtg_thread(frame_info->rtg->id, task, enable, new_prio); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_civoid set_frame_sched_state(struct frame_info *frame_info, bool enable) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci atomic_t *frame_sched_state = NULL; 60762306a36Sopenharmony_ci int prio; 60862306a36Sopenharmony_ci int i; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (!frame_info || !frame_info->rtg) 61162306a36Sopenharmony_ci return; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci frame_sched_state = &(frame_info->frame_sched_state); 61462306a36Sopenharmony_ci if (enable) { 61562306a36Sopenharmony_ci if (atomic_read(frame_sched_state) == 1) 61662306a36Sopenharmony_ci return; 61762306a36Sopenharmony_ci atomic_set(frame_sched_state, 1); 61862306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "FRAME_SCHED_ENABLE", 1); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci frame_info->prev_fake_load_util = 0; 62162306a36Sopenharmony_ci frame_info->prev_frame_load_util = 0; 62262306a36Sopenharmony_ci frame_info->frame_vload = 0; 62362306a36Sopenharmony_ci frame_info_rtg_load(frame_info)->curr_window_load = 0; 62462306a36Sopenharmony_ci } else { 62562306a36Sopenharmony_ci if (atomic_read(frame_sched_state) == 0) 62662306a36Sopenharmony_ci return; 62762306a36Sopenharmony_ci atomic_set(frame_sched_state, 0); 62862306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "FRAME_SCHED_ENABLE", 0); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci (void)sched_set_group_normalized_util(frame_info->rtg->id, 63162306a36Sopenharmony_ci 0, RTG_FREQ_NORMAL_UPDATE); 63262306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "preferred_cluster", 63362306a36Sopenharmony_ci INVALID_PREFERRED_CLUSTER); 63462306a36Sopenharmony_ci frame_info->status = FRAME_END; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* reset curr_rt_thread_num */ 63862306a36Sopenharmony_ci atomic_set(&frame_info->curr_rt_thread_num, 0); 63962306a36Sopenharmony_ci mutex_lock(&frame_info->lock); 64062306a36Sopenharmony_ci for (i = 0; i < MAX_TID_NUM; i++) { 64162306a36Sopenharmony_ci if (frame_info->thread[i]) { 64262306a36Sopenharmony_ci prio = atomic_read(&frame_info->thread_prio[i]); 64362306a36Sopenharmony_ci do_set_frame_sched_state(frame_info, frame_info->thread[i], 64462306a36Sopenharmony_ci enable, prio); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci mutex_unlock(&frame_info->lock); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "FRAME_STATUS", 65062306a36Sopenharmony_ci frame_info->status); 65162306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "frame_status", 65262306a36Sopenharmony_ci frame_info->status); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic inline bool check_frame_util_invalid(const struct frame_info *frame_info, 65662306a36Sopenharmony_ci u64 timeline) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci return ((frame_info_rtg(frame_info)->util_invalid_interval <= timeline) && 65962306a36Sopenharmony_ci (frame_info_rtg_load(frame_info)->curr_window_exec * FRAME_UTIL_INVALID_FACTOR 66062306a36Sopenharmony_ci <= timeline)); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic u64 calc_prev_fake_load_util(const struct frame_info *frame_info) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci u64 prev_frame_load = frame_info->prev_frame_load; 66662306a36Sopenharmony_ci u64 prev_frame_time = max_t(unsigned long, frame_info->prev_frame_time, 66762306a36Sopenharmony_ci frame_info->frame_time); 66862306a36Sopenharmony_ci u64 frame_util = 0; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (prev_frame_time > 0) 67162306a36Sopenharmony_ci frame_util = div_u64((prev_frame_load << SCHED_CAPACITY_SHIFT), 67262306a36Sopenharmony_ci prev_frame_time); 67362306a36Sopenharmony_ci frame_util = clamp_t(unsigned long, frame_util, 67462306a36Sopenharmony_ci frame_info->prev_min_util, 67562306a36Sopenharmony_ci frame_info->prev_max_util); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return frame_util; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic u64 calc_prev_frame_load_util(const struct frame_info *frame_info) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci u64 prev_frame_load = frame_info->prev_frame_load; 68362306a36Sopenharmony_ci u64 frame_time = frame_info->frame_time; 68462306a36Sopenharmony_ci u64 frame_util = 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (prev_frame_load >= frame_time) 68762306a36Sopenharmony_ci frame_util = FRAME_MAX_LOAD; 68862306a36Sopenharmony_ci else 68962306a36Sopenharmony_ci frame_util = div_u64((prev_frame_load << SCHED_CAPACITY_SHIFT), 69062306a36Sopenharmony_ci frame_info->frame_time); 69162306a36Sopenharmony_ci frame_util = clamp_t(unsigned long, frame_util, 69262306a36Sopenharmony_ci frame_info->prev_min_util, 69362306a36Sopenharmony_ci frame_info->prev_max_util); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return frame_util; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* last frame load tracking */ 69962306a36Sopenharmony_cistatic void update_frame_prev_load(struct frame_info *frame_info, bool fake) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci /* last frame load tracking */ 70262306a36Sopenharmony_ci frame_info->prev_frame_exec = 70362306a36Sopenharmony_ci frame_info_rtg_load(frame_info)->prev_window_exec; 70462306a36Sopenharmony_ci frame_info->prev_frame_time = 70562306a36Sopenharmony_ci frame_info_rtg(frame_info)->prev_window_time; 70662306a36Sopenharmony_ci frame_info->prev_frame_load = 70762306a36Sopenharmony_ci frame_info_rtg_load(frame_info)->prev_window_load; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (fake) 71062306a36Sopenharmony_ci frame_info->prev_fake_load_util = 71162306a36Sopenharmony_ci calc_prev_fake_load_util(frame_info); 71262306a36Sopenharmony_ci else 71362306a36Sopenharmony_ci frame_info->prev_frame_load_util = 71462306a36Sopenharmony_ci calc_prev_frame_load_util(frame_info); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic void do_frame_end(struct frame_info *frame_info, bool fake) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci unsigned long prev_util; 72062306a36Sopenharmony_ci int id = frame_info->rtg->id; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci frame_info->status = FRAME_END; 72362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_status", frame_info->status); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* last frame load tracking */ 72662306a36Sopenharmony_ci update_frame_prev_load(frame_info, fake); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* reset frame_info */ 72962306a36Sopenharmony_ci frame_info->frame_vload = 0; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* reset frame_min_util */ 73262306a36Sopenharmony_ci frame_info->frame_min_util = 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (fake) 73562306a36Sopenharmony_ci prev_util = frame_info->prev_fake_load_util; 73662306a36Sopenharmony_ci else 73762306a36Sopenharmony_ci prev_util = frame_info->prev_frame_load_util; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci frame_info->frame_util = clamp_t(unsigned long, prev_util, 74062306a36Sopenharmony_ci frame_info->frame_min_util, 74162306a36Sopenharmony_ci frame_info->frame_max_util); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_task_time", 74462306a36Sopenharmony_ci frame_info->prev_frame_exec); 74562306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_time", frame_info->prev_frame_time); 74662306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_load", frame_info->prev_frame_load); 74762306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_load_util", 74862306a36Sopenharmony_ci frame_info->prev_frame_load_util); 74962306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_util", frame_info->frame_util); 75062306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_vload", frame_info->frame_vload); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci/* 75462306a36Sopenharmony_ci * frame_load : calculate frame load using exec util 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_cistatic inline u64 calc_frame_exec(const struct frame_info *frame_info) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci if (frame_info->frame_time > 0) 75962306a36Sopenharmony_ci return div_u64((frame_info_rtg_load(frame_info)->curr_window_exec << 76062306a36Sopenharmony_ci SCHED_CAPACITY_SHIFT), frame_info->frame_time); 76162306a36Sopenharmony_ci else 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/* 76662306a36Sopenharmony_ci * real_util: 76762306a36Sopenharmony_ci * max(last_util, virtual_util, boost_util, phase_util, frame_min_util) 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_cistatic u64 calc_frame_util(const struct frame_info *frame_info, bool fake) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci unsigned long load_util; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (fake) 77462306a36Sopenharmony_ci load_util = frame_info->prev_fake_load_util; 77562306a36Sopenharmony_ci else 77662306a36Sopenharmony_ci load_util = frame_info->prev_frame_load_util; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci load_util = max_t(unsigned long, load_util, frame_info->frame_vload); 77962306a36Sopenharmony_ci load_util = clamp_t(unsigned long, load_util, 78062306a36Sopenharmony_ci frame_info->frame_min_util, 78162306a36Sopenharmony_ci frame_info->frame_max_util); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return load_util; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/* 78762306a36Sopenharmony_ci * frame_vload [0~1024] 78862306a36Sopenharmony_ci * vtime: now - timestamp 78962306a36Sopenharmony_ci * max_time: frame_info->frame_time + vload_margin 79062306a36Sopenharmony_ci * load = F(vtime) 79162306a36Sopenharmony_ci * = vtime ^ 2 - vtime * max_time + FRAME_MAX_VLOAD * vtime / max_time; 79262306a36Sopenharmony_ci * = vtime * (vtime + FRAME_MAX_VLOAD / max_time - max_time); 79362306a36Sopenharmony_ci * [0, 0] -=> [max_time, FRAME_MAX_VLOAD] 79462306a36Sopenharmony_ci * 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_cistatic u64 calc_frame_vload(const struct frame_info *frame_info, u64 timeline) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci u64 vload; 79962306a36Sopenharmony_ci int vtime = div_u64(timeline, NSEC_PER_MSEC); 80062306a36Sopenharmony_ci int max_time = frame_info->max_vload_time; 80162306a36Sopenharmony_ci int factor; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if ((max_time <= 0) || (vtime > max_time)) 80462306a36Sopenharmony_ci return FRAME_MAX_VLOAD; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci factor = vtime + FRAME_MAX_VLOAD / max_time; 80762306a36Sopenharmony_ci /* margin maybe negative */ 80862306a36Sopenharmony_ci if ((vtime <= 0) || (factor <= max_time)) 80962306a36Sopenharmony_ci return 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci vload = (u64)vtime * (u64)(factor - max_time); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return vload; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic int update_frame_info_tick_inner(int id, struct frame_info *frame_info, 81762306a36Sopenharmony_ci u64 timeline) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci switch (frame_info->status) { 82062306a36Sopenharmony_ci case FRAME_INVALID: 82162306a36Sopenharmony_ci case FRAME_END: 82262306a36Sopenharmony_ci if (timeline >= frame_info->frame_time) { 82362306a36Sopenharmony_ci /* 82462306a36Sopenharmony_ci * fake FRAME_END here to rollover frame_window. 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_ci sched_set_group_window_rollover(id); 82762306a36Sopenharmony_ci do_frame_end(frame_info, true); 82862306a36Sopenharmony_ci } else { 82962306a36Sopenharmony_ci frame_info->frame_vload = calc_frame_exec(frame_info); 83062306a36Sopenharmony_ci frame_info->frame_util = 83162306a36Sopenharmony_ci calc_frame_util(frame_info, true); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* when not in boost, start tick timer */ 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci case FRAME_START: 83762306a36Sopenharmony_ci /* check frame_util invalid */ 83862306a36Sopenharmony_ci if (!check_frame_util_invalid(frame_info, timeline)) { 83962306a36Sopenharmony_ci /* frame_vload statistic */ 84062306a36Sopenharmony_ci frame_info->frame_vload = calc_frame_vload(frame_info, timeline); 84162306a36Sopenharmony_ci /* frame_util statistic */ 84262306a36Sopenharmony_ci frame_info->frame_util = 84362306a36Sopenharmony_ci calc_frame_util(frame_info, false); 84462306a36Sopenharmony_ci } else { 84562306a36Sopenharmony_ci frame_info->status = FRAME_INVALID; 84662306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_STATUS", 84762306a36Sopenharmony_ci frame_info->status); 84862306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_status", 84962306a36Sopenharmony_ci frame_info->status); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* 85262306a36Sopenharmony_ci * trigger FRAME_END to rollover frame_window, 85362306a36Sopenharmony_ci * we treat FRAME_INVALID as FRAME_END. 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_ci sched_set_group_window_rollover(id); 85662306a36Sopenharmony_ci do_frame_end(frame_info, false); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci default: 86062306a36Sopenharmony_ci return -EINVAL; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic inline struct frame_info *rtg_frame_info_inner( 86762306a36Sopenharmony_ci const struct related_thread_group *grp) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci return (struct frame_info *)grp->private_data; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic inline void frame_boost(struct frame_info *frame_info) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci if (frame_info->frame_util < frame_info->frame_boost_min_util) 87562306a36Sopenharmony_ci frame_info->frame_util = frame_info->frame_boost_min_util; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci/* 87962306a36Sopenharmony_ci * update CPUFREQ and PLACEMENT when frame task running (in tick) and migration 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_cistatic void update_frame_info_tick(struct related_thread_group *grp) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci u64 window_start; 88462306a36Sopenharmony_ci u64 wallclock; 88562306a36Sopenharmony_ci u64 timeline; 88662306a36Sopenharmony_ci struct frame_info *frame_info = NULL; 88762306a36Sopenharmony_ci int id = grp->id; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci rcu_read_lock(); 89062306a36Sopenharmony_ci frame_info = rtg_frame_info_inner(grp); 89162306a36Sopenharmony_ci window_start = grp->window_start; 89262306a36Sopenharmony_ci rcu_read_unlock(); 89362306a36Sopenharmony_ci if (unlikely(!frame_info)) 89462306a36Sopenharmony_ci return; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (atomic_read(&frame_info->frame_sched_state) == 0) 89762306a36Sopenharmony_ci return; 89862306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_status", frame_info->status); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci wallclock = ktime_get_ns(); 90162306a36Sopenharmony_ci timeline = wallclock - window_start; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "update_curr_pid", current->pid); 90462306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_timeline", div_u64(timeline, NSEC_PER_MSEC)); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (update_frame_info_tick_inner(grp->id, frame_info, timeline) == -EINVAL) 90762306a36Sopenharmony_ci return; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci frame_boost(frame_info); 91062306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_vload", frame_info->frame_vload); 91162306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_util", frame_info->frame_util); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci sched_set_group_normalized_util(grp->id, 91462306a36Sopenharmony_ci frame_info->frame_util, RTG_FREQ_NORMAL_UPDATE); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (grp->preferred_cluster) 91762306a36Sopenharmony_ci trace_rtg_frame_sched(id, "preferred_cluster", 91862306a36Sopenharmony_ci grp->preferred_cluster->id); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ciconst struct rtg_class frame_rtg_class = { 92262306a36Sopenharmony_ci .sched_update_rtg_tick = update_frame_info_tick, 92362306a36Sopenharmony_ci}; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ciint set_frame_margin(struct frame_info *frame_info, int margin) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci int id; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if ((margin < MIN_VLOAD_MARGIN) || (margin > MAX_VLOAD_MARGIN)) { 93062306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s invalid MARGIN value\n", 93162306a36Sopenharmony_ci __func__); 93262306a36Sopenharmony_ci return -EINVAL; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (!frame_info || !frame_info->rtg) 93662306a36Sopenharmony_ci return -EINVAL; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci frame_info->vload_margin = margin; 93962306a36Sopenharmony_ci frame_info->max_vload_time = 94062306a36Sopenharmony_ci div_u64(frame_info->frame_time, NSEC_PER_MSEC) + 94162306a36Sopenharmony_ci frame_info->vload_margin; 94262306a36Sopenharmony_ci id = frame_info->rtg->id; 94362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_MARGIN", -margin); 94462306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_MAX_TIME", frame_info->max_vload_time); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic void set_frame_start(struct frame_info *frame_info) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci int id = frame_info->rtg->id; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (likely(frame_info->status == FRAME_START)) { 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * START -=> START -=> ...... 95662306a36Sopenharmony_ci * FRMAE_START is 95762306a36Sopenharmony_ci * the end of last frame 95862306a36Sopenharmony_ci * the start of the current frame 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_ci update_frame_prev_load(frame_info, false); 96162306a36Sopenharmony_ci } else if ((frame_info->status == FRAME_END) || 96262306a36Sopenharmony_ci (frame_info->status == FRAME_INVALID)) { 96362306a36Sopenharmony_ci /* START -=> END -=> [START] 96462306a36Sopenharmony_ci * FRAME_START is 96562306a36Sopenharmony_ci * only the start of current frame 96662306a36Sopenharmony_ci * we shoudn't tracking the last rtg-window 96762306a36Sopenharmony_ci * [FRAME_END, FRAME_START] 96862306a36Sopenharmony_ci * it's not an available frame window 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ci update_frame_prev_load(frame_info, true); 97162306a36Sopenharmony_ci frame_info->status = FRAME_START; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_STATUS", frame_info->status); 97462306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_task_time", 97562306a36Sopenharmony_ci frame_info->prev_frame_exec); 97662306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_time", frame_info->prev_frame_time); 97762306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_load", frame_info->prev_frame_load); 97862306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_last_load_util", 97962306a36Sopenharmony_ci frame_info->prev_frame_load_util); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* new_frame_start */ 98262306a36Sopenharmony_ci if (!frame_info->margin_imme) { 98362306a36Sopenharmony_ci frame_info->frame_vload = 0; 98462306a36Sopenharmony_ci frame_info->frame_util = clamp_t(unsigned long, 98562306a36Sopenharmony_ci frame_info->prev_frame_load_util, 98662306a36Sopenharmony_ci frame_info->frame_min_util, 98762306a36Sopenharmony_ci frame_info->frame_max_util); 98862306a36Sopenharmony_ci } else { 98962306a36Sopenharmony_ci frame_info->frame_vload = calc_frame_vload(frame_info, 0); 99062306a36Sopenharmony_ci frame_info->frame_util = calc_frame_util(frame_info, false); 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_vload", frame_info->frame_vload); 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic void set_frame_end(struct frame_info *frame_info) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci trace_rtg_frame_sched(frame_info->rtg->id, "FRAME_STATUS", FRAME_END); 99962306a36Sopenharmony_ci do_frame_end(frame_info, false); 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic int update_frame_timestamp(unsigned long status, 100362306a36Sopenharmony_ci struct frame_info *frame_info, struct related_thread_group *grp) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci int id = frame_info->rtg->id; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci /* SCHED_FRAME timestamp */ 100862306a36Sopenharmony_ci switch (status) { 100962306a36Sopenharmony_ci case FRAME_START: 101062306a36Sopenharmony_ci /* collect frame_info when frame_end timestamp coming */ 101162306a36Sopenharmony_ci set_frame_start(frame_info); 101262306a36Sopenharmony_ci break; 101362306a36Sopenharmony_ci case FRAME_END: 101462306a36Sopenharmony_ci /* FRAME_END should only set and update freq once */ 101562306a36Sopenharmony_ci if (unlikely(frame_info->status == FRAME_END)) 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci set_frame_end(frame_info); 101862306a36Sopenharmony_ci break; 101962306a36Sopenharmony_ci default: 102062306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s invalid timestamp(status)\n", 102162306a36Sopenharmony_ci __func__); 102262306a36Sopenharmony_ci return -EINVAL; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci frame_boost(frame_info); 102662306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_util", frame_info->frame_util); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* update cpufreq force when frame_stop */ 102962306a36Sopenharmony_ci sched_set_group_normalized_util(grp->id, 103062306a36Sopenharmony_ci frame_info->frame_util, RTG_FREQ_FORCE_UPDATE); 103162306a36Sopenharmony_ci if (grp->preferred_cluster) 103262306a36Sopenharmony_ci trace_rtg_frame_sched(id, "preferred_cluster", 103362306a36Sopenharmony_ci grp->preferred_cluster->id); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci return 0; 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic int set_frame_status(struct frame_info *frame_info, unsigned long status) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct related_thread_group *grp = NULL; 104162306a36Sopenharmony_ci int id; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (!frame_info) 104462306a36Sopenharmony_ci return -EINVAL; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci grp = frame_info->rtg; 104762306a36Sopenharmony_ci if (unlikely(!grp)) 104862306a36Sopenharmony_ci return -EINVAL; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (atomic_read(&frame_info->frame_sched_state) == 0) 105162306a36Sopenharmony_ci return -EINVAL; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (!(status & FRAME_SETTIME) || 105462306a36Sopenharmony_ci (status == (unsigned long)FRAME_SETTIME_PARAM)) { 105562306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s invalid timetsamp(status)\n", 105662306a36Sopenharmony_ci __func__); 105762306a36Sopenharmony_ci return -EINVAL; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (status & FRAME_TIMESTAMP_SKIP_START) { 106162306a36Sopenharmony_ci frame_info->timestamp_skipped = true; 106262306a36Sopenharmony_ci status &= ~FRAME_TIMESTAMP_SKIP_START; 106362306a36Sopenharmony_ci } else if (status & FRAME_TIMESTAMP_SKIP_END) { 106462306a36Sopenharmony_ci frame_info->timestamp_skipped = false; 106562306a36Sopenharmony_ci status &= ~FRAME_TIMESTAMP_SKIP_END; 106662306a36Sopenharmony_ci } else if (frame_info->timestamp_skipped) { 106762306a36Sopenharmony_ci /* 106862306a36Sopenharmony_ci * skip the following timestamp until 106962306a36Sopenharmony_ci * FRAME_TIMESTAMP_SKIPPED reset 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_ci return 0; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci id = grp->id; 107462306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_TIMESTAMP_SKIPPED", 107562306a36Sopenharmony_ci frame_info->timestamp_skipped); 107662306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_MAX_UTIL", frame_info->frame_max_util); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if (status & FRAME_USE_MARGIN_IMME) { 107962306a36Sopenharmony_ci frame_info->margin_imme = true; 108062306a36Sopenharmony_ci status &= ~FRAME_USE_MARGIN_IMME; 108162306a36Sopenharmony_ci } else { 108262306a36Sopenharmony_ci frame_info->margin_imme = false; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_MARGIN_IMME", frame_info->margin_imme); 108562306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_TIMESTAMP", status); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci return update_frame_timestamp(status, frame_info, grp); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ciint set_frame_timestamp(struct frame_info *frame_info, unsigned long timestamp) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci int ret; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (!frame_info || !frame_info->rtg) 109562306a36Sopenharmony_ci return -EINVAL; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (atomic_read(&frame_info->frame_sched_state) == 0) 109862306a36Sopenharmony_ci return -EINVAL; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci ret = sched_set_group_window_rollover(frame_info->rtg->id); 110162306a36Sopenharmony_ci if (!ret) 110262306a36Sopenharmony_ci ret = set_frame_status(frame_info, timestamp); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci return ret; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ciint set_frame_min_util(struct frame_info *frame_info, int min_util, bool is_boost) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci int id; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (unlikely((min_util < 0) || (min_util > SCHED_CAPACITY_SCALE))) { 111262306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s invalid min_util value\n", 111362306a36Sopenharmony_ci __func__); 111462306a36Sopenharmony_ci return -EINVAL; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (!frame_info || !frame_info->rtg) 111862306a36Sopenharmony_ci return -EINVAL; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci id = frame_info->rtg->id; 112162306a36Sopenharmony_ci if (is_boost) { 112262306a36Sopenharmony_ci frame_info->frame_boost_min_util = min_util; 112362306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_BOOST_MIN_UTIL", min_util); 112462306a36Sopenharmony_ci } else { 112562306a36Sopenharmony_ci frame_info->frame_min_util = min_util; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci frame_info->frame_util = calc_frame_util(frame_info, false); 112862306a36Sopenharmony_ci trace_rtg_frame_sched(id, "frame_util", frame_info->frame_util); 112962306a36Sopenharmony_ci sched_set_group_normalized_util(id, 113062306a36Sopenharmony_ci frame_info->frame_util, RTG_FREQ_FORCE_UPDATE); 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ciint set_frame_max_util(struct frame_info *frame_info, int max_util) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci int id; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci if ((max_util < 0) || (max_util > SCHED_CAPACITY_SCALE)) { 114162306a36Sopenharmony_ci pr_err("[FRAME_RTG]: %s invalid max_util value\n", 114262306a36Sopenharmony_ci __func__); 114362306a36Sopenharmony_ci return -EINVAL; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (!frame_info || !frame_info->rtg) 114762306a36Sopenharmony_ci return -EINVAL; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci frame_info->frame_max_util = max_util; 115062306a36Sopenharmony_ci id = frame_info->rtg->id; 115162306a36Sopenharmony_ci trace_rtg_frame_sched(id, "FRAME_MAX_UTIL", frame_info->frame_max_util); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci return 0; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistruct frame_info *lookup_frame_info_by_grp_id(int grp_id) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci if (grp_id >= (MULTI_FRAME_ID + MULTI_FRAME_NUM) || (grp_id <= 0)) 115962306a36Sopenharmony_ci return NULL; 116062306a36Sopenharmony_ci if (grp_id >= MULTI_FRAME_ID) { 116162306a36Sopenharmony_ci read_lock(&g_id_manager.lock); 116262306a36Sopenharmony_ci if (!test_bit(grp_id - MULTI_FRAME_ID, g_id_manager.id_map)) { 116362306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 116462306a36Sopenharmony_ci return NULL; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci read_unlock(&g_id_manager.lock); 116762306a36Sopenharmony_ci return rtg_frame_info(grp_id); 116862306a36Sopenharmony_ci } else 116962306a36Sopenharmony_ci return rtg_frame_info(grp_id); 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic int _init_frame_info(struct frame_info *frame_info, int id) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci struct related_thread_group *grp = NULL; 117562306a36Sopenharmony_ci unsigned long flags; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci memset(frame_info, 0, sizeof(struct frame_info)); 117862306a36Sopenharmony_ci mutex_init(&frame_info->lock); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci mutex_lock(&frame_info->lock); 118162306a36Sopenharmony_ci frame_info->frame_rate = DEFAULT_FRAME_RATE; 118262306a36Sopenharmony_ci frame_info->frame_time = div_u64(NSEC_PER_SEC, frame_info->frame_rate); 118362306a36Sopenharmony_ci frame_info->thread_num = 0; 118462306a36Sopenharmony_ci frame_info->prio = NOT_RT_PRIO; 118562306a36Sopenharmony_ci atomic_set(&(frame_info->curr_rt_thread_num), 0); 118662306a36Sopenharmony_ci atomic_set(&(frame_info->frame_sched_state), 0); 118762306a36Sopenharmony_ci frame_info->vload_margin = DEFAULT_VLOAD_MARGIN; 118862306a36Sopenharmony_ci frame_info->max_vload_time = 118962306a36Sopenharmony_ci div_u64(frame_info->frame_time, NSEC_PER_MSEC) + 119062306a36Sopenharmony_ci frame_info->vload_margin; 119162306a36Sopenharmony_ci frame_info->frame_min_util = FRAME_DEFAULT_MIN_UTIL; 119262306a36Sopenharmony_ci frame_info->frame_max_util = FRAME_DEFAULT_MAX_UTIL; 119362306a36Sopenharmony_ci frame_info->prev_min_util = FRAME_DEFAULT_MIN_PREV_UTIL; 119462306a36Sopenharmony_ci frame_info->prev_max_util = FRAME_DEFAULT_MAX_PREV_UTIL; 119562306a36Sopenharmony_ci frame_info->margin_imme = false; 119662306a36Sopenharmony_ci frame_info->timestamp_skipped = false; 119762306a36Sopenharmony_ci frame_info->status = FRAME_END; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci grp = frame_rtg(id); 120062306a36Sopenharmony_ci if (unlikely(!grp)) { 120162306a36Sopenharmony_ci mutex_unlock(&frame_info->lock); 120262306a36Sopenharmony_ci return -EINVAL; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci raw_spin_lock_irqsave(&grp->lock, flags); 120662306a36Sopenharmony_ci grp->private_data = frame_info; 120762306a36Sopenharmony_ci grp->rtg_class = &frame_rtg_class; 120862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&grp->lock, flags); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci frame_info->rtg = grp; 121162306a36Sopenharmony_ci mutex_unlock(&frame_info->lock); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci return 0; 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic int __init init_frame_info(void) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci int ret = 0; 121962306a36Sopenharmony_ci int id; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci for (id = MULTI_FRAME_ID; id < (MULTI_FRAME_ID + MULTI_FRAME_NUM); id++) { 122262306a36Sopenharmony_ci if (ret != 0) 122362306a36Sopenharmony_ci break; 122462306a36Sopenharmony_ci ret = _init_frame_info(rtg_multi_frame_info(id), id); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci return ret; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_cilate_initcall(init_frame_info); 1230