605 lines
17 KiB
C
605 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2021 MediaTek Inc.
|
|
*/
|
|
|
|
/**
|
|
* @file mtk_gpuppm.c
|
|
* @brief Performance power management for GPU-DVFS
|
|
*/
|
|
|
|
/**
|
|
* ===============================================
|
|
* Include
|
|
* ===============================================
|
|
*/
|
|
#include <linux/mutex.h>
|
|
|
|
#include <gpufreq_v2.h>
|
|
#include <gpuppm.h>
|
|
#include <gpufreq_common.h>
|
|
#include <gpufreq_history_common.h>
|
|
|
|
/**
|
|
* ===============================================
|
|
* Local Function Declaration
|
|
* ===============================================
|
|
*/
|
|
static void __gpuppm_sort_limit(void);
|
|
static int __gpuppm_limit_effective(enum gpufreq_target target);
|
|
static int __gpuppm_convert_limit_to_idx(enum gpufreq_target target, enum gpuppm_limiter limiter,
|
|
int ceiling_info, int floor_info, int *ceiling_idx, int *floor_idx);
|
|
static void __gpuppm_update_gpuppm_info(void);
|
|
|
|
/**
|
|
* ===============================================
|
|
* Local Variable Definition
|
|
* ===============================================
|
|
*/
|
|
static DEFINE_MUTEX(gpuppm_lock);
|
|
static struct gpuppm_status g_ppm;
|
|
static unsigned int g_gpueb_support;
|
|
static unsigned int g_stress_test;
|
|
static struct gpufreq_shared_status *g_shared_status;
|
|
|
|
static struct gpuppm_limit_info g_limit_table[] = {
|
|
LIMITOP(LIMIT_SEGMENT, "SEGMENT", GPUPPM_PRIO_9,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_DEBUG, "DEBUG", GPUPPM_PRIO_8,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_GPM3, "GPM_3.0", GPUPPM_PRIO_7,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_TEMPER_COMP, "TEMPER_COMP", GPUPPM_PRIO_7,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_PEAK_POWER_AP, "PEAK_POWER_AP", GPUPPM_PRIO_7,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_PEAK_POWER_EB, "PEAK_POWER_EB", GPUPPM_PRIO_7,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_THERMAL_AP, "THERMAL_AP", GPUPPM_PRIO_6,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_THERMAL_EB, "THERMAL_EB", GPUPPM_PRIO_6,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_SRAMRC, "SRAMRC", GPUPPM_PRIO_5,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_BATT_OC, "BATT_OC", GPUPPM_PRIO_4,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_BATT_PERCENT, "BATT_PERCENT", GPUPPM_PRIO_4,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_LOW_BATT, "LOW_BATT", GPUPPM_PRIO_4,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_PBM, "PBM", GPUPPM_PRIO_4,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_APIBOOST, "APIBOOST", GPUPPM_PRIO_3,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
LIMITOP(LIMIT_FPSGO, "FPSGO", GPUPPM_PRIO_2,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE,
|
|
GPUPPM_DEFAULT_IDX, LIMIT_ENABLE),
|
|
};
|
|
|
|
static struct gpuppm_platform_fp platform_ap_fp = {
|
|
.set_shared_status = gpuppm_set_shared_status,
|
|
.limited_commit = gpuppm_limited_commit,
|
|
.set_limit = gpuppm_set_limit,
|
|
.switch_limit = gpuppm_switch_limit,
|
|
.get_ceiling = gpuppm_get_ceiling,
|
|
.get_floor = gpuppm_get_floor,
|
|
.get_c_limiter = gpuppm_get_c_limiter,
|
|
.get_f_limiter = gpuppm_get_f_limiter,
|
|
};
|
|
|
|
static struct gpuppm_platform_fp platform_eb_fp = {};
|
|
|
|
/**
|
|
* ===============================================
|
|
* Function Definition
|
|
* ===============================================
|
|
*/
|
|
static void __gpuppm_sort_limit(void)
|
|
{
|
|
struct gpuppm_limit_info *limit_table = NULL;
|
|
int cur_ceiling = 0, cur_floor = 0;
|
|
int max_oppidx = 0, min_oppidx = 0;
|
|
unsigned int cur_c_limiter = LIMIT_NUM;
|
|
unsigned int cur_f_limiter = LIMIT_NUM;
|
|
unsigned int cur_c_priority = GPUPPM_PRIO_NONE;
|
|
unsigned int cur_f_priority = GPUPPM_PRIO_NONE;
|
|
int i = 0;
|
|
|
|
limit_table = g_limit_table;
|
|
cur_ceiling = -1;
|
|
cur_floor = g_ppm.opp_num;
|
|
max_oppidx = 0;
|
|
min_oppidx = g_ppm.opp_num - 1;
|
|
|
|
/* sort ceiling among valid limiters except SEGMENT */
|
|
for (i = 1; i < LIMIT_NUM; i++) {
|
|
/* skip default value and check enable */
|
|
if (limit_table[i].ceiling != GPUPPM_DEFAULT_IDX &&
|
|
limit_table[i].ceiling != max_oppidx &&
|
|
limit_table[i].c_enable == LIMIT_ENABLE) {
|
|
/* use the largest ceiling with its limiter */
|
|
if (limit_table[i].ceiling > cur_ceiling) {
|
|
cur_ceiling = limit_table[i].ceiling;
|
|
cur_c_limiter = limit_table[i].limiter;
|
|
}
|
|
/* use the largest priority to cover all valid limiters */
|
|
if (limit_table[i].priority > cur_c_priority)
|
|
cur_c_priority = limit_table[i].priority;
|
|
}
|
|
}
|
|
/* sort floor among valid limiters except SEGMENT */
|
|
for (i = 1; i < LIMIT_NUM; i++) {
|
|
/* skip default value and check enable */
|
|
if (limit_table[i].floor != GPUPPM_DEFAULT_IDX &&
|
|
limit_table[i].floor != min_oppidx &&
|
|
limit_table[i].f_enable == LIMIT_ENABLE) {
|
|
/* use the smallest floor with its limiter */
|
|
if (limit_table[i].floor < cur_floor) {
|
|
cur_floor = limit_table[i].floor;
|
|
cur_f_limiter = limit_table[i].limiter;
|
|
}
|
|
/* use the largest priority to cover all valid limiters */
|
|
if (limit_table[i].priority > cur_f_priority)
|
|
cur_f_priority = limit_table[i].priority;
|
|
}
|
|
}
|
|
|
|
/* if no valid limitation, use SEGMENT */
|
|
if (cur_ceiling == -1) {
|
|
cur_ceiling = limit_table[LIMIT_SEGMENT].ceiling;
|
|
cur_c_limiter = limit_table[LIMIT_SEGMENT].limiter;
|
|
cur_c_priority = limit_table[LIMIT_SEGMENT].priority;
|
|
}
|
|
if (cur_floor == g_ppm.opp_num) {
|
|
cur_floor = limit_table[LIMIT_SEGMENT].floor;
|
|
cur_f_limiter = limit_table[LIMIT_SEGMENT].limiter;
|
|
cur_f_priority = limit_table[LIMIT_SEGMENT].priority;
|
|
}
|
|
|
|
/* if limit interval with intersection */
|
|
if (cur_ceiling > cur_floor) {
|
|
GPUFREQ_LOGD("exist intersection in limited interval: [%d, %d]",
|
|
cur_ceiling, cur_floor);
|
|
/*
|
|
* floor_priority > ceiling_priority: align floor
|
|
* floor_priority < ceiling_priority: align ceiling
|
|
* floor_priority = ceiling_priority: align ceiling
|
|
*/
|
|
if (cur_f_priority > cur_c_priority)
|
|
cur_ceiling = cur_floor;
|
|
else
|
|
cur_floor = cur_ceiling;
|
|
}
|
|
|
|
/* only update if both limiter of ceiling/floor are found */
|
|
if (cur_c_limiter != LIMIT_NUM && cur_f_limiter != LIMIT_NUM) {
|
|
GPUFREQ_LOGD("[ceiling] index: %d, limiter: %s, priority: %d",
|
|
cur_ceiling, limit_table[cur_c_limiter].name, cur_c_priority);
|
|
GPUFREQ_LOGD("[floor] index: %d, limiter: %s, priority: %d",
|
|
cur_floor, limit_table[cur_f_limiter].name, cur_f_priority);
|
|
|
|
g_ppm.ceiling = cur_ceiling;
|
|
g_ppm.c_limiter = cur_c_limiter;
|
|
g_ppm.c_priority = cur_c_priority;
|
|
g_ppm.floor = cur_floor;
|
|
g_ppm.f_limiter = cur_f_limiter;
|
|
g_ppm.f_priority = cur_f_priority;
|
|
}
|
|
}
|
|
|
|
static int __gpuppm_limit_effective(enum gpufreq_target target)
|
|
{
|
|
int cur_oppidx = 0, cur_ceiling = 0, cur_floor = 0;
|
|
int ret = GPUFREQ_SUCCESS;
|
|
|
|
cur_ceiling = g_ppm.ceiling;
|
|
cur_floor = g_ppm.floor;
|
|
|
|
if (target == TARGET_STACK) {
|
|
cur_oppidx = __gpufreq_get_cur_idx_stack();
|
|
if (cur_oppidx < cur_ceiling)
|
|
ret = __gpufreq_generic_commit_stack(cur_ceiling, DVFS_FREE);
|
|
else if (cur_oppidx > cur_floor)
|
|
ret = __gpufreq_generic_commit_stack(cur_floor, DVFS_FREE);
|
|
} else {
|
|
cur_oppidx = __gpufreq_get_cur_idx_gpu();
|
|
if (cur_oppidx < cur_ceiling)
|
|
ret = __gpufreq_generic_commit_gpu(cur_ceiling, DVFS_FREE);
|
|
else if (cur_oppidx > cur_floor)
|
|
ret = __gpufreq_generic_commit_gpu(cur_floor, DVFS_FREE);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int __gpuppm_convert_limit_to_idx(enum gpufreq_target target, enum gpuppm_limiter limiter,
|
|
int ceiling_info, int floor_info, int *ceiling_idx, int *floor_idx)
|
|
{
|
|
int ret = GPUFREQ_SUCCESS;
|
|
|
|
switch (limiter) {
|
|
case LIMIT_SEGMENT:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = ceiling_info;
|
|
*floor_idx = floor_info;
|
|
break;
|
|
case LIMIT_DEBUG:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = ceiling_info;
|
|
*floor_idx = floor_info;
|
|
break;
|
|
case LIMIT_GPM3:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = ceiling_info;
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_TEMPER_COMP:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = GPUPPM_KEEP_IDX;
|
|
*floor_idx = floor_info;
|
|
break;
|
|
case LIMIT_PEAK_POWER_AP:
|
|
/* limit info: freq */
|
|
if (ceiling_info > 0) {
|
|
if (target == TARGET_STACK)
|
|
*ceiling_idx = __gpufreq_get_idx_by_fstack(
|
|
(unsigned int)ceiling_info);
|
|
else
|
|
*ceiling_idx = __gpufreq_get_idx_by_fgpu(
|
|
(unsigned int)ceiling_info);
|
|
} else
|
|
*ceiling_idx = GPUPPM_RESET_IDX;
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_PEAK_POWER_EB:
|
|
/* limit info: freq */
|
|
if (ceiling_info > 0) {
|
|
if (target == TARGET_STACK)
|
|
*ceiling_idx = __gpufreq_get_idx_by_fstack(
|
|
(unsigned int)ceiling_info);
|
|
else
|
|
*ceiling_idx = __gpufreq_get_idx_by_fgpu(
|
|
(unsigned int)ceiling_info);
|
|
} else
|
|
*ceiling_idx = GPUPPM_RESET_IDX;
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_THERMAL_AP:
|
|
/* limit info: freq */
|
|
if (ceiling_info > 0) {
|
|
if (target == TARGET_STACK)
|
|
*ceiling_idx = __gpufreq_get_idx_by_fstack(
|
|
(unsigned int)ceiling_info);
|
|
else
|
|
*ceiling_idx = __gpufreq_get_idx_by_fgpu(
|
|
(unsigned int)ceiling_info);
|
|
} else
|
|
*ceiling_idx = GPUPPM_RESET_IDX;
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_THERMAL_EB:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = ceiling_info;
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_SRAMRC:
|
|
/* limit info: volt */
|
|
*ceiling_idx = GPUPPM_KEEP_IDX;
|
|
if (floor_info > 0) {
|
|
if (target == TARGET_STACK)
|
|
*floor_idx = __gpufreq_get_idx_by_vstack(
|
|
(unsigned int)floor_info);
|
|
else
|
|
*floor_idx = __gpufreq_get_idx_by_vgpu(
|
|
(unsigned int)floor_info);
|
|
} else
|
|
*floor_idx = GPUPPM_RESET_IDX;
|
|
break;
|
|
case LIMIT_BATT_OC:
|
|
/* limit info: batt_oc_level */
|
|
*ceiling_idx = __gpufreq_get_batt_oc_idx(ceiling_info);
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_BATT_PERCENT:
|
|
/* limit info: batt_percent_level */
|
|
*ceiling_idx = __gpufreq_get_batt_percent_idx(ceiling_info);
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_LOW_BATT:
|
|
/* limit info: low_batt_level */
|
|
*ceiling_idx = __gpufreq_get_low_batt_idx(ceiling_info);
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_PBM:
|
|
/* limit info: power */
|
|
if (ceiling_info > 0) {
|
|
if (target == TARGET_STACK)
|
|
*ceiling_idx = __gpufreq_get_idx_by_pstack(
|
|
(unsigned int)ceiling_info);
|
|
else
|
|
*ceiling_idx = __gpufreq_get_idx_by_pgpu(
|
|
(unsigned int)ceiling_info);
|
|
} else
|
|
*ceiling_idx = GPUPPM_RESET_IDX;
|
|
*floor_idx = GPUPPM_KEEP_IDX;
|
|
break;
|
|
case LIMIT_APIBOOST:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = ceiling_info;
|
|
*floor_idx = floor_info;
|
|
break;
|
|
case LIMIT_FPSGO:
|
|
/* limit info: OPP index */
|
|
*ceiling_idx = ceiling_info;
|
|
*floor_idx = floor_info;
|
|
break;
|
|
default:
|
|
GPUFREQ_LOGE("invalid limiter: %d (EINVAL)", limiter);
|
|
ret = GPUFREQ_EINVAL;
|
|
break;
|
|
}
|
|
|
|
GPUFREQ_LOGD("[%s limiter: %d] ceiling_info: %d (idx: %d), floor_info: %d, (idx: %d)",
|
|
(target == TARGET_STACK) ? "STACK" : "GPU",
|
|
limiter, ceiling_info, *ceiling_idx, floor_info, *floor_idx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __gpuppm_update_gpuppm_info(void)
|
|
{
|
|
unsigned int copy_size = 0;
|
|
|
|
if (!g_shared_status)
|
|
return;
|
|
|
|
/* update current status to shared memory */
|
|
g_shared_status->cur_ceiling = g_ppm.ceiling;
|
|
g_shared_status->cur_floor = g_ppm.floor;
|
|
g_shared_status->cur_c_limiter = g_ppm.c_limiter;
|
|
g_shared_status->cur_f_limiter = g_ppm.f_limiter;
|
|
g_shared_status->cur_c_priority = g_ppm.c_priority;
|
|
g_shared_status->cur_f_priority = g_ppm.f_priority;
|
|
|
|
copy_size = sizeof(struct gpuppm_limit_info) * LIMIT_NUM;
|
|
memcpy(g_shared_status->limit_table, g_limit_table, copy_size);
|
|
}
|
|
|
|
void gpuppm_set_stress_test(unsigned int val)
|
|
{
|
|
g_stress_test = val;
|
|
|
|
/* update current status to shared memory */
|
|
if (g_shared_status)
|
|
g_shared_status->stress_test = g_stress_test;
|
|
}
|
|
|
|
int gpuppm_get_ceiling(void)
|
|
{
|
|
return g_ppm.ceiling;
|
|
}
|
|
|
|
int gpuppm_get_floor(void)
|
|
{
|
|
return g_ppm.floor;
|
|
}
|
|
|
|
unsigned int gpuppm_get_c_limiter(void)
|
|
{
|
|
return g_ppm.c_limiter;
|
|
}
|
|
|
|
unsigned int gpuppm_get_f_limiter(void)
|
|
{
|
|
return g_ppm.f_limiter;
|
|
}
|
|
|
|
int gpuppm_set_limit(enum gpufreq_target target, enum gpuppm_limiter limiter,
|
|
int ceiling_info, int floor_info)
|
|
{
|
|
struct gpuppm_limit_info *limit_table = NULL;
|
|
int opp_num = 0, ceiling_idx = 0, floor_idx = 0;
|
|
int ret = GPUFREQ_SUCCESS;
|
|
|
|
GPUFREQ_TRACE_START("target=%d, limiter=%d, ceiling_info=%d, floor_info=%d",
|
|
target, limiter, ceiling_info, floor_info);
|
|
|
|
if (limiter < 0 || limiter >= LIMIT_NUM) {
|
|
GPUFREQ_LOGE("invalid limiter: %d (EINVAL)", limiter);
|
|
ret = GPUFREQ_EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
limit_table = g_limit_table;
|
|
opp_num = g_ppm.opp_num;
|
|
|
|
mutex_lock(&gpuppm_lock);
|
|
|
|
/* convert input limit info to OPP index */
|
|
ret = __gpuppm_convert_limit_to_idx(target, limiter,
|
|
ceiling_info, floor_info, &ceiling_idx, &floor_idx);
|
|
if (unlikely(ret)) {
|
|
GPUFREQ_LOGE("fail to convert limit info to OPP index (%d)", ret);
|
|
goto done;
|
|
}
|
|
|
|
if (ceiling_idx == GPUPPM_RESET_IDX || ceiling_idx == GPUPPM_DEFAULT_IDX)
|
|
limit_table[limiter].ceiling = GPUPPM_DEFAULT_IDX;
|
|
else if (ceiling_idx >= 0 && ceiling_idx < opp_num)
|
|
limit_table[limiter].ceiling = ceiling_idx;
|
|
|
|
if (floor_idx == GPUPPM_RESET_IDX || floor_idx == GPUPPM_DEFAULT_IDX)
|
|
limit_table[limiter].floor = GPUPPM_DEFAULT_IDX;
|
|
else if (floor_idx >= 0 && floor_idx < opp_num)
|
|
limit_table[limiter].floor = floor_idx;
|
|
|
|
/* update current limit status */
|
|
__gpuppm_sort_limit();
|
|
|
|
/* update current status to shared memory */
|
|
if (g_shared_status)
|
|
__gpuppm_update_gpuppm_info();
|
|
|
|
/* update current OPP if necessary */
|
|
ret = __gpuppm_limit_effective(target);
|
|
|
|
mutex_unlock(&gpuppm_lock);
|
|
|
|
done:
|
|
GPUFREQ_TRACE_END();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int gpuppm_switch_limit(enum gpufreq_target target, enum gpuppm_limiter limiter,
|
|
int c_enable, int f_enable)
|
|
{
|
|
struct gpuppm_limit_info *limit_table = NULL;
|
|
int ret = GPUFREQ_SUCCESS;
|
|
|
|
if (limiter < 0 || limiter >= LIMIT_NUM) {
|
|
GPUFREQ_LOGE("invalid limiter: %d (EINVAL)", limiter);
|
|
ret = GPUFREQ_EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
limit_table = g_limit_table;
|
|
|
|
mutex_lock(&gpuppm_lock);
|
|
|
|
if (c_enable == LIMIT_ENABLE)
|
|
limit_table[limiter].c_enable = LIMIT_ENABLE;
|
|
else if (c_enable == LIMIT_DISABLE)
|
|
limit_table[limiter].c_enable = LIMIT_DISABLE;
|
|
|
|
if (f_enable == LIMIT_ENABLE)
|
|
limit_table[limiter].f_enable = LIMIT_ENABLE;
|
|
else if (f_enable == LIMIT_DISABLE)
|
|
limit_table[limiter].f_enable = LIMIT_DISABLE;
|
|
|
|
/* update current limit status */
|
|
__gpuppm_sort_limit();
|
|
|
|
/* update current status to shared memory */
|
|
if (g_shared_status)
|
|
__gpuppm_update_gpuppm_info();
|
|
|
|
/* update current OPP if necessary */
|
|
ret = __gpuppm_limit_effective(target);
|
|
|
|
mutex_unlock(&gpuppm_lock);
|
|
|
|
done:
|
|
return ret;
|
|
}
|
|
|
|
int gpuppm_limited_commit(enum gpufreq_target target, int oppidx)
|
|
{
|
|
int limited_idx = 0;
|
|
int cur_ceiling = 0, cur_floor = 0;
|
|
int ret = GPUFREQ_SUCCESS;
|
|
|
|
GPUFREQ_TRACE_START("target=%d, oppidx=%d", target, oppidx);
|
|
|
|
mutex_lock(&gpuppm_lock);
|
|
|
|
/* fit to limited interval */
|
|
cur_ceiling = g_ppm.ceiling;
|
|
cur_floor = g_ppm.floor;
|
|
|
|
/* randomly replace target OPP index */
|
|
if (g_stress_test) {
|
|
get_random_bytes(&oppidx, sizeof(oppidx));
|
|
oppidx = oppidx < 0 ? (oppidx * -1) : oppidx;
|
|
oppidx = (oppidx % (cur_floor - cur_ceiling + 1)) + cur_ceiling;
|
|
}
|
|
|
|
if (oppidx < cur_ceiling)
|
|
limited_idx = cur_ceiling;
|
|
else if (oppidx > cur_floor)
|
|
limited_idx = cur_floor;
|
|
else
|
|
limited_idx = oppidx;
|
|
|
|
GPUFREQ_LOGD("[%s] restrict OPP index: (%d->%d), limited interval: [%d, %d]",
|
|
(target == TARGET_STACK) ? "STACK" : "GPU",
|
|
oppidx, limited_idx, cur_ceiling, cur_floor);
|
|
|
|
#if GPUFREQ_HISTORY_ENABLE
|
|
gpufreq_set_history_target_opp(target, oppidx);
|
|
#endif /* GPUFREQ_HISTORY_ENABLE */
|
|
|
|
if (target == TARGET_STACK)
|
|
ret = __gpufreq_generic_commit_stack(limited_idx, DVFS_FREE);
|
|
else
|
|
ret = __gpufreq_generic_commit_gpu(limited_idx, DVFS_FREE);
|
|
|
|
mutex_unlock(&gpuppm_lock);
|
|
|
|
GPUFREQ_TRACE_END();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void gpuppm_set_shared_status(struct gpufreq_shared_status *shared_status)
|
|
{
|
|
mutex_lock(&gpuppm_lock);
|
|
|
|
if (shared_status)
|
|
g_shared_status = shared_status;
|
|
else
|
|
__gpufreq_abort("null gpufreq shared status: 0x%llx", shared_status);
|
|
|
|
/* update current status to shared memory */
|
|
if (g_shared_status) {
|
|
g_shared_status->stress_test = g_stress_test;
|
|
__gpuppm_update_gpuppm_info();
|
|
}
|
|
|
|
mutex_unlock(&gpuppm_lock);
|
|
}
|
|
|
|
int gpuppm_init(enum gpufreq_target target,
|
|
unsigned int gpueb_support, unsigned int sramrc_vsafe)
|
|
{
|
|
int max_oppidx = 0, min_oppidx = 0, opp_num = 0;
|
|
int ret = GPUFREQ_SUCCESS;
|
|
|
|
g_gpueb_support = gpueb_support;
|
|
|
|
if (g_gpueb_support)
|
|
gpufreq_register_gpuppm_fp(&platform_eb_fp);
|
|
/* init only in AP mode */
|
|
else {
|
|
if (target == TARGET_STACK)
|
|
opp_num = __gpufreq_get_opp_num_stack();
|
|
else
|
|
opp_num = __gpufreq_get_opp_num_gpu();
|
|
|
|
max_oppidx = 0;
|
|
min_oppidx = opp_num - 1;
|
|
g_ppm.opp_num = opp_num;
|
|
|
|
/* set basic limit at boot time */
|
|
gpuppm_set_limit(target, LIMIT_SEGMENT, max_oppidx, min_oppidx);
|
|
gpuppm_set_limit(target, LIMIT_SRAMRC, GPUPPM_KEEP_IDX, sramrc_vsafe);
|
|
|
|
gpufreq_register_gpuppm_fp(&platform_ap_fp);
|
|
}
|
|
|
|
return ret;
|
|
}
|