/* * 设置profile * success: return BSP_OK * fail: return BSP_ERROR */ int pwrctrl_dfs_set_profile(int profile) { struct cpufreq_msg set_msg = {0,0,0,0}; if ((profile < BALONG_FREQ_MIN) || (profile > BALONG_FREQ_MAX)) { cpufreq_err("profile in right bound??%d\n", profile); return BSP_ERROR; } set_msg.msg_type = CPUFREQ_ADJUST_FREQ; set_msg.source = CPUFREQ_ACORE; if (pwrctrl_dfs_get_profile() < profile) { set_msg.content = DFS_PROFILE_UP_TARGET; } else if (pwrctrl_dfs_get_profile() > profile) { set_msg.content = DFS_PROFILE_DOWN_TARGET; } else { return BSP_OK; } set_msg.profile = (u32)profile; return balong_cpufreq_icc_send(&set_msg); }
static void pwrctrl_dfs_mgrmsg_task(void) { int cur_profile = 0; unsigned int flowctrl_cpuload = 0; PWRCTRLFUNCPTR pRoutine = NULL; struct cpufreq_msg task_msg = {0,0,0,0}; g_stDfsCpuControl.ulStartTime = bsp_get_slice_value(); /* coverity[INFINITE_LOOP] */ /* coverity[no_escape] */ for (;;) { if (NULL != g_sem_calccpu_flag) { semTake(g_sem_calccpu_flag, DFS_WAIT_FOREVER); /*调用ttf回调函数*/ if ((NULL != FlowCtrlCallBack) && (g_flowctrl_in_interr_times >= 200)) { flowctrl_cpuload = cpufreq_calccpu_cpuload(); pRoutine = FlowCtrlCallBack; (void)(*pRoutine)(flowctrl_cpuload); } } else { taskDelay((int)g_stDfsCpuConfigInfo.ulTimerLen); g_calccpu_load_result = cpufreq_calccpu_result(&g_next_freq); } if (!g_cpufreq_lock_status_flag) { continue; } cur_profile = pwrctrl_dfs_get_profile(); cpufreq_assistant_regulate_ddr(cur_profile); if (DFS_PROFILE_NOCHANGE != g_calccpu_load_result) { if (g_icc_run_flag == 1) { task_msg.msg_type = CPUFREQ_ADJUST_FREQ; task_msg.source = CPUFREQ_CCORE; task_msg.content = g_calccpu_load_result; if (DFS_PROFILE_UP_TARGET == g_calccpu_load_result) { cur_profile = DC_RESV; } else if ((u32)cur_profile == CPUFREQ_MIN_PROFILE_LIMIT) { continue; } task_msg.profile = (unsigned int)cur_profile - 1; balong_cpufreq_icc_send(&task_msg); } else if (g_icc_run_flag == 2) { cpufreq_excute_result_cpu(g_calccpu_load_result, g_next_freq); } } } }
/*检查调频请求是否符合限制*/ static int balong_check_msg(struct cpufreq_msg *msg) { int ret = BSP_OK; int max_limit = 0; int min_limit = 0; balong_check_profile_limit(&max_limit, &min_limit); int cur_profile = pwrctrl_dfs_get_profile(); if (CPUFREQ_ADJUST_FREQ == msg->msg_type) { switch(msg->content) { case DFS_PROFILE_UP: case DFS_PROFILE_UP_TARGET: if (max_limit == cur_profile) { ret = BSP_ERROR; } if (msg->profile > (u32)max_limit) { msg->profile = (u32)max_limit; } break; case DFS_PROFILE_DOWN: case DFS_PROFILE_DOWN_TARGET: if (min_limit == cur_profile) { ret = BSP_ERROR; } if (msg->profile < (u32)min_limit) { msg->profile = (u32)min_limit; } #ifdef CPUFREQ_IS_SYNC_DDR /*判断本次请求是否和上次重复,重复则停止再次发送*/ if ((1 == CPUFREQ_DOWN_FLAG(msg->source)) && ((msg->profile) == CPUFREQ_DOWN_PROFILE(msg->source))) { ret = BSP_ERROR; } #endif break; case DFS_PROFILE_DOWN_LIMIT: if ((u32)min_limit == msg->profile) { ret =BSP_ERROR; } break; case DFS_PROFILE_UP_LIMIT: if ((u32)max_limit == msg->profile) { ret =BSP_ERROR; } break; default: break; } }/*CPUFREQ_ADJUST_FREQ == msg->msg_type*/ return ret; }
static inline void cpufreq_pm_om_log(struct cpufreq_msg *msg) { struct cpufreq_debug_msg debug_msg_log = {msg->msg_type, msg->source, msg->content, msg->profile, 0, 0, 0}; debug_msg_log.taskid = taskIdSelf(); debug_msg_log.cur_profile = (unsigned int)pwrctrl_dfs_get_profile(); debug_msg_log.cur_load = g_ulCCpuload; bsp_pm_log_type(PM_OM_CPUF, CPUFREQ_ICC_LOG, sizeof(struct cpufreq_debug_msg), &debug_msg_log); }
/* * Here we notify other drivers of the proposed change and the final change. * * *根据relation做相应动作 */ static s32 balong_cpufreq_target(struct cpufreq_policy *policy, u32 target_freq, u32 relation) { u32 result = 2; u32 new_index = 0; int cur_profile = 0; struct cpufreq_msg task_msg = {0,0,0,0}; cpufreq_frequency_table_target(policy, balong_clockrate_table, target_freq, relation, &new_index); cpufreq_debug("target_freq %d new_index%d\n", target_freq, new_index); cur_profile = pwrctrl_dfs_get_profile(); if ((CPUFREQ_RELATION_H == relation) && (BALONG_FREQ_MAX != cur_profile)) { result = DFS_PROFILE_UP_TARGET; } else if ((CPUFREQ_RELATION_L == relation) && (BALONG_FREQ_MIN != cur_profile)) { result = DFS_PROFILE_DOWN_TARGET; } else { policy->cur = balong_clockrate_table[cur_profile].frequency; g_cur_freq = policy->cur; cpufreq_info("set target relation %d, cur pro %d\n", relation, policy->cur); return BSP_ERROR; } cpufreq_frequency_target_profile(balong_clockrate_table[new_index].frequency, relation, &new_index); task_msg.msg_type = CPUFREQ_ADJUST_FREQ; task_msg.source = CPUFREQ_ACORE; task_msg.content = result; task_msg.profile = new_index; balong_cpufreq_icc_send(&task_msg); policy->cur = balong_clockrate_table[cur_profile].frequency; g_cur_freq = policy->cur; return BSP_OK; }
/* * 获取当前频率 BSP_ERROR 设置失败;BSP_OK 设置成功 * */ int pwrctrl_dfs_current(int *a9freq, int *ddrfreq, int *slowfreq) { int cur_profile = 0; int ret = BSP_OK; if ((a9freq != NULL) && (ddrfreq != NULL) && (slowfreq != NULL)) { cur_profile = pwrctrl_dfs_get_profile(); *a9freq = (s32)balong_query_profile_table[cur_profile].cpu_frequency; *ddrfreq = (s32)balong_query_profile_table[cur_profile].ddr_frequency; *slowfreq = (s32)balong_query_profile_table[cur_profile].sbus_frequency; } else { cpufreq_err("argv is NULL,check it\n"); ret = BSP_ERROR; } return ret; }
/*find the first profile that is the target*/ static void cpufreq_frequency_target_profile( unsigned int target_freq, unsigned int relation, unsigned int *new_profile) { int i = 0; int cur_profile = pwrctrl_dfs_get_profile(); switch (relation) { case DFS_PROFILE_UP: *new_profile = balong_clockrate_table[BALONG_FREQ_MAX].index; return; case DFS_PROFILE_DOWN: cpufreq_debug("down to frequency\n"); break; default : break; } for (i = cur_profile; i >= BALONG_FREQ_MIN; i--) { if (target_freq != balong_query_profile_table[i].cpu_frequency) { continue; } if ((u32)cur_profile == balong_query_profile_table[i].profile) { continue; } *new_profile = balong_query_profile_table[i].profile; goto out; } if (cur_profile != BALONG_FREQ_MIN) { *new_profile = balong_query_profile_table[cur_profile - 1].profile; } else { *new_profile = balong_query_profile_table[BALONG_FREQ_MIN].profile; } out: return; }
void cpufreq_print_debug(void) { pwrctrl_dfs_get_profile(); cpufreq_err("cur\t profile: %d\n", g_cur_profile); cpufreq_err("ccore\t load: %d\n", g_ulCCpuload); cpufreq_err("lase\t ddr: %d\n", g_last_ddr_value_id); cpufreq_err("up times: %d\n", g_stDfsCpuControl.ulCurSysUpTime); cpufreq_err("down times: %d\n", g_stDfsCpuControl.ulCurSysDownTime); cpufreq_err("up_threshold: %d\n", g_stDfsCpuConfigInfo.astThresHold[0].usProfileUpLimit); cpufreq_err("up_threshold_times: %d\n", g_stDfsCpuConfigInfo.usProfileUpTime); cpufreq_err("down_threshold: %d\n", g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit); cpufreq_err("down_threshold_times: %d\n", g_stDfsCpuConfigInfo.usProfileDownTime); cpufreq_err("sampling_rate: %d\n", g_stDfsCpuConfigInfo.ulTimerLen); cpufreq_err("last icc msg\n"); cpufreq_err("icc msg_type: %d\n", debug_msg.msg_type); cpufreq_err("icc source: %d\n", debug_msg.source); cpufreq_err("icc content: %d\n", debug_msg.content); cpufreq_err("icc profile: %d\n", debug_msg.profile); cpufreq_err("cur max limit:%d\n", CPUFREQ_MAX_PROFILE_LIMIT); cpufreq_err("cur min limit:%d\n", CPUFREQ_MIN_PROFILE_LIMIT); }
void cpufreq_print_debug(void) { struct cpu_dbs_info_s *dbs_info; dbs_info = &per_cpu(g_acpu_dbs_info, 0); pwrctrl_dfs_get_profile(); cpufreq_err("cur profile: %d\n", g_cur_profile); cpufreq_err("acore load: %d\n", g_ulACpuload); cpufreq_err("up times: %d\n", dbs_info->cpu_up_time); cpufreq_err("down times: %d\n", dbs_info->cpu_down_time); cpufreq_err("up_threshold: %d\n", dbs_tuners_ins.up_threshold); cpufreq_err("up_threshold_times: %d\n", dbs_tuners_ins.up_threshold_times); cpufreq_err("down_threshold: %d\n", dbs_tuners_ins.down_threshold); cpufreq_err("down_threshold_times: %d\n", dbs_tuners_ins.down_threshold_times); cpufreq_err("sampling_rate: %d\n", dbs_tuners_ins.sampling_rate); cpufreq_err("last icc msg\n"); cpufreq_err("icc msg_type: %d\n", debug_msg.msg_type); cpufreq_err("icc source: %d\n", debug_msg.source); cpufreq_err("icc content: %d\n", debug_msg.content); cpufreq_err("icc profile: %d\n", debug_msg.profile); cpufreq_err("cur max limit:%d\n", CPUFREQ_MAX_PROFILE_LIMIT); cpufreq_err("cur min limit:%d\n", CPUFREQ_MIN_PROFILE_LIMIT); }
/* * 该接口负责cpu负载检测, * 并根据预设阈值判决是否需要向M3请求调频 */ void cpufreq_update_frequency(void) { u32 cpuload = 0; int cur_profile = 0; struct cpufreq_msg task_msg = {CPUFREQ_ADJUST_FREQ, CPUFREQ_ACORE, 0, BALONG_FREQ_MAX}; cpuload = (u32)cpufreq_calccpu_cpuload(); cur_profile = (int)pwrctrl_dfs_get_profile(); if (cpuload > dbs_tuners_ins.up_threshold) { task_msg.content = DFS_PROFILE_UP_TARGET; } else if (cpuload < dbs_tuners_ins.down_threshold) { task_msg.profile = (cur_profile != BALONG_FREQ_MIN) ? (cur_profile - 1) : (BALONG_FREQ_MIN); task_msg.content = DFS_PROFILE_DOWN; } else { return; } balong_cpufreq_icc_send(&task_msg); }
/* * 该接口负责cpu负载检测, * 并根据预设阈值判决是否需要向M3请求调频 */ void cpufreq_update_frequency(void) { u32 cpuload = 0; int cur_profile = 0; struct cpufreq_msg task_msg = {CPUFREQ_ADJUST_FREQ, CPUFREQ_CCORE, 0, BALONG_FREQ_MAX}; cpuload = cpufreq_calccpu_cpuload(); cur_profile = pwrctrl_dfs_get_profile(); if (cpuload > g_stDfsCpuConfigInfo.astThresHold[0].usProfileUpLimit) { task_msg.content = DFS_PROFILE_UP_TARGET; } else if (cpuload < g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit) { task_msg.profile = (cur_profile != BALONG_FREQ_MIN) ? (cur_profile - 1) : (BALONG_FREQ_MIN); task_msg.content = DFS_PROFILE_DOWN; } else { return; } balong_cpufreq_icc_send(&task_msg); }
/*find a freq in all table*/ static int cpufreq_frequency_table_target(struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index) {/*lint !e578 */ struct cpufreq_frequency_table optimal = { .index = ~0, .frequency = 0, }; struct cpufreq_frequency_table suboptimal = { .index = ~0, .frequency = 0, }; unsigned int i; /*lint --e{744} */ switch (relation) { case DFS_PROFILE_UP: suboptimal.frequency = ~0; break; case DFS_PROFILE_DOWN: optimal.frequency = ~0; break; } for (i = 0; (table[i].frequency != (u32)CPUFREQ_TABLE_END); i++) { unsigned int freq = table[i].frequency; if (freq == (u32)CPUFREQ_ENTRY_INVALID) continue; if ((freq < balong_query_profile_table[BALONG_FREQ_MIN].cpu_frequency) || (freq > balong_query_profile_table[BALONG_FREQ_MAX].cpu_frequency)) continue; switch (relation) { case DFS_PROFILE_UP: if (freq <= target_freq) { if (freq >= optimal.frequency) { optimal.frequency = freq; optimal.index = i; } } else { if (freq <= suboptimal.frequency) { suboptimal.frequency = freq; suboptimal.index = i; } } break; case DFS_PROFILE_DOWN: if (freq >= target_freq) { if (freq <= optimal.frequency) { optimal.frequency = freq; optimal.index = i; } } else { if (freq >= suboptimal.frequency) { suboptimal.frequency = freq; suboptimal.index = i; } } break; } } if (optimal.index > i) { if (suboptimal.index > i) return BSP_ERROR; *index = suboptimal.index; } else *index = optimal.index; return BSP_OK; } /***************************************************************************** Function: PWRCTRL_DfsMgrExcuteVoteResultCpu Description:Handle the Profile Vote Result Input: enResult: The Vote Value Output: None Return: None Others: *****************************************************************************/ static int cpufreq_excute_result_cpu(u32 relation, u32 target_freq) { u32 result = 2; u32 new_index = 0; int cur_profile = 0; struct cpufreq_msg task_msg = {0,0,0,0}; cpufreq_frequency_table_target(balong_clockrate_table, target_freq, relation, &new_index); cpufreq_debug("target_freq %d new_index%d\n", target_freq, new_index); cur_profile = pwrctrl_dfs_get_profile(); if ((DFS_PROFILE_UP == relation) && (BALONG_FREQ_MAX != cur_profile)) { result = DFS_PROFILE_UP_TARGET; } else if ((DFS_PROFILE_DOWN == relation) && (BALONG_FREQ_MIN != cur_profile)) { result = DFS_PROFILE_DOWN_TARGET; } else { cpufreq_err("set target relation %d, cur pro %d\n", relation, cur_profile); return BSP_ERROR; } cpufreq_frequency_target_profile(balong_clockrate_table[new_index].frequency, relation, &new_index); task_msg.msg_type = CPUFREQ_ADJUST_FREQ; task_msg.source = CPUFREQ_CCORE; task_msg.content = result; task_msg.profile = new_index; balong_cpufreq_icc_send(&task_msg); g_stDfsCpuControl.enCurProfile = (u32)cur_profile; return BSP_OK; } unsigned int cpufreq_calccpu_cpuload(void) { u32 end_time = 0; u32 idle_time = 0; u32 wall_time = 0; u32 cpu_load = 0; unsigned long irqlock = 0; local_irq_save(irqlock); end_time = bsp_get_slice_value(); wall_time = get_timer_slice_delta(g_cpufreq_start_time, end_time); idle_time = g_ulDfsCcpuIdleTime_long; g_cpufreq_start_time = end_time; g_ulDfsCcpuIdleTime_long = 0; g_flowctrl_in_interr_times = 0; cpu_load = (wall_time == 0) ? (0) : (((wall_time - idle_time) * 100) / wall_time); local_irq_restore(irqlock); if (cpu_load > 100) { cpu_load = g_ulCCpuload; cpufreq_info("cpuload: %d, wall:%d, idle:%d\n", cpu_load, wall_time, idle_time); } return cpu_load; }
/* 调频策略 */ static u32 cpufreq_calccpu_result(u32 *next_freq) { u32 ulSleepTime; u32 ulCpuFree; u32 ulCpuLoad_C; u32 ulProTime; u32 ulEndTime; int cur_profile = 0; PWRCTRLFUNCPTR pRoutine = NULL; /*这里是读取时间,暂时大桩*/ ulEndTime = bsp_get_slice_value(); ulProTime = ulEndTime - g_stDfsCpuControl.ulStartTime; ulSleepTime = g_ulDfsCcpuIdleTime; g_ulDfsCcpuIdleTime = 0; g_stDfsCpuControl.ulStartTime = ulEndTime; ulCpuFree= (ulSleepTime* 100) / (ulProTime); /*Calc the Cpu Free Value*/ if (ulCpuFree > 100) { cpufreq_err("calc cpuload error!\n"); return DFS_PROFILE_NOCHANGE; } ulCpuLoad_C= 100 - ulCpuFree; g_ulCCpuload = ulCpuLoad_C; /*调用ttf回调函数*/ if (NULL != FlowCtrlCallBack) { pRoutine = FlowCtrlCallBack; (void)(*pRoutine)(g_ulCCpuload); } else { } if (ulCpuLoad_C > g_stDfsCpuConfigInfo.astThresHold[0].usProfileUpLimit) { /*Clean the Value of the System Down Counter*/ g_stDfsCpuControl.ulCurSysDownTime = 0; g_stDfsCpuControl.ulCurSysUpTime++; } else if (ulCpuLoad_C < g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit) { /*Clean the Value of the System Over Load Counter*/ g_stDfsCpuControl.ulCurSysUpTime = 0; g_stDfsCpuControl.ulCurSysDownTime++; } else /*The System Load is Normal Value*/ { g_stDfsCpuControl.ulCurSysDownTime = 0; g_stDfsCpuControl.ulCurSysUpTime = 0; return DFS_PROFILE_NOCHANGE; } cur_profile = pwrctrl_dfs_get_profile(); if (g_stDfsCpuControl.ulCurSysDownTime >= g_stDfsCpuConfigInfo.usProfileDownTime) { g_stDfsCpuControl.ulCurSysDownTime = 0; g_stDfsCpuControl.ulCurSysUpTime = 0; *next_freq =( ulCpuLoad_C * (balong_query_profile_table[cur_profile].cpu_frequency)) / (g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit); return DFS_PROFILE_DOWN; } if (g_stDfsCpuControl.ulCurSysUpTime >= g_stDfsCpuConfigInfo.usProfileUpTime) { g_stDfsCpuControl.ulCurSysDownTime = 0; g_stDfsCpuControl.ulCurSysUpTime = 0; *next_freq = balong_query_profile_table[BALONG_FREQ_MAX].cpu_frequency;/*max cpufreq*/ return DFS_PROFILE_UP_TARGET; } return DFS_PROFILE_NOCHANGE; }