这篇博客我们主要分析thermal-engine中如何加载配置文件,包括代码中和配置文件。这里主要分析下thermal和ss算法的配置。
加载配置,在main函数中主要涉及如下代码。
init_settings(&thermal_settings);
pid_init_data(&thermal_settings);//pid算法我们平台disable后续分析
thermal_monitor_init_data(&thermal_settings);
speaker_cal_init_data(&thermal_settings);//后续分析
ss_init_data(&thermal_settings);
tb_init_data(&thermal_settings);//后续分析
virtual_sensors_init_data(&thermal_settings);//后续分析
virtual_sensors_init(&thermal_settings, config_file);//这里主要是通过settings_info中的type为virtual的,创建virtual sensor
# ifdef ENABLE_OLD_PARSER
load_config(&thermal_settings, config_file);//不涉及
# else
load_config(&thermal_settings, config_file, LOAD_ALL_FLAG);//加载配置文件
# endif
init_settings函数主要是做下初始化。
void init_settings(struct thermal_setting_t *settings)
{
if (!settings)
return;
memset(settings, 0, sizeof(struct thermal_setting_t));
settings->sample_period_ms = ERR_SAMPLING_VAL;
}
thermal_monitor_init_data函数代码如下,主要是根据平台的类型加载代码中的thermal算法的配置。
void thermal_monitor_init_data(struct thermal_setting_t *setting)
{
unsigned int i;
struct setting_info *cfg = NULL;
unsigned int arr_size = 0;
switch (therm_get_msm_id()) {//通过读取soc_id得到msm_id
......
case THERM_MSM_8909:
switch (therm_get_pmic_model()) {
case THERM_PMIC_PM8916:
cfg = tm_cfgs_8909_pm8916;
arr_size =
ARRAY_SIZE(tm_cfgs_8909_pm8916);
break;
case THERM_PMIC_PM8909://读取pmic_model得到pmic
default:
if (therm_get_hw_platform_subtype() ==
THERM_PLATFORM_SUB_QRD_HUAQIN) {
cfg = tm_cfgs_8909_qrd_hq;
arr_size =
ARRAY_SIZE(tm_cfgs_8909_qrd_hq);
} else {
cfg = tm_cfgs_8909;
arr_size =
ARRAY_SIZE(tm_cfgs_8909);
}
break;
}
break;
......
default:
msg("%s: Uknown Bear family device", __func__);
break;
}
for (i = 0; i < arr_size; i++) {
add_setting(setting, &cfg[i]);
}
}
我们先来看下therm_get_msm_id函数,先是从/sys/devices/soc0/soc_id或者/sys/devices/system/soc/soc0/id节点中读取soc_id,然后再从msm_soc_table中找到msm_id
enum therm_msm_id therm_get_msm_id(void)
{
static enum therm_msm_id msm_id;
static uint8_t msm_id_init;
if (!msm_id_init) {
int idx;
char buf[MAX_SOC_INFO_NAME_LEN];
if (soc_id < 0) {
get_soc_info(buf, SYSFS_PLATFORMID, SYSFS_PLATFORMID_DEPRECATED);
soc_id = atoi(buf);
}
for (idx = 0; idx < ARRAY_SIZE(msm_soc_table); idx++) {
if (soc_id == msm_soc_table[idx].soc_id) {
msm_id = msm_soc_table[idx].msm_id;
break;
}
}
if (!msm_id)
msg("Unknown target identified with soc id %d\n", soc_id);
msm_id_init = 1;
}
return msm_id;
}
soc_id为如下
msm_soc_table表如下,soc_id是245对应的msm_id是8909
static struct therm_msm_soc_type msm_soc_table[] = {
{THERM_MSM_8960, 87},
......
{THERM_MSM_8909, 245},
therm_get_pmic_model读取/sys/devices/soc0/pmic_model或者/sys/devices/system/soc/soc0/pmic_model节点的值为65549,然后通过pmic_type_table得到是THERM_PMIC_PM8909
enum therm_pmic_model therm_get_pmic_model(void)
{
static enum therm_pmic_model pmic = THERM_PMIC_UNKNOWN;
static uint8_t pmic_id_init;
if (!pmic_id_init) {
int idx;
int pmic_id = 0;
char buf[MAX_SOC_INFO_NAME_LEN] = {0};
get_soc_info(buf, SYSFS_PMIC_MODEL,
SYSFS_PMIC_MODEL_DEPRECATED);
pmic_id = atoi(buf);
for (idx = 0; idx < ARRAY_SIZE(pmic_type_table); idx++) {
if (pmic_id == pmic_type_table[idx].pmic_id) {
pmic = pmic_type_table[idx].pmic;
break;
}
}
if (!pmic)
msg("Unknown pmic identified with pmic id %d\n",
pmic_id);
pmic_id_init = 1;
}
return pmic;
}
最后再通过therm_get_hw_platform_subtype函数得到平台类型,读取/sys/devices/soc0/platform_subtype_id或者/sys/devices/system/soc/soc0/platform_subtype_id节点,这里是是1,因此最后cfg = tm_cfgs_8909
enum therm_hw_platform_subtype therm_get_hw_platform_subtype(void)
{
static enum therm_hw_platform_subtype subtype =
THERM_PLATFORM_SUB_UNKNOWN;
static uint8_t subtype_id_init;
if (!subtype_id_init) {
int subtype_id = 0;
char buf[MAX_SOC_INFO_NAME_LEN];
get_soc_info(buf, SYSFS_HW_SUBTYPE, SYSFS_HW_SUBTYPE_DEPRECATED);
subtype_id = atoi(buf);
if (subtype_id > THERM_PLATFORM_SUB_UNKNOWN)
subtype = subtype_id;
subtype_id_init = 1;
}
return subtype;
}
我们来看下tm_cfgs_8909,这里列了部分典型的后面我们再温度到达条件再结合配置一起看。
static struct setting_info tm_cfgs_8909[] =
{
{
.desc = "CPU3_HOTPLUG_MONITOR",
.algo_type = MONITOR_ALGO_TYPE,
.data.tm = {
.sensor = "tsens_tz_sensor4",
.sampling_period_ms = 1000,
.num_thresholds = 1,
._n_thresholds = 1,
._n_to_clear = 1,
._n_actions = 1,
._n_action_info = 1,
.t[0] = {
.lvl_trig = 85000,
.lvl_clr = 80000,
.num_actions = 1,
.actions[0] = {
.device = "hotplug_3",
.info = 1,
},
}
},
},
......
{
.desc = "CX_MITIGATION_MONITOR_TSENS4",
.algo_type = MONITOR_ALGO_TYPE,
.data.tm = {
.sensor = "tsens_tz_sensor4",
.sampling_period_ms = 250,
.num_thresholds = 2,
._n_thresholds = 2,
._n_to_clear = 2,
._n_actions = 2,
._n_action_info = 2,
.t[0] = {
.lvl_trig = 92000,
.lvl_clr = 85000,
.num_actions = 7,
.actions[0] = {
.device = "modem_cx",
.info = 2,
},
.actions[1] = {
.device = "gpu",
.info = 200000000,
},
.actions[2] = {
.device = "venus",
.info = 1,
},
.actions[3] = {
.device = "mdp",
.info = 1,
},
.actions[4] = {
.device = "wlan",
.info = 1,
},
.actions[5] = {
.device = "camera",
.info = 0,
},
.actions[6] = {
.device = "camcorder",
.info = 0,
},
},
.t[1] = {
.lvl_trig = 100000,
.lvl_clr = 92000,
.num_actions = 7,
.actions[0] = {
.device = "modem_cx",
.info = 3,
},
.actions[1] = {
.device = "gpu",
.info = 200000000,
},
.actions[2] = {
.device = "venus",
.info = 3,
},
.actions[3] = {
.device = "mdp",
.info = 3,
},
.actions[4] = {
.device = "wlan",
.info = 4,
},
.actions[5] = {
.device = "camera",
.info = 10,
},
.actions[6] = {
.device = "camcorder",
.info = 10,
},
}
},
},
};
下面我们来看ss算法,ss_init_data函数如下
case THERM_MSM_8909:
switch (therm_get_hw_platform()) {
case THERM_PLATFORM_QRD:
if (therm_get_hw_platform_subtype() ==
THERM_PLATFORM_SUB_QRD_HUAQIN) {
cfg = ss_cfgs_8909_qrd_hq;
arr_size =
ARRAY_SIZE(ss_cfgs_8909_qrd_hq);
} else {
cfg = ss_cfgs_8909_qrd_lc;
arr_size =
ARRAY_SIZE(ss_cfgs_8909_qrd_lc);
}
break;
default:
cfg = ss_cfgs_8909;
arr_size = ARRAY_SIZE(ss_cfgs_8909);
break;
}
break;
therm_get_hw_platform是获取/sys/devices/soc0/hw_platform或者/sys/devices/system/soc/soc0/hw_platform节点这里MTP,最后是cfg= s_cfgs_8909。
enum therm_hw_platform therm_get_hw_platform(void)
{
static enum therm_hw_platform platform;
static uint8_t hw_platform_init;
if (!hw_platform_init) {
int idx;
char buf[MAX_SOC_INFO_NAME_LEN];
get_soc_info(buf, SYSFS_HW_PLATFORM,
SYSFS_HW_PLATFORM_DEPRECATED);
for (idx = 0; idx < ARRAY_SIZE(platform_table); idx++) {
if (strncmp(platform_table[idx].platform_name, buf,
MAX_SOC_INFO_NAME_LEN) == 0) {
platform = platform_table[idx].platform;
break;
}
}
hw_platform_init = 1;
}
return platform;
}
我们来看下ss算法,后续结合温度一起分析。
static struct setting_info ss_cfgs_8909[] =
{
{
.desc = "SS-CPU0-2",
.algo_type = SS_ALGO_TYPE,
.data.ss =
{
.sensor = "tsens_tz_sensor3",
.device = "cpu",
.sampling_period_ms = 65,
.set_point = 85000,
.set_point_clr = 55000,
},
},
{
.desc = "SS-CPU1-3",
.algo_type = SS_ALGO_TYPE,
.data.ss =
{
.sensor = "tsens_tz_sensor4",
.device = "cpu",
.sampling_period_ms = 65,
.set_point = 85000,
.set_point_clr = 55000,
},
},
{
.desc = "SS-POPMEM",
.algo_type = SS_ALGO_TYPE,
.data.ss =
{
.sensor = "pop_mem",
.device = "cpu",
.sampling_period_ms = 250,
.set_point = 75000,
.set_point_clr = 55000,
.time_constant = 2,
},
},
{
.desc = "SS-GPU",
.algo_type = SS_ALGO_TYPE,
.data.ss =
{
.sensor = "tsens_tz_sensor2",
.device = "gpu",
.sampling_period_ms = 250,
.set_point = 80000,
.set_point_clr = 65000,
},
},
};
load_config函数是加载配置,主要加载各个sensor、device、和文件中的算法配置。
int load_config(struct thermal_setting_t *settings, const char *pFName, int flag)
{
int ret_val = 0;
const char *cf = (pFName) ? pFName : CONFIG_FILE_DEFAULT;//如果没有指定configfile就用/system/etc/thermal-engine.conf
info("Loading configuration file %s\n", cf);
configFile = fopen(cf,"r");
if (configFile == NULL) {
msg("Unable to open config file '%s'\n",cf);
ret_val = -(EIO);
goto error_handler;
}
if (load_sensors() || load_devices() || load_fields()) {//这是是收集平台所有的sensor、device信息
ret_val = -(EFAULT);
goto error_handler;
}
parse_file(settings, flag);//解析算法配置文件
validate_config(settings);// 验证配置文件是否有效
error_handler:
if (sensor_info_arr)
free(sensor_info_arr);
if (device_info_arr)
free(device_info_arr);
if (configFile)
fclose(configFile);
if (fields)
free(fields);
fields = NULL;
sensor_info_arr = NULL;
device_info_arr = NULL;
configFile = NULL;
return ret_val;
}