SET(SRCS
src/pass/pass.c
- src/pass/pass-core.c
+ src/pass/pass-gov.c
src/pass/pass-gov-radiation.c
src/pass/pass-gov-step.c
src/pass/pass-parser.c
+++ /dev/null
-/*
- * PASS (Power Aware System Service)
- *
- * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include "pass.h"
-#include "pass-gov.h"
-#include "pass-pmqos.h"
-#include "pass-hal.h"
-
-#include "core/device-notifier.h"
-#include "core/config-parser.h"
-
-#define PASS_CPU_STATS_MAX_COUNT 20
-
-/*
- * FIXME: Current notifier of PASS didn't pass separate user_data parameter
- * on callback function. So, PASS must need global pass_policy instance. This
- * code must be modified after changing PASS's notifier feature.
- */
-static struct pass_policy *policy_pmqos[PASS_RESOURCE_MAX];
-static int num_policy_pmqos = 0;
-
-/*
- * is_enabled - Check the state of PASS governor
- * @policy: instance of pass_policy structure
- *
- * Return true if the state of PASS is PASS_GOV_START
- * Return false if the state of PASS is PASS_GOV_STOP
- */
-static bool is_enabled(struct pass_policy *policy)
-{
- if (!policy)
- return false;
-
- if (policy->gov_state != PASS_GOV_START)
- return false;
-
- return true;
-}
-
-/*
- * pass_notifier_booting_done - Callback function of DEVICE_NOTIFIER_BOOTING_
- * DONE notifier
- * @data: NULL, this parameter isn't used
- */
-static int pass_notifier_booting_done(void *data)
-{
- int i;
-
- if (num_policy_pmqos == 0)
- return 0;
-
- /* Start PASS governor if 'pass_support' in pass.conf is true */
- for (i = 0; i < num_policy_pmqos; i++) {
- if (policy_pmqos[i]->state == PASS_ON
- && policy_pmqos[i]->governor != NULL) {
- policy_pmqos[i]->governor->update(policy_pmqos[i],
- PASS_GOV_START);
- }
- }
-
- return 0;
-}
-
-static int pass_notifier_pmqos(void *data)
-{
- int i;
-
- if (num_policy_pmqos == 0)
- return 0;
-
- for (i = 0; i < num_policy_pmqos; i++) {
- if (policy_pmqos[i]->state == PASS_ON
- && policy_pmqos[i]->governor != NULL) {
- pass_notifier_pmqos_func(policy_pmqos[i], data);
- }
- }
-
- return 0;
-}
-
-/*
- * pass_notifier_init - Register notifiers and init
- * @policy: the instance of pass_policy structure
- */
-static int pass_notifier_init(struct pass_policy *policy)
-{
- /* Register DEVICE_NOTIFIER_PMQOS */
- register_notifier(DEVICE_NOTIFIER_PMQOS, pass_notifier_pmqos);
-
- /* Register DEVICE_NOTIFIER_BOOTING_DONE */
- register_notifier(DEVICE_NOTIFIER_BOOTING_DONE,
- pass_notifier_booting_done);
-
- /*
- * FIXME: Current notifier of PASS didn't pass separate user_data
- * parameter on callback function. So, PASS must need global pass_policy
- * instance. This code must be modified after changing PASS's
- * notifier feature.
- */
- policy_pmqos[num_policy_pmqos++] = policy;
-
- return 0;
-}
-
-/*
- * pass_notifier_exit - Un-register notifiers and exit
- * @policy: the instance of pass_policy structure
- */
-static int pass_notifier_exit(struct pass_policy *policy)
-{
- /* Un-register DEVICE_NOTIFIER_PMQOS */
- unregister_notifier(DEVICE_NOTIFIER_PMQOS, pass_notifier_pmqos);
-
- /* Un-Register DEVICE_NOTIFIER_BOOTING_DONE */
- unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE,
- pass_notifier_booting_done);
-
- return 0;
-}
-
-/*****************************************************************************
- * PASS CPU Hotplug *
- ****************************************************************************/
-
-/*
- * pass_hotplug_set_online - Change the maximum number of online cpu
- *
- * @policy: the instance of struct pass_policy
- * @max_online: the maximum number of online cpu
- */
-static void pass_hotplug_set_online(struct pass_policy *policy,
- unsigned int online)
-{
- struct pass_resource *pass_res = to_pass_resource(policy);
- struct pass_hotplug *hotplug = policy->hotplug;
- int i;
-
- if (!hotplug || online == hotplug->online)
- return;
-
- if (online > hotplug->max_online)
- online = hotplug->max_online;
-
- for (i = 0 ; i < policy->cpufreq.num_nr_cpus; i++) {
- if (i < online) {
- pass_set_online_state(pass_res, hotplug->sequence[i],
- PASS_CPU_UP);
- } else {
- pass_set_online_state(pass_res, hotplug->sequence[i],
- PASS_CPU_DOWN);
- }
- }
-
- /*
- _I("- CPU %4s '%d->%d'Core\n",
- (hotplug->online > online ? "DOWN" : "UP"),
- hotplug->online, online);
- */
-
- hotplug->online = online;
-}
-
-/*
- * pass_hotplug_stop - Stop PASS hotplug
- *
- * @policy: the instance of struct pass_policy
- */
-static void pass_hotplug_stop(struct pass_policy *policy)
-{
- struct pass_table *table = policy->pass_table;
- int level = policy->max_level;
-
- if (!policy->hotplug)
- return;
-
- policy->hotplug->online = table[level].limit_max_cpu;
- policy->hotplug->max_online = policy->cpufreq.num_nr_cpus;
-}
-
-static int pass_hotplug_dummy_governor(struct pass_policy *policy)
-{
- int level = policy->curr_level;
-
- return policy->pass_table[level].limit_max_cpu;
-}
-
-/*
- * pass_get_governor - Return specific hotplug instance according to type
- *
- * @type: the type of PASS hotplug
- */
-struct pass_hotplug* pass_get_hotplug(struct pass_policy *policy,
- enum pass_gov_type type)
-{
- struct pass_hotplug *hotplug;
-
- switch (type) {
- case PASS_GOV_STEP:
- case PASS_GOV_RADIATION:
- hotplug = calloc(1, sizeof(struct pass_hotplug));
- if (!hotplug) {
- _E("cannot allocate the memory of struct pass_hotplug");
- return NULL;
- }
- hotplug->governor = pass_hotplug_dummy_governor;
- return hotplug;
- default:
- _E("Unknown hotplug type");
- break;
- };
-
- return NULL;
-}
-
-/*****************************************************************************
- * PASS governor *
- ****************************************************************************/
-
-/*
- * pass_governor_change_level - Change maximum cpu frequency and number of online cpu
- *
- * @policy: the instance of struct pass_policy
- * @level: the pass level
- */
-static int pass_governor_change_level(struct pass_policy *policy, int new_level)
-{
- struct pass_resource *pass_res = to_pass_resource(policy);
- struct pass_conf_data *cdata = &pass_res->cdata;
- struct pass_table *table = policy->pass_table;
- struct pass_hotplug *hotplug = policy->hotplug;
- int curr_level = policy->curr_level;
- int limit_max_freq;
- int limit_max_cpu;
- int online;
- int ret;
-
- if (new_level > policy->max_level)
- new_level = policy->max_level;
-
- if (new_level < policy->min_level)
- new_level = policy->min_level;
-
- if (new_level == curr_level)
- return 0;
-
- /*
- * Get maximum CPU frequency/the maximum number of online CPU
- * according to PASS level.
- */
- limit_max_freq = table[new_level].limit_max_freq;
- limit_max_cpu = table[new_level].limit_max_cpu;
-
- policy->prev_level = policy->curr_level;
- policy->curr_level = new_level;
-
- /* Turn on/off CPUs according the maximum number of online CPU */
- if (hotplug) {
- if (hotplug->max_online != limit_max_cpu)
- hotplug->max_online = limit_max_cpu;
-
- if (hotplug->governor)
- online = hotplug->governor(policy);
- else
- online = 1;
-
- pass_hotplug_set_online(policy, online);
- }
-
- /* Set maximum CPU frequency */
- ret = pass_set_max_freq(pass_res, limit_max_freq);
- if (ret < 0) {
- _E("cannot set the maximum frequency of %s", cdata->res_name);
- return -EINVAL;
- }
-
- /*
- _I("[PASS %s] Level %4s '%d->%d' : '%d'Hz/'%d'Core\n",
- pass_res->cdata.res_name,
- (curr_level > new_level ? "DOWN" : "UP"),
- curr_level, new_level, limit_max_freq, limit_max_cpu);
- */
-
- return 0;
-};
-
-/*
- * pass_calculate_busy_cpu - Count a number of busy cpu among NR_CPUS by using
- * runnable_avg_sum/runnable_avg_period
- *
- * @policy: the instance of struct pass_policy
- */
-static void pass_calculate_busy_cpu(struct pass_policy *policy)
-{
- struct pass_cpu_stats *stats = policy->pass_cpu_stats;
- struct pass_table *table = policy->pass_table;
- unsigned int level = policy->curr_level;
- unsigned int cpu_threshold = 0;
- unsigned int busy_cpu;
- unsigned int cur_freq;
- unsigned int load;
- unsigned int sum_load;
- unsigned int sum_runnable_load;
- unsigned int nr_runnings;
- int limit_max_cpu;
- int i;
- int j;
-
- limit_max_cpu = table[level].limit_max_cpu;
-
- for (i = 0; i < policy->num_pass_cpu_stats; i++) {
- cur_freq = stats[i].freq;
- nr_runnings = stats[i].nr_runnings;
-
- stats[i].num_busy_cpu = 0;
- stats[i].avg_load = 0;
- stats[i].avg_runnable_load = 0;
- stats[i].avg_thread_load = 0;
- stats[i].avg_thread_runnable_load = 0;
-
- busy_cpu = 0;
- sum_load = 0;
- sum_runnable_load = 0;
-
- /* Calculate the number of busy cpu */
- for (j = 0; j < policy->cpufreq.num_nr_cpus; j++) {
- load = stats[i].load[j];
- sum_load += stats[i].load[j];
- sum_runnable_load += stats[i].runnable_load[j];
- if (!load)
- continue;
-
- cpu_threshold =
- (unsigned int)(cur_freq * load)
- / policy->cpufreq.max_freq;
- if (load == 100
- || cpu_threshold >= policy->pass_cpu_threshold)
- busy_cpu++;
- }
-
- stats[i].num_busy_cpu = busy_cpu;
- stats[i].avg_load = sum_load / limit_max_cpu;
- stats[i].avg_runnable_load = sum_runnable_load / limit_max_cpu;
- if (nr_runnings) {
- stats[i].avg_thread_load
- = (sum_load * 100) / nr_runnings;
- stats[i].avg_thread_runnable_load
- = (sum_runnable_load * 100) / nr_runnings;
- }
- }
-}
-
-/*
- * pass_governor_stop - Stop PASS governor through D-Bus
- *
- * @policy: the instance of struct pass_policy
- */
-static void pass_governor_stop(struct pass_policy *policy)
-{
- struct pass_resource *res = to_pass_resource(policy);
- struct pass_conf_data *cdata = &res->cdata;
-
- if (!policy->governor) {
- _E("cannot stop PASS governor");
- return;
- }
-
- if (policy->gov_state == PASS_GOV_STOP) {
- _E("PASS governor is already inactive state");
- return;
- }
-
- /* Restore maximum cpu freq/the number of online cpu */
- pass_governor_change_level(policy, policy->num_levels - 1);
-
- pass_hotplug_stop(policy);
-
- if (policy->governor->gov_timer_id) {
- ecore_timer_del(policy->governor->gov_timer_id);
- policy->governor->gov_timer_id = NULL;
- }
-
- /* Set PASS state as PASS_GOV_STOP */
- policy->gov_state = PASS_GOV_STOP;
-
- _I("Stop governor for '%s' resource", cdata->res_name);
-}
-
-/*
- * pass_governor_core_timer - Callback function of core timer for PASS governor
- *
- * @data: the instance of struct pass_policy
- */
-static Eina_Bool pass_governor_core_timer(void *data)
-{
- struct pass_policy *policy = (struct pass_policy *)data;
- static int count = 0;
- int level;
- int ret;
-
- if (!policy) {
- _E("cannot execute PASS core timer");
- return ECORE_CALLBACK_CANCEL;
- }
-
- /*
- * Collect data related to system state
- * - current cpu frequency
- * - the number of nr_running
- * - cpu load (= runnable_avg_sum * 100 / runnable_avg_period)
- */
- ret = pass_get_cpu_stats(policy);
- if (ret < 0) {
- if (count++ < PASS_CPU_STATS_MAX_COUNT)
- return ECORE_CALLBACK_RENEW;
-
- count = 0;
-
- _E("cannot read 'pass_cpu_stats' sysfs entry");
- pass_governor_stop(policy);
-
- return ECORE_CALLBACK_CANCEL;
- }
-
- /* Calculate the number of busy cpu */
- pass_calculate_busy_cpu(policy);
-
- /* Determine the amount of proper resource */
- if (policy->governor->governor) {
- level = policy->governor->governor(policy);
-
- pass_governor_change_level(policy, level);
- } else {
- _E("cannot execute governor function");
- pass_governor_stop(policy);
- return ECORE_CALLBACK_CANCEL;
- }
-
- /*
- * Change the period of govenor timer according to PASS level
- */
- if (policy->pass_table[level].gov_timeout >= PASS_MIN_GOV_TIMEOUT &&
- (policy->governor->gov_timeout
- != policy->pass_table[level].gov_timeout)) {
-
- _I("Change the period of governor timer from %fs to %fs\n",
- policy->governor->gov_timeout,
- policy->pass_table[level].gov_timeout);
-
- policy->governor->gov_timeout =
- policy->pass_table[level].gov_timeout;
- ecore_timer_interval_set(policy->governor->gov_timer_id,
- policy->governor->gov_timeout);
- ecore_timer_reset(policy->governor->gov_timer_id);
- }
-
- return ECORE_CALLBACK_RENEW;
-}
-
-/*
- * pass_governor_start - Start PASS governor through D-Bus
- *
- * @policy: the instance of struct pass_policy
- */
-static void pass_governor_start(struct pass_policy *policy)
-{
- struct pass_resource *res = to_pass_resource(policy);
- struct pass_conf_data *cdata = &res->cdata;
-
- if (!policy->governor) {
- _E("cannot start PASS governor");
- return;
- }
-
- if (is_enabled(policy)) {
- _E("PASS governor is already active state");
- return;
- }
-
- /* Create the core timer of PASS governor */
- policy->governor->gov_timer_id = ecore_timer_add(
- policy->governor->gov_timeout,
- (Ecore_Task_Cb)pass_governor_core_timer,
- (void *)policy);
- if (!policy->governor->gov_timer_id) {
- _E("cannot add core timer for governor");
- pass_governor_stop(policy);
- return;
- }
-
- /*
- * Set default pass level when starting pass
- * - default pass level according to policy->init_level
- */
- policy->curr_level = -1;
- if (policy->init_level > policy->max_level)
- policy->init_level = policy->max_level;
- pass_governor_change_level(policy, policy->init_level);
-
- /* Set PASS state as PASS_GOV_START */
- policy->gov_state = PASS_GOV_START;
-
- _I("Start governor for '%s' resource", cdata->res_name);
-}
-
-/*
- * pass_governor_init - Initialize PASS governor
- *
- * @policy: the instance of struct pass_policy
- */
-static int pass_governor_init(struct pass_policy *policy)
-{
- struct pass_resource *res = to_pass_resource(policy);
- struct pass_conf_data *cdata = &res->cdata;
-
- if(policy->governor->gov_timeout < 0) {
- _E("invalid timeout value [%d]!",
- policy->governor->gov_timeout);
- pass_governor_stop(policy);
- return -EINVAL;
- }
-
- /* Set default PASS state */
- policy->gov_state = PASS_GOV_STOP;
-
- /* Initialize notifier */
- pass_notifier_init(policy);
-
- _I("Initialize governor for '%s' resource", cdata->res_name);
-
- return 0;
-}
-
-/*
- * pass_governor_exit - Exit PASS governor
- */
-static int pass_governor_exit(struct pass_policy *policy)
-{
- struct pass_resource *res = to_pass_resource(policy);
- struct pass_conf_data *cdata = &res->cdata;
- int i;
-
- /* Exit notifier */
- pass_notifier_exit(policy);
-
- /*
- * Stop core timer and
- * Restore maximum online cpu/cpu frequency
- */
- pass_governor_stop(policy);
-
- /* Free allocated memory */
- for (i = 0; i < policy->num_pass_cpu_stats; i++) {
- free(policy->pass_cpu_stats[i].load);
- free(policy->pass_cpu_stats[i].nr_running);
- free(policy->pass_cpu_stats[i].runnable_load);
- }
- free(policy->pass_cpu_stats);
-
- if (policy->hotplug)
- free(policy->hotplug->sequence);
-
- if (num_policy_pmqos > 0) {
- for (i = 0; i < num_policy_pmqos; i++)
- policy_pmqos[i] = NULL;
- num_policy_pmqos = 0;
- }
-
- /* Set pass_policy structure as default value */
- policy->pass_cpu_threshold = 0;
- policy->up_threshold = 0;
- policy->down_threshold = 0;
-
- policy->prev_level = 0;
- policy->curr_level = 0;
- policy->min_level = 0;
- policy->max_level = 0;
- policy->level_up_threshold = 0;
-
- policy->pass_table = NULL;
- policy->num_pass_cpu_stats = 0;
-
- policy->governor->gov_timeout = 0;
-
- policy->governor = NULL;
-
- _I("Exit governor for '%s' resource", cdata->res_name);
-
- return 0;
-}
-
-/*
- * pass_governor_update - Restart/Pause PASS governor
- *
- * @cond: the instance of struct pass_policy
- */
-static int pass_governor_update(struct pass_policy *policy,
- enum pass_gov_state state)
-{
- if (!policy) {
- _E("cannot update PASS governor");
- return -EINVAL;
- }
-
- switch (state) {
- case PASS_GOV_START:
- pass_governor_start(policy);
- break;
- case PASS_GOV_STOP:
- pass_governor_stop(policy);
- break;
- default:
- _E("Unknown governor state");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * pass_governor_change_level_scope - Change the scope of cpufreq scaling
- *
- * @policy: the instance of struct pass_policy
- * @min_level: the minimum level of cpufreq scaling
- * @max_level: the maximum level of cpufreq scaling
- */
-int pass_governor_change_level_scope(struct pass_policy *policy,
- int min_level, int max_level)
-{
- if (!policy)
- return -EINVAL;
-
- if (min_level > max_level) {
- _E("min_level(%d) have to be smaller than max_level(%d)\n",
- min_level, max_level);
- return -EINVAL;
- }
-
- if (min_level == policy->min_level
- && max_level == policy->max_level)
- return 0;
-
- /* Change minimum/maximum level of cpufreq scaling */
- policy->min_level = min_level;
- policy->max_level = max_level;
-
- pass_governor_change_level(policy, policy->curr_level);
-
- return 0;
-}
-
-/*
- * Define PASS governor
- *
- * - Step governor
- * - Radiation governor
- */
-static struct pass_governor pass_gov_step = {
- .name = "pass_step",
- .init = pass_governor_init,
- .exit = pass_governor_exit,
- .update = pass_governor_update,
-
- .governor = pass_step_governor,
-};
-
-static struct pass_governor pass_gov_radiation = {
- .name = "pass_radiation",
- .init = pass_governor_init,
- .exit = pass_governor_exit,
- .update = pass_governor_update,
-
- .governor = pass_radiation_governor,
-};
-
-/*
- * pass_get_governor - Return specific governor instance according to type
- *
- * @type: the type of PASS governor
- */
-struct pass_governor* pass_get_governor(struct pass_policy *policy,
- enum pass_gov_type type)
-{
- switch (type) {
- case PASS_GOV_STEP:
- return &pass_gov_step;
- case PASS_GOV_RADIATION:
- return &pass_gov_radiation;
- default:
- _E("Unknown governor type");
- break;
- };
-
- return NULL;
-}
+++ /dev/null
-/*
- * PASS (Power Aware System Service)
- *
- * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PASS_CORE__
-#define __PASS_CORE__
-
-/*
- * pass_get_governor - Return specific governor instance according to type
- *
- * @policy: the instance of struct pass_policy
- * @type: the type of PASS governor
- */
-struct pass_governor* pass_get_governor(struct pass_policy *policy,
- enum pass_gov_type type);
-
-/*
- * pass_get_hotplug - Return specific hotplug instance according to type
- *
- * @policy: the instance of struct pass_policy
- * @type: the type of PASS governor
- */
-struct pass_hotplug* pass_get_hotplug(struct pass_policy *policy,
- enum pass_gov_type type);
-
-/*
- * pass_governor_change_level_scope - Change the scope of cpufreq scaling
- *
- * @policy: the instance of struct pass_policy
- * @min_level: the minimum level of cpufreq scaling
- * @max_level: the maximum level of cpufreq scaling
- */
-int pass_governor_change_level_scope(struct pass_policy *policy,
- int min_level, int max_level);
-
-#endif /* __PASS_CORE__ */
--- /dev/null
+/*
+ * PASS (Power Aware System Service) Governor
+ *
+ * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "pass.h"
+#include "pass-gov.h"
+#include "pass-pmqos.h"
+#include "pass-hal.h"
+
+#include "core/device-notifier.h"
+#include "core/config-parser.h"
+
+#define PASS_CPU_STATS_MAX_COUNT 20
+
+/*
+ * FIXME: Current notifier of PASS didn't pass separate user_data parameter
+ * on callback function. So, PASS must need global pass_policy instance. This
+ * code must be modified after changing PASS's notifier feature.
+ */
+static struct pass_policy *policy_pmqos[PASS_RESOURCE_MAX];
+static int num_policy_pmqos = 0;
+
+/*
+ * is_enabled - Check the state of PASS governor
+ * @policy: instance of pass_policy structure
+ *
+ * Return true if the state of PASS is PASS_GOV_START
+ * Return false if the state of PASS is PASS_GOV_STOP
+ */
+static bool is_enabled(struct pass_policy *policy)
+{
+ if (!policy)
+ return false;
+
+ if (policy->gov_state != PASS_GOV_START)
+ return false;
+
+ return true;
+}
+
+/*
+ * pass_notifier_booting_done - Callback function of DEVICE_NOTIFIER_BOOTING_
+ * DONE notifier
+ * @data: NULL, this parameter isn't used
+ */
+static int pass_notifier_booting_done(void *data)
+{
+ int i;
+
+ if (num_policy_pmqos == 0)
+ return 0;
+
+ /* Start PASS governor if 'pass_support' in pass.conf is true */
+ for (i = 0; i < num_policy_pmqos; i++) {
+ if (policy_pmqos[i]->state == PASS_ON
+ && policy_pmqos[i]->governor != NULL) {
+ policy_pmqos[i]->governor->update(policy_pmqos[i],
+ PASS_GOV_START);
+ }
+ }
+
+ return 0;
+}
+
+static int pass_notifier_pmqos(void *data)
+{
+ int i;
+
+ if (num_policy_pmqos == 0)
+ return 0;
+
+ for (i = 0; i < num_policy_pmqos; i++) {
+ if (policy_pmqos[i]->state == PASS_ON
+ && policy_pmqos[i]->governor != NULL) {
+ pass_notifier_pmqos_func(policy_pmqos[i], data);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * pass_notifier_init - Register notifiers and init
+ * @policy: the instance of pass_policy structure
+ */
+static int pass_notifier_init(struct pass_policy *policy)
+{
+ /* Register DEVICE_NOTIFIER_PMQOS */
+ register_notifier(DEVICE_NOTIFIER_PMQOS, pass_notifier_pmqos);
+
+ /* Register DEVICE_NOTIFIER_BOOTING_DONE */
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE,
+ pass_notifier_booting_done);
+
+ /*
+ * FIXME: Current notifier of PASS didn't pass separate user_data
+ * parameter on callback function. So, PASS must need global pass_policy
+ * instance. This code must be modified after changing PASS's
+ * notifier feature.
+ */
+ policy_pmqos[num_policy_pmqos++] = policy;
+
+ return 0;
+}
+
+/*
+ * pass_notifier_exit - Un-register notifiers and exit
+ * @policy: the instance of pass_policy structure
+ */
+static int pass_notifier_exit(struct pass_policy *policy)
+{
+ /* Un-register DEVICE_NOTIFIER_PMQOS */
+ unregister_notifier(DEVICE_NOTIFIER_PMQOS, pass_notifier_pmqos);
+
+ /* Un-Register DEVICE_NOTIFIER_BOOTING_DONE */
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE,
+ pass_notifier_booting_done);
+
+ return 0;
+}
+
+/*****************************************************************************
+ * PASS CPU Hotplug *
+ ****************************************************************************/
+
+/*
+ * pass_hotplug_set_online - Change the maximum number of online cpu
+ *
+ * @policy: the instance of struct pass_policy
+ * @max_online: the maximum number of online cpu
+ */
+static void pass_hotplug_set_online(struct pass_policy *policy,
+ unsigned int online)
+{
+ struct pass_resource *pass_res = to_pass_resource(policy);
+ struct pass_hotplug *hotplug = policy->hotplug;
+ int i;
+
+ if (!hotplug || online == hotplug->online)
+ return;
+
+ if (online > hotplug->max_online)
+ online = hotplug->max_online;
+
+ for (i = 0 ; i < policy->cpufreq.num_nr_cpus; i++) {
+ if (i < online) {
+ pass_set_online_state(pass_res, hotplug->sequence[i],
+ PASS_CPU_UP);
+ } else {
+ pass_set_online_state(pass_res, hotplug->sequence[i],
+ PASS_CPU_DOWN);
+ }
+ }
+
+ /*
+ _I("- CPU %4s '%d->%d'Core\n",
+ (hotplug->online > online ? "DOWN" : "UP"),
+ hotplug->online, online);
+ */
+
+ hotplug->online = online;
+}
+
+/*
+ * pass_hotplug_stop - Stop PASS hotplug
+ *
+ * @policy: the instance of struct pass_policy
+ */
+static void pass_hotplug_stop(struct pass_policy *policy)
+{
+ struct pass_table *table = policy->pass_table;
+ int level = policy->max_level;
+
+ if (!policy->hotplug)
+ return;
+
+ policy->hotplug->online = table[level].limit_max_cpu;
+ policy->hotplug->max_online = policy->cpufreq.num_nr_cpus;
+}
+
+static int pass_hotplug_dummy_governor(struct pass_policy *policy)
+{
+ int level = policy->curr_level;
+
+ return policy->pass_table[level].limit_max_cpu;
+}
+
+/*
+ * pass_get_governor - Return specific hotplug instance according to type
+ *
+ * @type: the type of PASS hotplug
+ */
+struct pass_hotplug* pass_get_hotplug(struct pass_policy *policy,
+ enum pass_gov_type type)
+{
+ struct pass_hotplug *hotplug;
+
+ switch (type) {
+ case PASS_GOV_STEP:
+ case PASS_GOV_RADIATION:
+ hotplug = calloc(1, sizeof(struct pass_hotplug));
+ if (!hotplug) {
+ _E("cannot allocate the memory of struct pass_hotplug");
+ return NULL;
+ }
+ hotplug->governor = pass_hotplug_dummy_governor;
+ return hotplug;
+ default:
+ _E("Unknown hotplug type");
+ break;
+ };
+
+ return NULL;
+}
+
+/*****************************************************************************
+ * PASS governor *
+ ****************************************************************************/
+
+/*
+ * pass_governor_change_level - Change maximum cpu frequency and number of online cpu
+ *
+ * @policy: the instance of struct pass_policy
+ * @level: the pass level
+ */
+static int pass_governor_change_level(struct pass_policy *policy, int new_level)
+{
+ struct pass_resource *pass_res = to_pass_resource(policy);
+ struct pass_conf_data *cdata = &pass_res->cdata;
+ struct pass_table *table = policy->pass_table;
+ struct pass_hotplug *hotplug = policy->hotplug;
+ int curr_level = policy->curr_level;
+ int limit_max_freq;
+ int limit_max_cpu;
+ int online;
+ int ret;
+
+ if (new_level > policy->max_level)
+ new_level = policy->max_level;
+
+ if (new_level < policy->min_level)
+ new_level = policy->min_level;
+
+ if (new_level == curr_level)
+ return 0;
+
+ /*
+ * Get maximum CPU frequency/the maximum number of online CPU
+ * according to PASS level.
+ */
+ limit_max_freq = table[new_level].limit_max_freq;
+ limit_max_cpu = table[new_level].limit_max_cpu;
+
+ policy->prev_level = policy->curr_level;
+ policy->curr_level = new_level;
+
+ /* Turn on/off CPUs according the maximum number of online CPU */
+ if (hotplug) {
+ if (hotplug->max_online != limit_max_cpu)
+ hotplug->max_online = limit_max_cpu;
+
+ if (hotplug->governor)
+ online = hotplug->governor(policy);
+ else
+ online = 1;
+
+ pass_hotplug_set_online(policy, online);
+ }
+
+ /* Set maximum CPU frequency */
+ ret = pass_set_max_freq(pass_res, limit_max_freq);
+ if (ret < 0) {
+ _E("cannot set the maximum frequency of %s", cdata->res_name);
+ return -EINVAL;
+ }
+
+ /*
+ _I("[PASS %s] Level %4s '%d->%d' : '%d'Hz/'%d'Core\n",
+ pass_res->cdata.res_name,
+ (curr_level > new_level ? "DOWN" : "UP"),
+ curr_level, new_level, limit_max_freq, limit_max_cpu);
+ */
+
+ return 0;
+};
+
+/*
+ * pass_calculate_busy_cpu - Count a number of busy cpu among NR_CPUS by using
+ * runnable_avg_sum/runnable_avg_period
+ *
+ * @policy: the instance of struct pass_policy
+ */
+static void pass_calculate_busy_cpu(struct pass_policy *policy)
+{
+ struct pass_cpu_stats *stats = policy->pass_cpu_stats;
+ struct pass_table *table = policy->pass_table;
+ unsigned int level = policy->curr_level;
+ unsigned int cpu_threshold = 0;
+ unsigned int busy_cpu;
+ unsigned int cur_freq;
+ unsigned int load;
+ unsigned int sum_load;
+ unsigned int sum_runnable_load;
+ unsigned int nr_runnings;
+ int limit_max_cpu;
+ int i;
+ int j;
+
+ limit_max_cpu = table[level].limit_max_cpu;
+
+ for (i = 0; i < policy->num_pass_cpu_stats; i++) {
+ cur_freq = stats[i].freq;
+ nr_runnings = stats[i].nr_runnings;
+
+ stats[i].num_busy_cpu = 0;
+ stats[i].avg_load = 0;
+ stats[i].avg_runnable_load = 0;
+ stats[i].avg_thread_load = 0;
+ stats[i].avg_thread_runnable_load = 0;
+
+ busy_cpu = 0;
+ sum_load = 0;
+ sum_runnable_load = 0;
+
+ /* Calculate the number of busy cpu */
+ for (j = 0; j < policy->cpufreq.num_nr_cpus; j++) {
+ load = stats[i].load[j];
+ sum_load += stats[i].load[j];
+ sum_runnable_load += stats[i].runnable_load[j];
+ if (!load)
+ continue;
+
+ cpu_threshold =
+ (unsigned int)(cur_freq * load)
+ / policy->cpufreq.max_freq;
+ if (load == 100
+ || cpu_threshold >= policy->pass_cpu_threshold)
+ busy_cpu++;
+ }
+
+ stats[i].num_busy_cpu = busy_cpu;
+ stats[i].avg_load = sum_load / limit_max_cpu;
+ stats[i].avg_runnable_load = sum_runnable_load / limit_max_cpu;
+ if (nr_runnings) {
+ stats[i].avg_thread_load
+ = (sum_load * 100) / nr_runnings;
+ stats[i].avg_thread_runnable_load
+ = (sum_runnable_load * 100) / nr_runnings;
+ }
+ }
+}
+
+/*
+ * pass_governor_core_timer - Callback function of core timer for PASS governor
+ *
+ * @data: the instance of struct pass_policy
+ */
+static Eina_Bool pass_governor_core_timer(void *data)
+{
+ struct pass_policy *policy = (struct pass_policy *)data;
+ static int count = 0;
+ int level;
+ int ret;
+
+ if (!policy) {
+ _E("cannot execute PASS core timer");
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ /*
+ * Collect data related to system state
+ * - current cpu frequency
+ * - the number of nr_running
+ * - cpu load (= runnable_avg_sum * 100 / runnable_avg_period)
+ */
+ ret = pass_get_cpu_stats(policy);
+ if (ret < 0) {
+ if (count++ < PASS_CPU_STATS_MAX_COUNT)
+ return ECORE_CALLBACK_RENEW;
+
+ count = 0;
+
+ _E("cannot read 'pass_cpu_stats' sysfs entry");
+ pass_governor_update(policy, PASS_GOV_STOP);
+
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ /* Calculate the number of busy cpu */
+ pass_calculate_busy_cpu(policy);
+
+ /* Determine the amount of proper resource */
+ if (policy->governor->governor) {
+ level = policy->governor->governor(policy);
+
+ pass_governor_change_level(policy, level);
+ } else {
+ _E("cannot execute governor function");
+ pass_governor_update(policy, PASS_GOV_STOP);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ /*
+ * Change the period of govenor timer according to PASS level
+ */
+ if (policy->pass_table[level].gov_timeout >= PASS_MIN_GOV_TIMEOUT &&
+ (policy->governor->gov_timeout
+ != policy->pass_table[level].gov_timeout)) {
+
+ _I("Change the period of governor timer from %fs to %fs\n",
+ policy->governor->gov_timeout,
+ policy->pass_table[level].gov_timeout);
+
+ policy->governor->gov_timeout =
+ policy->pass_table[level].gov_timeout;
+ ecore_timer_interval_set(policy->governor->gov_timer_id,
+ policy->governor->gov_timeout);
+ ecore_timer_reset(policy->governor->gov_timer_id);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+/*
+ * __pass_governor_start - Start PASS governor through D-Bus
+ *
+ * @policy: the instance of struct pass_policy
+ */
+static void __pass_governor_start(struct pass_policy *policy)
+{
+ struct pass_resource *res = to_pass_resource(policy);
+ struct pass_conf_data *cdata = &res->cdata;
+
+ if (!policy->governor) {
+ _E("cannot start PASS governor");
+ return;
+ }
+
+ if (is_enabled(policy)) {
+ _E("PASS governor is already active state");
+ return;
+ }
+
+ /* Create the core timer of PASS governor */
+ policy->governor->gov_timer_id = ecore_timer_add(
+ policy->governor->gov_timeout,
+ (Ecore_Task_Cb)pass_governor_core_timer,
+ (void *)policy);
+ if (!policy->governor->gov_timer_id) {
+ _E("cannot add core timer for governor");
+ pass_governor_update(policy, PASS_GOV_STOP);
+ return;
+ }
+
+ /*
+ * Set default pass level when starting pass
+ * - default pass level according to policy->init_level
+ */
+ policy->curr_level = -1;
+ if (policy->init_level > policy->max_level)
+ policy->init_level = policy->max_level;
+ pass_governor_change_level(policy, policy->init_level);
+
+ /* Set PASS state as PASS_GOV_START */
+ policy->gov_state = PASS_GOV_START;
+
+ _I("Start governor for '%s' resource", cdata->res_name);
+}
+
+/*
+ * __pass_governor_stop - Stop PASS governor through D-Bus
+ *
+ * @policy: the instance of struct pass_policy
+ */
+static void __pass_governor_stop(struct pass_policy *policy)
+{
+ struct pass_resource *res = to_pass_resource(policy);
+ struct pass_conf_data *cdata = &res->cdata;
+
+ if (!policy->governor) {
+ _E("cannot stop PASS governor");
+ return;
+ }
+
+ if (policy->gov_state == PASS_GOV_STOP) {
+ _E("PASS governor is already inactive state");
+ return;
+ }
+
+ /* Restore maximum cpu freq/the number of online cpu */
+ pass_governor_change_level(policy, policy->num_levels - 1);
+
+ pass_hotplug_stop(policy);
+
+ if (policy->governor->gov_timer_id) {
+ ecore_timer_del(policy->governor->gov_timer_id);
+ policy->governor->gov_timer_id = NULL;
+ }
+
+ /* Set PASS state as PASS_GOV_STOP */
+ policy->gov_state = PASS_GOV_STOP;
+
+ _I("Stop governor for '%s' resource", cdata->res_name);
+}
+
+static int __pass_governor_init(struct pass_policy *policy)
+{
+ struct pass_resource *res = to_pass_resource(policy);
+ struct pass_conf_data *cdata = &res->cdata;
+
+ if(policy->governor->gov_timeout < 0) {
+ _E("invalid timeout value [%d]!",
+ policy->governor->gov_timeout);
+ pass_governor_update(policy, PASS_GOV_STOP);
+ return -EINVAL;
+ }
+
+ /* Set default PASS state */
+ policy->gov_state = PASS_GOV_STOP;
+
+ /* Initialize notifier */
+ pass_notifier_init(policy);
+
+ _I("Initialize governor for '%s' resource", cdata->res_name);
+
+ return 0;
+}
+
+static int __pass_governor_exit(struct pass_policy *policy)
+{
+ struct pass_resource *res = to_pass_resource(policy);
+ struct pass_conf_data *cdata = &res->cdata;
+ int i;
+
+ /* Exit notifier */
+ pass_notifier_exit(policy);
+
+ /*
+ * Stop core timer and
+ * Restore maximum online cpu/cpu frequency
+ */
+ pass_governor_update(policy, PASS_GOV_STOP);
+
+ /* Free allocated memory */
+ for (i = 0; i < policy->num_pass_cpu_stats; i++) {
+ free(policy->pass_cpu_stats[i].load);
+ free(policy->pass_cpu_stats[i].nr_running);
+ free(policy->pass_cpu_stats[i].runnable_load);
+ }
+ free(policy->pass_cpu_stats);
+
+ if (policy->hotplug)
+ free(policy->hotplug->sequence);
+
+ if (num_policy_pmqos > 0) {
+ for (i = 0; i < num_policy_pmqos; i++)
+ policy_pmqos[i] = NULL;
+ num_policy_pmqos = 0;
+ }
+
+ /* Set pass_policy structure as default value */
+ policy->pass_cpu_threshold = 0;
+ policy->up_threshold = 0;
+ policy->down_threshold = 0;
+
+ policy->prev_level = 0;
+ policy->curr_level = 0;
+ policy->min_level = 0;
+ policy->max_level = 0;
+ policy->level_up_threshold = 0;
+
+ policy->pass_table = NULL;
+ policy->num_pass_cpu_stats = 0;
+
+ policy->governor->gov_timeout = 0;
+
+ policy->governor = NULL;
+
+ _I("Exit governor for '%s' resource", cdata->res_name);
+
+ return 0;
+}
+
+static int __pass_governor_update(struct pass_policy *policy,
+ enum pass_gov_state state)
+{
+ if (!policy) {
+ _E("cannot update PASS governor");
+ return -EINVAL;
+ }
+
+ switch (state) {
+ case PASS_GOV_START:
+ __pass_governor_start(policy);
+ break;
+ case PASS_GOV_STOP:
+ __pass_governor_stop(policy);
+ break;
+ default:
+ _E("Unknown governor state");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * pass_governor_change_level_scope - Change the scope of cpufreq scaling
+ *
+ * @policy: the instance of struct pass_policy
+ * @min_level: the minimum level of cpufreq scaling
+ * @max_level: the maximum level of cpufreq scaling
+ */
+int pass_governor_change_level_scope(struct pass_policy *policy,
+ int min_level, int max_level)
+{
+ if (!policy)
+ return -EINVAL;
+
+ if (min_level > max_level) {
+ _E("min_level(%d) have to be smaller than max_level(%d)\n",
+ min_level, max_level);
+ return -EINVAL;
+ }
+
+ if (min_level == policy->min_level
+ && max_level == policy->max_level)
+ return 0;
+
+ /* Change minimum/maximum level of cpufreq scaling */
+ policy->min_level = min_level;
+ policy->max_level = max_level;
+
+ pass_governor_change_level(policy, policy->curr_level);
+
+ return 0;
+}
+
+/*
+ * Define PASS governor
+ *
+ * - Step governor
+ * - Radiation governor
+ */
+static struct pass_governor pass_gov_step = {
+ .name = "pass_step",
+ .init = __pass_governor_init,
+ .exit = __pass_governor_exit,
+ .update = __pass_governor_update,
+
+ .governor = pass_step_governor,
+};
+
+static struct pass_governor pass_gov_radiation = {
+ .name = "pass_radiation",
+ .init = __pass_governor_init,
+ .exit = __pass_governor_exit,
+ .update = __pass_governor_update,
+
+ .governor = pass_radiation_governor,
+};
+
+/*
+ * pass_get_governor - Return specific governor instance according to type
+ *
+ * @type: the type of PASS governor
+ */
+struct pass_governor* pass_get_governor(struct pass_policy *policy,
+ enum pass_gov_type type)
+{
+ switch (type) {
+ case PASS_GOV_STEP:
+ return &pass_gov_step;
+ case PASS_GOV_RADIATION:
+ return &pass_gov_radiation;
+ default:
+ _E("Unknown governor type");
+ break;
+ };
+
+ return NULL;
+}
+
+/*
+ * __pass_governor_init - Initialize PASS governor
+ *
+ * @policy: the instance of struct pass_policy
+ */
+int pass_governor_init(struct pass_policy *policy)
+{
+ if (!policy || !policy->governor || !policy->governor->init)
+ return -EINVAL;
+
+ return policy->governor->init(policy);
+}
+
+/*
+ * __pass_governor_exit - Exit PASS governor
+ */
+int pass_governor_exit(struct pass_policy *policy)
+{
+ if (!policy || !policy->governor || !policy->governor->exit)
+ return -EINVAL;
+
+ return policy->governor->exit(policy);
+}
+
+/*
+ * __pass_governor_update - Restart/Pause PASS governor
+ *
+ * @policy: the instance of struct pass_policy
+ * @state: the state of governor
+ * PASS_GOV_START : start governor
+ * PASS_GOV_STOP: stop governor
+ */
+int pass_governor_update(struct pass_policy *policy,
+ enum pass_gov_state state)
+{
+ if (!policy || !policy->governor || !policy->governor->update)
+ return -EINVAL;
+
+ return policy->governor->update(policy, state);
+}
/*
- * PASS (Power Aware System Service)
+ * PASS (Power Aware System Service) Governor
*
* Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
*
#ifndef __PASS_GOV__
#define __PASS_GOV__
-/* PASS Step governor function */
-int pass_step_governor(struct pass_policy *policy);
+/* Init, exit and update the governor */
+int pass_governor_init(struct pass_policy *policy);
+int pass_governor_exit(struct pass_policy *policy);
+int pass_governor_update(struct pass_policy *policy, enum pass_gov_state state);
+int pass_governor_change_level_scope(struct pass_policy *policy,
+ int min_level, int max_level);
+
+/* Get the governor/hotplug instance according to enum pass_gov_type */
+struct pass_governor* pass_get_governor(struct pass_policy *policy,
+ enum pass_gov_type type);
+struct pass_hotplug* pass_get_hotplug(struct pass_policy *policy,
+ enum pass_gov_type type);
-/* PASS Radiation governor function */
+/* Function for radiation and step governor */
+int pass_step_governor(struct pass_policy *policy);
int pass_radiation_governor(struct pass_policy *policy);
#endif /* __PASS_GOV__ */
#include <sys/time.h>
#include "pass.h"
-#include "pass-core.h"
+#include "pass-gov.h"
#include "pass-hal.h"
#include "core/device-notifier.h"
#include <stdlib.h>
#include "pass.h"
-#include "pass-core.h"
#include "pass-parser.h"
#include "pass-hal.h"
+#include "pass-gov.h"
#include "core/devices.h"
#include "core/common.h"
******************************************************/
static DBusMessage* e_dbus_start_cb(E_DBus_Object *obj, DBusMessage* msg)
{
- DBusMessage *ret = NULL;
- int i;
+ DBusMessage *ret_dbus = NULL;
+ int i, ret;
for (i = 0; i < g_pass.num_resources; i++) {
struct pass_resource *pass_res = &g_pass.res[i];
struct pass_policy *policy = &pass_res->policy;
- if (policy->governor)
- policy->governor->update(policy, PASS_GOV_START);
- ret = dbus_message_new_method_return(msg);
- if (!ret)
- return ret;
+ ret = pass_governor_update(policy, PASS_GOV_START);
+ if (ret < 0) {
+ _E("cannot start the governor with dbus");
+ return ret_dbus;
+ }
+ ret_dbus = dbus_message_new_method_return(msg);
+ if (!ret_dbus)
+ return ret_dbus;
}
- return ret;
+ return ret_dbus;
}
static DBusMessage* e_dbus_stop_cb(E_DBus_Object *obj, DBusMessage* msg)
{
- DBusMessage *ret = NULL;
- int i;
+ DBusMessage *ret_dbus = NULL;
+ int i, ret;
for (i = 0; i < g_pass.num_resources; i++) {
struct pass_resource *pass_res = &g_pass.res[i];
struct pass_policy *policy = &pass_res->policy;
- if (policy->governor)
- policy->governor->update(policy, PASS_GOV_STOP);
- ret = dbus_message_new_method_return(msg);
- if (!ret)
- return ret;
+ ret = pass_governor_update(policy, PASS_GOV_STOP);
+ if (ret < 0) {
+ _E("cannot stop the governor");
+ return ret_dbus;
+ }
+
+ ret_dbus = dbus_message_new_method_return(msg);
+ if (!ret_dbus)
+ return ret_dbus;
}
- return ret;
+ return ret_dbus;
}
static const struct edbus_method edbus_methods[] = {
policy->hotplug->sequence[i] = i + pass_res->cdata.cpu;
}
- if (policy->governor->init) {
- ret = policy->governor->init(policy);
- if (ret < 0) {
- _E("cannot initialize PASS governor");
- return -1;
- }
- } else {
- _E("cannot execute init() of PASS governor");
+ ret = pass_governor_init(policy);
+ if (ret < 0) {
+ _E("cannot initialize PASS governor");
return -1;
}
{
int ret;
- if (!policy->governor) {
- _E("cannot exit PASS");
- return -1;
- }
-
pass_put_table(policy);
- if (policy->governor->exit) {
- ret = policy->governor->exit(policy);
- if (ret < 0) {
- _E("cannot exit PASS governor");
- return -1;
- }
- } else {
- _E("cannot execute exit() of PASS governor");
+ ret = pass_governor_exit(policy);
+ if (ret < 0) {
+ _E("cannot exit PASS governor");
return -1;
}