From: Chanwoo Choi Date: Tue, 28 Jan 2020 05:47:44 +0000 (+0900) Subject: pass: rescon: Add support for multiple scenario pass_level X-Git-Tag: submit/tizen/20200227.020232~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d54cf9cc4588b52f41a420d268e976c35b45f957;p=platform%2Fcore%2Fsystem%2Fpass.git pass: rescon: Add support for multiple scenario pass_level PASS provides multiple modules like CPUHP (CPU Hotplug Manager), PMQoS, Thermal Monitor and so on. Each module requires their own pass_level in order to change h/w resources such as the number of online CPU, the minimum/maximum frequency of GPU. Prior to that, PASS supports only 'pass_level'. If user of PASS want to set 'AppLaunch' scenario of PMQoS module, PMQoS only requires the range of 'pass_level' like the minimum and maximum 'pass_level'. It is not enough to meet the requirements from 'AppLaunch' scenario. Some scenario might require the more detailed changes than already defined 'pass_level'. In result of these requirements, add support for new 'scenario pass_level' for scenarios such as AppLaunch of PMQoS and WarningAction of Thermal Monitor. 'scenario pass_level' is possible to specify the detailed value of h/w resources such as the minimum/maximum frequency (limit_(min|max)_freq), the minimum/maximum number of online CPU (limit_(min|max)_cpu) and fault_around_bytes for memorh h/w resource. In order to support the multiple scenario pass_level at the same time, RESCON (Resource Controller) module adds new following functions and then delete previous function. PMQoS will use new functions for supporting the 'scenario pass_level' and Thermal Monitor will use the new functions for 'scenario pass_level' for constrainting the h/w resouece to prevent the dangerous overheating. [Added new functions] - int pass_rescon_sync(struct pass_resource *res); - int pass_rescon_set_level_sync(struct pass_resource *res, int level); - int pass_rescon_set_scenario_level_sync(struct pass_resource *res, int scenario_level); - int pass_rescon_unset_scenario_level_sync(struct pass_resource *res, int scenario_level); - int pass_rescon_set_scenario_level(struct pass_resource *res, int scenario_level); - int pass_rescon_unset_scenario_level(struct pass_resource *res, int scenario_level); [Deleted functions] - int pass_rescon_set_level_scope(struct pass_resource *res, int new_level, int min_level, int max_level, void *data); [Deprecated functions. Because these functions are keeping for the compatibility with legacy feature. It should be used on PMQoS module.] - int pass_rescon_set_scenario_level_sync_with_data(struct pass_resource *res, int scenario_level, void *data); - int pass_rescon_unset_scenario_level_sync_with_data(struct pass_resource *res, int scenario_level, void *data); [Exmaple of multiple scenario pass_level on PMQoS and Thermal Monitor modules] Case 1. AppLaunch scenario of PMQoS , - 'AppLaunch' scenario contains 'scenario_level=1' property as following: [ScenarioLevel1] limit_min_freq=1300000 limit_max_freq=1300000 limit_min_cpu=3 limit_max_cpu=4 - In result, RESCON (Resource Controller) set h/w resource as following: The minimum frequency is 1300MHz. The maximum frequency is 1300MHz. The minimum number of online CPU is 3. The maximum number of online CPU is 4. -> It maintains 1300MHz and three online CPU. Case 2. Warning scenario of Thermal Monitor, - 'Warning' scenario contains 'scenario_level=2' property as following: [ScenarioLevel2] limit_min_freq=768000 limit_max_freq=1000000 limit_min_cpu=0 limit_max_cpu=2 - In result, RESCON (Resource Controller) set h/w resource as following: The minimum frequency is 768MHz. The maximum frequency is 1000MHz. The minimum number of online CPU has no any constraint. The maximum number of online CPU is 2. -> It maintain 768MHz and doesn't turn on more than 2 CPU. Case 3. AppLaunch scenario of PMQoS + Warning scenario of Thermal Monitor, - 'AppLaunch' scenario contains 'scenario_level=1' property and 'Warning' scenario contains 'scenario_level=2' property as following: [ScenarioLevel1] limit_min_freq=1300000 limit_max_freq=1300000 limit_min_cpu=3 limit_max_cpu=4 [ScenarioLevel2] limit_min_freq=768000 limit_max_freq=1000000 limit_min_cpu=0 limit_max_cpu=2 - In result, RESCON (Resource Controller) set h/w resource as following: The minimum frequency is 1000MHz because MAX(1300000, 768000) cannot be over thatn maximum frequency (1000MHz). The maximum frequency is 1000MHz. The minimum number of online CPU is 2. The maximum number of online CPU is 2. -> It maintain 1000MHz and doesn't turn on more than 2 CPU. [ScenarioLevel0] limit_min_freq=768000 limit_max_freq=1300000 limit_min_cpu=0 limit_max_cpu=4 [ScenarioLevel1] limit_min_freq=1300000 limit_max_freq=1300000 limit_min_cpu=3 limit_max_cpu=4 [ScenarioLevel2] limit_min_freq=768000 limit_max_freq=1000000 limit_min_cpu=0 limit_max_cpu=2 [PassScenario] pass_scenario_support=yes pass_num_scenarios=1 [Scenario0] name=AppLaunch support=yes scenario_level=1 <- It indicates 'ScenarioLevel1' for AppLaunch scenario. [thermal] thermal_support=yes thermal_number_of_scenario=2 thermal_timer_interval_ms=5000 [thermal.scenario0] support=yes name=Release temperature=25 timer_interval_ms=5000 scenario_level=0 [thermal.scenario1] support=yes name=Warning temperature=30 timer_interval_ms=3000 scenario_level=2 <- It indicates 'ScenarioLevel2' for Warning scenario. Change-Id: I45e99b1794b85342f29bf0decec6a859f56f8f58 Signed-off-by: Chanwoo Choi --- diff --git a/src/pass/pass-cpuhp.c b/src/pass/pass-cpuhp.c index d659416..5345e03 100644 --- a/src/pass/pass-cpuhp.c +++ b/src/pass/pass-cpuhp.c @@ -192,7 +192,7 @@ static int cpuhp_timer_func(void *result, void *user_data) if (cpuhp->governor->governor) { level = cpuhp->governor->governor(res, result); - pass_rescon_set_level(res, level); + pass_rescon_set_level_sync(res, level); } else { _E("cannot call the governor function"); cpuhp_governor_update(res, PASS_OFF); diff --git a/src/pass/pass-parser.c b/src/pass/pass-parser.c index ac2d46f..26292a6 100644 --- a/src/pass/pass-parser.c +++ b/src/pass/pass-parser.c @@ -1006,9 +1006,9 @@ int pass_get_each_resource_config(struct pass_resource *res, char *path) /* Initialize the ResCon's data */ res->rescon.init_level = INIT_VALUE; - res->rescon.prev_level = 0; - res->rescon.min_level = 0; - res->rescon.max_level = 0; + res->rescon.prev_level = INIT_VALUE; + res->rescon.min_level = INIT_VALUE; + res->rescon.max_level = INIT_VALUE; res->rescon.init_scenario_level = INIT_VALUE; /* Initialize the CPUHP's data */ diff --git a/src/pass/pass-pmqos.c b/src/pass/pass-pmqos.c index dd96e8c..3fd69a8 100644 --- a/src/pass/pass-pmqos.c +++ b/src/pass/pass-pmqos.c @@ -74,9 +74,6 @@ static int pmqos_notifier_cb(void *data, void *user_data) struct pass_scenario *scn = NULL; enum pass_state locked = PASS_UNUSED; char name[BUFF_MAX] = {""}; - unsigned int new_level = 0; - unsigned int min_level = 0; - unsigned int max_level = 0; int index = -1; if (!res) @@ -140,52 +137,31 @@ static int pmqos_notifier_cb(void *data, void *user_data) scn->pmqos.locked = locked; if (scn->pmqos.locked) { - if (pmqos->num_locked_scenarios == 0) - new_level = pmqos->init_level = res->rescon.curr_level; - else - new_level = pmqos->curr_level; - min_level = MAX(scn->pmqos.min_level, pmqos->min_level); - max_level = MAX(scn->pmqos.max_level, pmqos->max_level); - - if (new_level < min_level) - new_level = min_level; - else if (new_level > max_level) - new_level = scn->pmqos.max_level; - - pmqos->curr_level = new_level; - pmqos->min_level = min_level; - pmqos->max_level = max_level; - - pmqos->num_locked_scenarios++; - } else { - pmqos->num_locked_scenarios--; - - if (pmqos->num_locked_scenarios == 0) { - new_level = pmqos->init_level; - min_level = res->config_data.default_min_level; - max_level = res->config_data.default_max_level; + pass_rescon_set_scenario_level_sync_with_data(res, scn->level, data); - pmqos->curr_level = 0; - pmqos->min_level = 0; - pmqos->max_level = 0; + if (scn->level < 0) { + _I("Lock '%s' scenario for '%s' resource\n", + name, config_data->res_name); } else { - new_level = pmqos->curr_level; - min_level = pmqos->min_level; - max_level = pmqos->max_level; + _I("Lock '%s' scenario with 'ScenarioLevel%d' " \ + "for '%s' resource\n", + name, scn->level, config_data->res_name); } - } - - pass_rescon_set_level_scope(res, new_level, min_level, max_level, data); - - if (scn->pmqos.locked) { - _I("Lock '%s' scenario for '%s' resource\n", - name, config_data->res_name); pmqos->scenarios[index].pmqos.locked_time = get_time_ms(); } else { - _I("UnLock '%s' scenario for '%s' resource (%"PRId64"ms)\n", - name, config_data->res_name, - (get_time_ms() - pmqos->scenarios[index].pmqos.locked_time)); + if (scn->level < 0) { + _I("UnLock '%s' scenario for '%s' resource (%"PRId64"ms)\n", + name, config_data->res_name, + (get_time_ms() - pmqos->scenarios[index].pmqos.locked_time)); + } else { + _I("UnLock '%s' scenario with 'ScenarioLevel%d' " \ + "for '%s' resource (%"PRId64"ms)\n", + name, scn->level, config_data->res_name, + (get_time_ms() - pmqos->scenarios[index].pmqos.locked_time)); + } + + pass_rescon_unset_scenario_level_sync_with_data(res, scn->level, data); pmqos->scenarios[index].pmqos.locked_time = 0; } diff --git a/src/pass/pass-rescon.c b/src/pass/pass-rescon.c index c156a17..0ff6328 100644 --- a/src/pass/pass-rescon.c +++ b/src/pass/pass-rescon.c @@ -33,37 +33,141 @@ #include "pass.h" #include "pass-hal.h" -/** - * @brief Set the next pass_level required from modules like - * PASS_MODULE_CPUHP, PASS_MODULE_PMQOS and so on. The demanded - * pass_level has the different h/w value such as minimum/maximum - * frequency, the number of online CPU, fault_around_bytes and son - * on. It changes the h/w value by using the data within the - * demanded pass_level and it is final step to change h/w value. - * @param [in] res Instance of h/w resource - * @param [in] new_level Index of demanded pass_level - * @return @c 0 on success, otherwise error value - */ -static int rescon_set_level(struct pass_resource *res, int new_level) +#define MAX_INT 1000000000 +#define MIN_INT 0 +#define MIN_FAULT_AROUND_BYTES 4096 +#define MAX_FAULT_AROUND_BYTES 65536 + +static void rescon_print_level(struct pass_resource *res, + struct pass_level *level) +{ + if (!res || !level) + return; + + /* Add blank line for improving the readability on dlog */ + _D(""); + + if (level->limit_min_freq > 0) { + _D("MIN Frequency is %10d of '%s' resource \n", + level->limit_min_freq, + res->config_data.res_name); + } + + if (level->limit_max_freq > 0) { + _D("MAX Frequency is %10d of '%s' resource\n", + level->limit_max_freq, + res->config_data.res_name); + } + + if (level->limit_min_cpu >= 0) { + _D("MIN CPU number is %10d of '%s' resource\n", + level->limit_min_cpu, + res->config_data.res_name); + } + + if (level->limit_max_cpu >= 0) { + _D("MAX CPU number is %10d of '%s' resource\n", + level->limit_max_cpu, + res->config_data.res_name); + } + + if (level->fault_around_bytes > 0) { + _D("fault_around_byte is %10d of '%s' resource\n", + level->fault_around_bytes, + res->config_data.res_name); + } +} + +static void rescon_adjust_level(struct pass_level *a, struct pass_level *b) +{ + /* Adjust limit_min_freq and limit_max_freq */ + a->limit_min_freq = MAX(a->limit_min_freq, b->limit_min_freq); + a->limit_max_freq = MIN(a->limit_max_freq, b->limit_max_freq); + + if (a->limit_min_freq > a->limit_max_freq) + a->limit_min_freq = a->limit_max_freq; + + /* Adjust limit_min_cpu and limit_max_cpu */ + a->limit_min_cpu = MAX(a->limit_min_cpu, b->limit_min_cpu); + a->limit_max_cpu = MIN(a->limit_max_cpu, b->limit_max_cpu); + + if (a->limit_min_cpu > a->limit_max_cpu) + a->limit_min_cpu = a->limit_max_cpu; + + /* Adjust fault_around_bytes */ + a->fault_around_bytes = MAX(a->fault_around_bytes, + b->fault_around_bytes); + + if (a->fault_around_bytes > 0) { + if (a->fault_around_bytes < MIN_FAULT_AROUND_BYTES) + a->fault_around_bytes = MIN_FAULT_AROUND_BYTES; + if (a->fault_around_bytes > MAX_FAULT_AROUND_BYTES) + a->fault_around_bytes = MAX_FAULT_AROUND_BYTES; + } +} + +static int rescon_update(struct pass_resource *res) { + struct pass_rescon *rescon = &res->rescon; struct pass_level *levels = res->config_data.levels; - int curr_level = res->rescon.curr_level; - int limit_max_freq; - int limit_min_freq; - int limit_max_cpu; - int limit_min_cpu; - int fault_around_bytes; + struct pass_level *scenario_levels = res->config_data.scenario_levels; + struct pass_level adjusted_level; + GList *list = rescon->scenario_level_list; + int res_type = res->config_data.res_type; + int limit_max_freq = -1; + int limit_min_freq = -1; + int limit_min_cpu = -1; + int limit_max_cpu = -1; + int fault_around_bytes = -1; int ret, i; + int failed = 0; - /* Get the detailed resource value according to PASS level */ - limit_max_freq = levels[new_level].limit_max_freq; - limit_min_freq = levels[new_level].limit_min_freq; - limit_max_cpu = levels[new_level].limit_max_cpu; - limit_min_cpu = levels[new_level].limit_min_cpu; - fault_around_bytes = levels[new_level].fault_around_bytes; - - res->rescon.prev_level = curr_level; - res->rescon.curr_level = new_level; + /* + * Multiple PASS modules can require the change of h/w resource by + * using pass_level at the same time. It means RESCON (Resource + * Controller) have to adjust the values of h/w resource among + * the required pass_levels. + */ + adjusted_level.limit_min_freq = MIN_INT; + adjusted_level.limit_max_freq = MAX_INT; + adjusted_level.limit_min_cpu = MIN_INT; + adjusted_level.limit_max_cpu = MAX_INT; + adjusted_level.fault_around_bytes = MIN_INT; + + /* Adjust with pass_level */ + if (res->rescon.curr_level >= 0) + rescon_adjust_level(&adjusted_level, &levels[rescon->curr_level]); + + /* Adjust with scenario pass_level */ + g_mutex_lock(&rescon->scenario_level_mutex); + while (list != NULL) { + i = GPOINTER_TO_INT(list->data); + list = g_list_next(list); + + if (i < 0) + continue; + rescon_adjust_level(&adjusted_level, &scenario_levels[i]); + } + g_mutex_unlock(&rescon->scenario_level_mutex); + + switch (res_type) { + case PASS_RESOURCE_CPU_ID: + limit_min_cpu = adjusted_level.limit_min_cpu; + limit_max_cpu = adjusted_level.limit_max_cpu; + /* fall through */ + case PASS_RESOURCE_GPU_ID: + case PASS_RESOURCE_BUS_ID: + limit_max_freq = adjusted_level.limit_max_freq; + limit_min_freq = adjusted_level.limit_min_freq; + break; + case PASS_RESOURCE_MEMORY_ID: + fault_around_bytes = adjusted_level.fault_around_bytes; + break; + case PASS_RESOURCE_NONSTANDARD_ID: + break; + default: + return -EINVAL; + } /* Turn on/off CPUs according to the required number of online CPU */ if (limit_min_cpu >= 0 && limit_max_cpu >= 0) { @@ -75,31 +179,78 @@ static int rescon_set_level(struct pass_resource *res, int new_level) if (limit_min_cpu > limit_max_cpu) limit_min_cpu = limit_max_cpu; - pass_set_online_min_num(res, limit_min_cpu); - pass_set_online_max_num(res, limit_max_cpu); + ret = pass_set_online_min_num(res, limit_min_cpu); + if (ret == -EPERM || ret == -ENODEV) { + /* + * If -EPERM, function is not supported according to + * h/w resource type. And if -ENODEV, function is not + * implemented on HAL package. It means that this + * function is not necessary on two error case + * when calling the HAL functions. + */ + ; + } else if (ret < 0) { + _W("failed to set the minimum number of cpu(%d) of %s", + limit_min_cpu, + res->config_data.res_name); + failed = 1; + } + + ret = pass_set_online_max_num(res, limit_max_cpu); + if (ret == -EPERM || ret == -ENODEV) { + ; + } else if (ret < 0) { + _W("failed to set the maximum number of cpu(%d) of %s", + limit_max_cpu, + res->config_data.res_name); + failed = 1; + } - for (i = 0; i < limit_max_cpu; i++) - pass_set_online_state(res, res->config_data.cpu + i, + for (i = 0; i < limit_max_cpu; i++) { + ret = pass_set_online_state(res, + res->config_data.cpu + i, (i < limit_min_cpu) ? 1 : 0); + if (ret == -EPERM || ret == -ENODEV) { + ; + } else if (ret < 0) { + _W("failed to turn %s of cpu%d of %s", + (i < limit_min_cpu) ? "on" : "off", + res->config_data.cpu + i, + res->config_data.res_name); + failed = 1; + } + } + } - /* Set maximum frequency */ - if (limit_max_freq > 0) { - ret = pass_set_max_freq(res, limit_max_freq); - if (ret < 0) { - _E("cannot set the maximum frequency of %s", + /* Set minimum and maximum frequency */ + if (limit_max_freq > 0 && limit_min_freq > 0) { + int curr_min_freq = pass_get_min_freq(res); + int curr_max_freq = pass_get_max_freq(res); + int ret_min; + int ret_max; + + if ((limit_max_freq > curr_min_freq) + && (limit_min_freq > curr_max_freq)) { + ret_max = pass_set_max_freq(res, limit_max_freq); + ret_min = pass_set_min_freq(res, limit_min_freq); + } else { + ret_min = pass_set_min_freq(res, limit_min_freq); + ret_max = pass_set_max_freq(res, limit_max_freq); + } + + if (ret_max < 0) { + _W("failed to set the maximum frequency(%d) of %s", + limit_max_freq, res->config_data.res_name); - return -EINVAL; + failed = 1; } - } - /* Set minimum frequency */ - if (limit_min_freq > 0) { - ret = pass_set_min_freq(res, limit_min_freq); - if (ret < 0) { - _E("cannot set the minimum frequency of %s", + if (ret_min < 0) { + _W("failed to set the minimum frequency(%d) of %s", + limit_min_freq, res->config_data.res_name); - return -EINVAL; + failed = 1; } } @@ -107,26 +258,67 @@ static int rescon_set_level(struct pass_resource *res, int new_level) if (fault_around_bytes > 0) { ret = pass_set_fault_around_bytes(res, fault_around_bytes); if (ret < 0) { - _E("cannot set the fault_around_bytes of %s", + _W("failed to set the fault_around_bytes(%d) of %s", + fault_around_bytes, res->config_data.res_name); - return -EINVAL; + failed = 1; } } - /* - _I("[PASS %s] Level %4s '%d->%d' : 'max %d | min %d'Hz/'%d'Core\n", - res->config_data.res_name, - (curr_level > new_level ? "DOWN" : "UP"), - curr_level, new_level, - limit_max_freq, limit_min_freq, limit_min_cpu); - */ + if (!failed) + rescon_print_level(res, &adjusted_level); + else + _W("failed to update %s h/w resource", + res->config_data.res_name); return 0; }; +static void rescon_set_scenario_level(struct pass_resource *res, + int scenario_level) +{ + struct pass_rescon *rescon = &res->rescon; + + if (scenario_level < 0) + return; + + g_mutex_lock(&rescon->scenario_level_mutex); + rescon->scenario_level_list = g_list_append(rescon->scenario_level_list, + GINT_TO_POINTER(scenario_level)); + + g_mutex_unlock(&rescon->scenario_level_mutex); +} + +static void rescon_unset_scenario_level(struct pass_resource *res, + int scenario_level) +{ + struct pass_rescon *rescon = &res->rescon; + + if (scenario_level < 0) + return; + + g_mutex_lock(&rescon->scenario_level_mutex); + rescon->scenario_level_list = g_list_remove(rescon->scenario_level_list, + GINT_TO_POINTER(scenario_level)); + g_mutex_unlock(&rescon->scenario_level_mutex); +} + +/* + * @brief Update pass_level with sync by all PASS_MODULE_* + * @param [in] res Instance of struct pass_resource + * @param [in] scenario_level Index of scenario level + * @scenario_level: the scenario level + */ +int pass_rescon_sync(struct pass_resource *res) +{ + if (!res) + return -EINVAL; + + return rescon_update(res); +} + /** - * @brief Adjust the demanded pass_level by using the supported minimum - * and maximum pass_level. + * @brief Set pass_level by PASS_MODULE_CPUHP * @param [in] res Instance of h/w resource * @param [in] new_level Index of demanded pass_level * @return @c 0 on success, otherwise error value @@ -136,6 +328,9 @@ int pass_rescon_set_level(struct pass_resource *res, int new_level) if (!res) return -EINVAL; + if (new_level < 0) + return 0; + if (new_level > res->rescon.max_level) new_level = res->rescon.max_level; @@ -145,25 +340,120 @@ int pass_rescon_set_level(struct pass_resource *res, int new_level) if (new_level == res->rescon.curr_level) return 0; - return rescon_set_level(res, new_level); + res->rescon.prev_level = res->rescon.curr_level; + res->rescon.curr_level = new_level; + + return 0; }; /** - * @brief Change the range of pass_level like the minimum and maximum - * pass_level. + * @brief Set pass_level with sync by PASS_MODULE_CPUHP * @param [in] res Instance of h/w resource - * @param [in] new_level Demanded pass_level - * @param [in] min_level Minimum pass_level - * @param [in] max_level Maximum pass_level - * @param [in] data PMQoS data containing the scenario name and lock state + * @param [in] new_level Index of demanded pass_level * @return @c 0 on success, otherwise error value */ -int pass_rescon_set_level_scope(struct pass_resource *res, int new_level, - int min_level, int max_level, void *data) +int pass_rescon_set_level_sync(struct pass_resource *res, int new_level) { if (!res) return -EINVAL; + if (new_level < 0) + return 0; + + if (new_level > res->rescon.max_level) + new_level = res->rescon.max_level; + + if (new_level < res->rescon.min_level) + new_level = res->rescon.min_level; + + if (new_level == res->rescon.curr_level) + return 0; + + res->rescon.prev_level = res->rescon.curr_level; + res->rescon.curr_level = new_level; + + return rescon_update(res); +}; + +/** + * @brief Set scenario pass_level with sync by PASS_MODULE_(PMQOS|THERMAL). + * @param [in] res Instance of h/w resource + * @param [in] scenario_level Index of demanded pass_level + * @return @c 0 on success, otherwise error value + */ +int pass_rescon_set_scenario_level(struct pass_resource *res, + int scenario_level) +{ + if (!res) + return -EINVAL; + + rescon_set_scenario_level(res, scenario_level); + + return 0; +} + +/* + * @brief Unset the scenario pass_level by PASS_MODULE_(PMQOS|THERMAL). + * @param [in] res Instance of struct pass_resource + * @param [in] scenario_level Index of scenario level + * @scenario_level: the scenario level + */ +int pass_rescon_unset_scenario_level(struct pass_resource *res, + int scenario_level) +{ + if (!res) + return -EINVAL; + + rescon_unset_scenario_level(res, scenario_level); + + return 0; +} + +/** + * @brief Set scenario pass_level with sync by PASS_MODULE_(PMQOS|THERMAL). + * @param [in] res Instance of h/w resource + * @param [in] scenario_level Index of demanded pass_level + * @return @c 0 on success, otherwise error value + */ +int pass_rescon_set_scenario_level_sync(struct pass_resource *res, + int scenario_level) +{ + if (!res) + return -EINVAL; + + rescon_set_scenario_level(res, scenario_level); + + return rescon_update(res); +} + +/* + * @brief Unset the scenario pass_level by PASS_MODULE_(PMQOS|THERMAL). + * @param [in] res Instance of struct pass_resource + * @param [in] scenario_level Index of scenario level + * @scenario_level: the scenario level + */ +int pass_rescon_unset_scenario_level_sync(struct pass_resource *res, + int scenario_level) +{ + if (!res) + return -EINVAL; + + rescon_unset_scenario_level(res, scenario_level); + + return rescon_update(res); +} + +/* + * @brief Deprecated function to support backward compatibility with sync. + * Set up the scenario pass_level by PASS_MODULE_PMQOS with data. + * @param [in] res Instance of struct pass_resource + * @param [in] scenario_level Index of scenario level + * @param [in] data PMQoS data containing the scenario name and lock state + * @return @c 0 on success, otherwise error value + */ +int pass_rescon_set_scenario_level_sync_with_data(struct pass_resource *res, + int scenario_level, void *data) +{ /* * FIXME: PMQoS core sends the raw data to the HAL in order to * support the backwards compatibility. This function call will @@ -172,23 +462,33 @@ int pass_rescon_set_level_scope(struct pass_resource *res, int new_level, if (data) pass_set_pmqos_data(res, data); - if (min_level > max_level) { - _E("min_level(%d) have to be smaller than max_level(%d)\n", - min_level, max_level); - return -EINVAL; - } + rescon_set_scenario_level(res, scenario_level); - if (min_level == res->rescon.min_level - && max_level == res->rescon.max_level) - return 0; + return rescon_update(res); +} - /* Change minimum/maximum pass level */ - res->rescon.min_level = min_level; - res->rescon.max_level = max_level; +/* + * @brief Deprecated function to support backward compatibility with sync. + * Unset the scenario pass_level by PASS_MODULE_PMQOS with data. + * @param [in] res Insstance of struct pass_resource + * @param [in] scenario_level Index of scenario level + * @param [in] data PMQoS data containing the scenario name and lock state + * @return @c 0 on success, otherwise error value + */ +int pass_rescon_unset_scenario_level_sync_with_data(struct pass_resource *res, + int scenario_level, void *data) +{ + /* + * FIXME: PMQoS core sends the raw data to the HAL in order to + * support the backwards compatibility. This function call will + * be removed after finding the proper method. + */ + if (data) + pass_set_pmqos_data(res, data); - pass_rescon_set_level(res, new_level); + rescon_unset_scenario_level(res, scenario_level); - return 0; + return rescon_update(res); } /** @@ -207,8 +507,8 @@ int pass_rescon_init(struct pass_resource *res) rescon = &res->rescon; /* Initialize the variables of resource-controller */ - rescon->curr_level = 0; - rescon->prev_level = 0; + rescon->curr_level = -1; + rescon->prev_level = -1; if (!rescon->min_level) rescon->min_level = 0; @@ -218,10 +518,9 @@ int pass_rescon_init(struct pass_resource *res) rescon->max_level = res->config_data.num_levels - 1; res->config_data.default_max_level = rescon->max_level; - if (!rescon->init_level) - rescon->init_level = rescon->min_level; - else if (rescon->init_level > rescon->max_level) - rescon->init_level = rescon->max_level; + /* Initialize g_list of scenario_level */ + rescon->scenario_level_list = NULL; + g_mutex_init(&rescon->scenario_level_mutex); /* * Save the current data of h/w resource. The saved data @@ -234,22 +533,33 @@ int pass_rescon_init(struct pass_resource *res) return ret; } - /* Set initial level according to init_level from configuration */ - ret = rescon_set_level(res, rescon->init_level); + /* + * Set initial pass level when starting pass + * - default pass level according to res->init_level + */ + ret = pass_rescon_set_level(res, rescon->init_level); if (ret < 0) { _E("failed to set level%d\n", rescon->init_level); return ret; } /* - * Set default pass level when starting pass - * - default pass level according to res->init_level + * Set initial scenario pass_level when starting pass + * - default pass level according to res->init_scenario_level */ - res->rescon.curr_level = -1; - if (res->rescon.init_level > res->rescon.max_level) - res->rescon.init_level = res->rescon.max_level; + ret = pass_rescon_set_scenario_level(res, rescon->init_scenario_level); + if (ret < 0) { + _E("failed to set scenario level%d\n", + rescon->init_scenario_level); + return ret; + } - pass_rescon_set_level(res, res->rescon.init_level); + ret = pass_rescon_sync(res); + if (ret < 0) { + _E("failed to synchronize of '%s' resource\n", + res->config_data.res_name); + return ret; + } rescon->state = PASS_ON; @@ -284,6 +594,11 @@ int pass_rescon_exit(struct pass_resource *res) rescon->max_level = 0; rescon->init_level = 0; + /* Free g_list of scenario_level */ + g_list_free(rescon->scenario_level_list); + rescon->scenario_level_list = NULL; + g_mutex_clear(&rescon->scenario_level_mutex); + rescon->state = PASS_OFF; return ret; diff --git a/src/pass/pass-rescon.h b/src/pass/pass-rescon.h index 383c8c6..8227edf 100644 --- a/src/pass/pass-rescon.h +++ b/src/pass/pass-rescon.h @@ -29,8 +29,27 @@ #ifndef __PASS_RESCON__ #define __PASS_RESCON__ +int pass_rescon_sync(struct pass_resource *res); + +int pass_rescon_set_level_sync(struct pass_resource *res, int new_level); +int pass_rescon_set_scenario_level_sync(struct pass_resource *res, + int scenario_level); +int pass_rescon_unset_scenario_level_sync(struct pass_resource *res, + int scenario_level); + int pass_rescon_set_level(struct pass_resource *res, int new_level); -int pass_rescon_set_level_scope(struct pass_resource *res, int new_level, - int min_level, int max_level, void *data); +int pass_rescon_set_scenario_level(struct pass_resource *res, + int scenario_level); +int pass_rescon_unset_scenario_level(struct pass_resource *res, + int scenario_level); + +/* + * Following APIs are deprecated. These functions are provided + * for keeping the compatibility with legacy feature. + */ +int pass_rescon_set_scenario_level_sync_with_data(struct pass_resource *res, + int scenario_level, void *data); +int pass_rescon_unset_scenario_level_sync_with_data(struct pass_resource *res, + int scenario_level, void *data); #endif /* __PASS_RESCON__ */ diff --git a/src/pass/pass.h b/src/pass/pass.h index 22ced5b..a88c61c 100644 --- a/src/pass/pass.h +++ b/src/pass/pass.h @@ -261,23 +261,41 @@ struct pass_rescon { enum pass_state state; /** - * Initial level when initializing h/w resource by resource controller + * Initial level when initializing h/w resource by resource controller. + * If value is -1, it is not initialized by parser. */ int init_level; - /** Current level controlled by resource controller */ - unsigned int curr_level; - /** Previous level controlled by resource controller */ - unsigned int prev_level; - /** Available minimum level controlled by resource controller */ - unsigned int min_level; - /** Available maximum level controlled by resource controller */ - unsigned int max_level; + /** + * Current level controlled by resource controller. + * If value is -1, it is not initialized by parser. + */ + int curr_level; + /** + * Previous level controlled by resource controller. + * If value is -1, it is not initialized by parser. + */ + int prev_level; + /** + * Available minimum level controlled by resource controller. + * If value is -1, it is not initialized by parser. + */ + int min_level; + /** + * Available maximum level controlled by resource controller. + * If value is -1, it is not initialized by parser. + */ + int max_level; /** * Initial level when initializing h/w resource by resource controller. * If value is -1, it is not initialized by parser. */ int init_scenario_level; + + /** Ondemanded scenario list */ + GList *scenario_level_list; + /** Mutex of ondemanded scenario list */ + GMutex scenario_level_mutex; }; /**