src/proc/proc-handler.c
)
+IF(PASS_MODULE STREQUAL on)
+ ADD_SOURCE(src/pass PASS_SRCS)
+ SET(SRCS ${SRCS} ${PASS_SRCS})
+ENDIF()
+
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/deviced)
# Support two pattern combination vibration
%define standard_mix off
+%define pass_module on
%if "%{?profile}" == "mobile"
%endif
-DENGINEER_MODE=%{engineer_mode} \
-DPROFILE=%{profile} \
-DSTANDARD_MIX=%{standard_mix} \
+ -DPASS_MODULE=%{pass_module} \
#eol
%build
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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-hotplug.h"
+
+#include "core/device-notifier.h"
+#include "core/config-parser.h"
+
+#define PASS_CPU_STATS_MAX_COUNT 20
+
+/*
+ * 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 *
+ * - DEVICE_NOTIFIER_PMQOS *
+ * - DEVICE_NOTIFIER_BOOTING_DONE *
+ ****************************************************************************/
+#define PASS_LOCK "Lock"
+#define PASS_UNLOCK "Unlock"
+
+static int pass_governor_change_level_scope(struct pass_policy *policy,
+ int min_level, int max_level);
+
+/*
+ * FIXME: Current notifier of deviced 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 deviced's notifier feature.
+ */
+static struct pass_policy *policy_pmqos;
+
+/*
+ * is_pmqos_enabled - Check state of whether to support PM_QOS for scenario
+ * @policy: instance of pass_policy structure
+ *
+ * Return true if the state of PM_QOS is supported
+ * Return false if the state of PM_QOS isn't supported
+ */
+static bool is_pmqos_enabled(struct pass_policy *policy)
+{
+ if (!policy)
+ return false;
+
+ if (!policy->scenario.list)
+ return false;
+
+ if (policy->scenario.state != PASS_ON)
+ return false;
+
+ return true;
+}
+
+/*
+ * is_scenario_locked - Check locked state of each scenario
+ * @policy: instance of pass_scenario structure
+ *
+ * Return true if scenario is locked and enabled
+ * Return false if scenario is unlocked or disabled
+ */
+
+static bool is_scenario_locked(struct pass_scenario *scn)
+{
+ if (!scn)
+ return false;
+
+ if (!scn->locked || scn->state != PASS_ON)
+ return false;
+
+ return true;
+}
+
+static enum pass_state is_pmqos_locked(char *data, char *name)
+{
+ char *unlock = NULL;
+
+ if (!data)
+ return PASS_OFF;
+
+ unlock = strstr(data, PASS_UNLOCK);
+ if (!unlock) {
+ /* Lock scenario */
+ strncpy(name, data, strlen(data) - strlen(PASS_LOCK));
+ return PASS_ON;
+ } else {
+ /* Unlock scenario */
+ strncpy(name, data, strlen(data) - strlen(PASS_UNLOCK));
+ return PASS_OFF;
+ }
+}
+
+static int find_scenario_index(struct pass_scenario_policy *scenario,
+ char *name)
+{
+ int index;
+
+ for (index = 0; index < scenario->num_scenarios; index++)
+ if (MATCH(scenario->list[index].name, name))
+ return index;
+
+ return -EINVAL;
+}
+
+/*
+ * pass_notifier_pmqos - Callback function of DEVICE_NOTIFIER_PMQOS notifier
+ * @data: the scenario name
+ */
+static int pass_notifier_pmqos(void *data)
+{
+ struct pass_policy *policy = policy_pmqos;
+ struct pass_scenario_policy *scenario = &policy->scenario;
+ struct pass_scenario *scn = NULL;
+ enum pass_state locked = PASS_UNUSED;
+ char name[PASS_NAME_LEN] = {""};
+ unsigned int cpufreq_min_level = 0;
+ unsigned int cpufreq_max_level = 0;
+ int count = 0;
+ int index = -1;
+ int i;
+
+ if (!is_enabled(policy))
+ return 0;
+
+ if (!is_pmqos_enabled(policy))
+ return 0;
+
+ /*
+ * Parse scenario name(data) whether to include 'Lock' or 'Unlock'
+ * string and divide correct scenario name.
+ */
+ locked = is_pmqos_locked(data, name);
+ index = find_scenario_index(scenario, name);
+ if (index < 0) {
+ _W("Unknown scenario (%s)\n", data);
+ return -EINVAL;
+ }
+ scn = &scenario->list[index];
+
+ /* Check the state of each scenario whether to support or not */
+ if (scn->state != PASS_ON) {
+ _W("cannot support '%s' scenario (support=%d)\n",
+ name, scn->state);
+ return 0;
+ }
+
+ /*
+ * Compare locked state of scenario with
+ * if state is same as existing state
+ */
+ if (scn->locked == locked) {
+ _E("'%s' scenario is already %s\n",
+ name, locked ? "Locked" : "Unlocked");
+ return 0;
+ }
+ scenario->list[index].locked = locked;
+
+ if (locked)
+ scenario->list[index].locked_time = get_time_ms();
+
+ /* Change scaling scope according to scenario's level */
+ for (i = 0; i < scenario->num_scenarios; i++) {
+ struct pass_scenario *scn = &scenario->list[i];
+
+ if (is_scenario_locked(scn)) {
+ if (scn->cpufreq_min_level > cpufreq_min_level)
+ cpufreq_min_level = scn->cpufreq_min_level;
+ if (scn->cpufreq_max_level > cpufreq_max_level)
+ cpufreq_max_level = scn->cpufreq_max_level;
+ count++;
+ }
+
+ /*
+ * TODO: PASS have to control busfreq/gpufreq as same as cpufreq
+ */
+ }
+
+ /*
+ * Restore default min/max level if all scenarios hasn't locked state.
+ */
+ if (!is_scenario_locked(scn) && !count) {
+ cpufreq_min_level = policy->default_min_level;
+ cpufreq_max_level = policy->default_max_level;
+ }
+
+ if (locked) {
+ _I("Lock '%s' scenario\n", name);
+ } else {
+ int64_t locked_time =
+ get_time_ms() - scenario->list[index].locked_time;
+ scenario->list[index].locked_time = 0;
+
+ _I("UnLock '%s' scenario (%lldms)\n", name, locked_time);
+ }
+
+ pass_governor_change_level_scope(policy, cpufreq_min_level,
+ cpufreq_max_level);
+
+ /* TODO: PASS have to control busfreq/gpufreq as same as cpufreq. */
+
+ return 0;
+}
+
+/*
+ * 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)
+{
+ if (!policy_pmqos)
+ return 0;
+
+ /* Start PASS governor if 'pass_support' in pass.conf is true */
+ if (policy_pmqos->state == PASS_ON && policy_pmqos->governor)
+ policy_pmqos->governor->update(policy_pmqos, PASS_GOV_START);
+
+ 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 deviced 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 deviced's
+ * notifier feature.
+ */
+ 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_table *table = policy->pass_table;
+ struct pass_hotplug *hotplug = policy->hotplug;
+ int num_online;
+ int i;
+
+ if (!hotplug || online == hotplug->online)
+ return;
+
+ if (online > hotplug->max_online)
+ online = hotplug->max_online;
+
+ if (online > hotplug->online)
+ num_online = online;
+ else
+ num_online = hotplug->online;
+
+ for (i = 0 ; i < policy->cpufreq.num_nr_cpus; i++) {
+ if (i < online)
+ set_cpu_online(hotplug->sequence[i], PASS_CPU_UP);
+ else
+ set_cpu_online(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;
+}
+
+/*
+ * Define PASS hotplug
+ *
+ * - Dummy hotplug
+ */
+static struct pass_hotplug pass_hotplug_dummy = {
+ .name = "pass_hotplug_dummy",
+ .governor = pass_hotplug_dummy_governor,
+};
+
+/*
+ * 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)
+{
+ switch (type) {
+ case PASS_GOV_STEP:
+ case PASS_GOV_RADIATION:
+ return &pass_hotplug_dummy;
+ 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_table *table = policy->pass_table;
+ struct pass_hotplug *hotplug = policy->hotplug;
+ int curr_level = policy->curr_level;
+ int limit_max_freq;
+ int curr_max_freq;
+ int curr_min_freq;
+ int limit_max_cpu;
+ int online;
+ int i;
+
+ 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;
+
+ curr_max_freq = get_cpufreq_scaling_max_freq();
+ curr_min_freq = get_cpufreq_scaling_min_freq();
+
+ set_cpufreq_scaling_min_freq(curr_max_freq);
+
+ pass_hotplug_set_online(policy, online);
+
+ set_cpufreq_scaling_min_freq(curr_min_freq);
+ }
+
+ /* Set maximum CPU frequency */
+ set_cpufreq_scaling_max_freq(limit_max_freq);
+
+ /*
+ _I("Level %4s '%d->%d' : '%d'Hz/'%d'Core\n",
+ (curr_level > new_level ? "DOWN" : "UP"),
+ curr_level, new_level, limit_max_freq, limit_max_cpu);
+ */
+
+ 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
+ */
+static 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;
+}
+
+/*
+ * 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)
+{
+ 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 PASS governor");
+}
+
+/*
+ * 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 online;
+ 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 = get_pass_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)
+{
+ 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 PASS governor");
+}
+
+/*
+ * pass_governor_init - Initialize PASS governor
+ *
+ * @policy: the instance of struct pass_policy
+ */
+static int pass_governor_init(struct pass_policy *policy)
+{
+ int max_level;
+ int ret;
+
+ 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 PASS (Power Aware System Service)");
+
+ return 0;
+}
+
+/*
+ * pass_governor_exit - Exit PASS governor
+ */
+static int pass_governor_exit(struct pass_policy *policy)
+{
+ 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);
+
+ /* 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 PASS (Power Aware System Service)");
+
+ 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;
+}
+
+/*
+ * 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
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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);
+
+#endif /* __PASS_CORE__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 "pass.h"
+
+/*
+ * pass_radiation_governor - Check cpu state and determine the amount of resource
+ *
+ * @stats: structure for getting cpu frequency state from kerncel
+ *
+ * This function check periodically current following state of system
+ * and then determine whether pass level up or down according to pass
+ * policy with gathered data.
+ * - current cpu frequency
+ * - the number of nr_running
+ * - the number of busy_cpu
+ */
+int pass_radiation_governor(struct pass_policy *policy)
+{
+ struct pass_table *table = policy->pass_table;
+ struct pass_cpu_stats *cpu_stats = policy->pass_cpu_stats;
+ int up_threshold = policy->up_threshold;
+ int down_threshold = policy->down_threshold;
+ int num_pass_gov = 0;
+ int level = policy->curr_level;
+ int up_count = 0;
+ int down_count = 0;
+ int left_count = 0;
+ int right_count = 0;
+ bool up_condition;
+ bool down_condition;
+ bool left_condition;
+ bool right_condition;
+ int freq;
+ int nr_running;
+ int busy_cpu;
+ int i;
+ int j;
+ int64_t time;
+
+ for (i = 0; i < policy->num_pass_cpu_stats; i++) {
+ time = cpu_stats[i].time;
+ freq = cpu_stats[i].freq;
+ nr_running = cpu_stats[i].nr_runnings;
+ busy_cpu = cpu_stats[i].num_busy_cpu;
+ up_condition = true;
+ down_condition = true;
+ left_condition = true;
+ right_condition = true;
+
+ if (policy->last_time >= time)
+ continue;
+ policy->last_time = time;
+ num_pass_gov++;
+
+ /*
+ _I("[Level%d][%d][%lld] %d | %d | %d", level, i, time, freq,
+ nr_running, busy_cpu);
+ */
+
+ /* Check level up condition */
+ for (j = 0; j < table[level].num_up_cond && up_condition; j++) {
+ if (table[level].up_cond[j].freq &&
+ !(freq >= table[level].up_cond[j].freq))
+ up_condition = false;
+ }
+
+ if (table[level].num_up_cond && up_condition) {
+ up_count++;
+
+ /*
+ _I("[Level%d] [up_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, up_count,
+ table[level].up_cond[j].freq ? freq : -1,
+ */
+ }
+
+ /* Check level down condition */
+ for (j = 0; j < table[level].num_down_cond && down_condition; j++) {
+ if (table[level].down_cond[j].freq
+ && !(freq <= table[level].down_cond[j].freq))
+ down_condition = false;
+ }
+
+ if (table[level].num_down_cond && down_condition) {
+ down_count++;
+
+ /*
+ _I("[Level%d] [dw_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, down_count,
+ table[level].down_cond[j].freq ? freq : -1,
+ */
+ }
+
+ /* Check level right condition */
+ for (j = 0; j < table[level].num_right_cond && right_condition; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment right_count.
+ */
+ if (table[level].right_cond[j].nr_running
+ && !(nr_running > table[level].right_cond[j].nr_running))
+ right_condition = false;
+
+ if (table[level].right_cond[j].busy_cpu
+ && !(busy_cpu >= table[level].right_cond[j].busy_cpu))
+ right_condition = false;
+ }
+
+ if (table[level].num_right_cond && right_condition) {
+ right_count++;
+
+ /*
+ _I("[Level%d] [right_count : %2d] \
+ nr_running(%d), busy_cpu(%d)",
+ level, right_count,
+ table[level].right_cond[j].nr_running ? nr_running : -1,
+ table[level].right_cond[j].busy_cpu ? busy_cpu : -1);
+ */
+ }
+
+ /* Check level left condition */
+ for (j = 0; j < table[level].num_left_cond && left_condition; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment left_count.
+ */
+ if (table[level].left_cond[j].nr_running
+ && !(nr_running <= table[level].left_cond[j].nr_running))
+ left_condition = false;
+
+ if (table[level].left_cond[j].busy_cpu
+ && !(busy_cpu < table[level].left_cond[j].busy_cpu))
+ left_condition = false;
+ }
+
+ if (table[level].num_left_cond && left_condition) {
+ left_count++;
+
+ /*
+ _I("[Level%d] [ left_count : %2d] \
+ nr_running(%d), busy_cpu(%d)",
+ level, left_count,
+ table[level].left_cond[j].nr_running ? nr_running : -1,
+ table[level].left_cond[j].busy_cpu ? busy_cpu : -1);
+ */
+ }
+ }
+
+ if (up_count * 100 >= num_pass_gov * up_threshold)
+ level += policy->cpufreq.num_nr_cpus;
+ else if (down_count * 100 >= num_pass_gov * down_threshold)
+ level -= policy->cpufreq.num_nr_cpus;
+
+ if (right_count * 100 >= num_pass_gov * up_threshold)
+ level += 1;
+ else if (left_count * 100 >= num_pass_gov * down_threshold)
+ level -= 1;
+
+ /*
+ if (level == policy->prev_level) {
+ for (i = num_pass_gov; i < policy->num_pass_cpu_stats; i++) {
+ time = cpu_stats[i].time;
+ freq = cpu_stats[i].freq;
+ nr_running = cpu_stats[i].nr_runnings;
+ busy_cpu = cpu_stats[i].num_busy_cpu;
+
+ _I("[Level%d][%d][%lld] %d | %d | %d",
+ level, i, time, freq,
+ nr_running, busy_cpu);
+ }
+ }
+
+ if (level != policy->curr_level) {
+ _I("\n[Level%d] num_pass_gov: [%2d]", level, num_pass_gov);
+ _I("[Level%d] down_count : %2d (%3d >= %3d)", level, down_count,
+ down_count * 100, num_pass_gov * down_threshold);
+ _I("[Level%d] up_count : %2d (%3d >= %3d)", level, up_count,
+ up_count * 100, num_pass_gov * up_threshold);
+ _I("[Level%d] left_count : %2d (%3d >= %3d)", level, left_count,
+ left_count * 100, num_pass_gov * down_threshold);
+ _I("[Level%d] right_count : %2d (%3d >= %3d)", level, right_count,
+ right_count * 100, num_pass_gov * up_threshold);
+ }
+ */
+
+ return level;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 "pass.h"
+
+/*
+ * pass_step_governor - Check cpu state and determine the amount of resource
+ *
+ * @stats: structure for getting cpu frequency state from kerncel
+ *
+ * This function check periodically current following state of system
+ * and then determine whether pass level up or down according to pass
+ * policy with gathered data.
+ * - current cpu frequency
+ * - the number of nr_running
+ * - the number of busy_cpu
+ */
+int pass_step_governor(struct pass_policy *policy)
+{
+ struct pass_table *table = policy->pass_table;
+ struct pass_cpu_stats *cpu_stats = policy->pass_cpu_stats;
+ int up_threshold = policy->up_threshold;
+ int down_threshold = policy->down_threshold;
+ int num_pass_gov = 0;
+ int level = policy->curr_level;
+ int count = 0;
+ int up_count = 0;
+ int up_max_count = 0;
+ int down_count = 0;
+ bool up_condition;
+ bool down_condition;
+ int freq;
+ int nr_running;
+ int busy_cpu;
+ int i;
+ int j;
+ int64_t time;
+
+ for (i = 0; i < policy->num_pass_cpu_stats; i++) {
+ time = cpu_stats[i].time;
+ freq = cpu_stats[i].freq;
+ nr_running = cpu_stats[i].nr_runnings;
+ busy_cpu = cpu_stats[i].num_busy_cpu;
+ up_condition = false;
+ down_condition = false;
+
+ if (policy->last_time >= time)
+ continue;
+ policy->last_time = time;
+ num_pass_gov++;
+
+ /* Check level up condition */
+ for (j = 0; j < table[level].num_up_cond; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment up_count.
+ */
+ if (freq >= table[level].up_cond[j].freq
+ && nr_running >= table[level].up_cond[j].nr_running
+ && busy_cpu >= table[level].up_cond[j].busy_cpu)
+ up_condition = true;
+ }
+
+ if (table[level].num_up_cond && up_condition) {
+ up_count++;
+
+ /*
+ _I("[Level%d] [up_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, up_count,
+ table[level].up_cond[0].freq ? freq : -1,
+ table[level].up_cond[0].nr_running ? nr_running : -1,
+ table[level].up_cond[0].busy_cpu ? busy_cpu : -1);
+ */
+ }
+
+ /* Check level down condition */
+ for (j = 0; j < table[level].num_down_cond; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment down_count.
+ */
+ if (freq <= table[level].down_cond[j].freq
+ && nr_running < table[level].down_cond[j].nr_running
+ && busy_cpu < table[level].down_cond[j].busy_cpu)
+ down_condition = true;
+ }
+
+ if (table[level].num_down_cond && down_condition) {
+ down_count++;
+
+ /*
+ _I("[Level%d] [dw_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, down_count,
+ table[level].down_cond[0].freq ? freq : -1,
+ table[level].down_cond[0].nr_running ? nr_running : -1,
+ table[level].down_cond[0].busy_cpu ? busy_cpu : -1);
+ */
+ }
+
+ if (level < policy->max_level &&
+ freq == table[level].limit_max_freq)
+ up_max_count++;
+ }
+
+ if (!num_pass_gov)
+ return level;
+
+ if (up_count && level < policy->max_level &&
+ up_count * 100 >= num_pass_gov * up_threshold) {
+ level += 1;
+ } else if (down_count && level > policy->min_level &&
+ down_count * 100 >= num_pass_gov * down_threshold) {
+ level -= 1;
+ }
+
+ return level;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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_GOV__
+#define __PASS_GOV__
+
+/* PASS Step governor function */
+int pass_step_governor(struct pass_policy *policy);
+
+/* PASS Radiation governor function */
+int pass_radiation_governor(struct pass_policy *policy);
+
+#endif /* __PASS_GOV__ */
--- /dev/null
+/*
+ * PASS Hotplug
+ *
+ * Copyright (c) 2012 - 2015 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_HOTPLUG__
+#define __PASS_HOTPLUG__
+
+#endif /* __PASS_HOTPLUG__ */
--- /dev/null
+[Pass]
+pass_compatible=samsung,tizen-w
+pass_support=1
+
+pass_gov_type=0
+pass_num_levels=6
+pass_min_level=0
+pass_max_level=5
+pass_init_level=2
+
+pass_num_cpu_stats=20
+
+pass_cpu_threshold=60
+pass_up_threshold=50
+pass_down_threshold=80
+pass_level_up_threshold=1
+
+pass_governor_timeout=0.4
+
+[CpufreqLevel0]
+limit_max_freq=600000
+limit_max_cpu=1
+
+num_down_cond=0
+num_up_cond=1
+num_up_cond_freq=500000
+num_up_cond_nr_running=150
+num_up_cond_busy_cpu=1
+num_left_cond=0
+num_right_cond=0
+
+[CpufreqLevel1]
+limit_max_freq=700000
+limit_max_cpu=1
+
+num_down_cond=1
+num_down_cond_freq=500000
+num_down_cond_nr_running=250
+num_down_cond_busy_cpu=2
+num_up_cond=1
+num_up_cond_freq=700000
+num_up_cond_nr_running=250
+num_up_cond_busy_cpu=1
+num_left_cond=0
+num_right_cond=0
+
+[CpufreqLevel2]
+limit_max_freq=800000
+limit_max_cpu=1
+
+num_down_cond=1
+num_down_cond_freq=700000
+num_down_cond_nr_running=300
+num_down_cond_busy_cpu=2
+num_up_cond=1
+num_up_cond_freq=800000
+num_up_cond_nr_running=200
+num_up_cond_busy_cpu=1
+num_left_cond=0
+num_right_cond=0
+
+[CpufreqLevel3]
+limit_max_freq=700000
+limit_max_cpu=2
+
+num_down_cond=1
+num_down_cond_freq=600000
+num_down_cond_nr_running=250
+num_down_cond_busy_cpu=1
+num_up_cond=1
+num_up_cond_freq=700000
+num_up_cond_nr_running=300
+num_up_cond_busy_cpu=2
+num_left_cond=0
+num_right_cond=0
+
+[CpufreqLevel4]
+limit_max_freq=700000
+limit_max_cpu=2
+
+num_down_cond=1
+num_down_cond_freq=600000
+num_down_cond_nr_running=300
+num_down_cond_busy_cpu=2
+num_up_cond=1
+num_up_cond_freq=700000
+num_up_cond_nr_running=350
+num_up_cond_busy_cpu=2
+num_left_cond=0
+num_right_cond=0
+
+[CpufreqLevel5]
+limit_max_freq=800000
+limit_max_cpu=2
+
+num_down_cond=1
+num_down_cond_freq=700000
+num_down_cond_nr_running=200
+num_down_cond_busy_cpu=1
+num_up_cond=0
+num_left_cond=0
+num_right_cond=0
+
+############################
+### Add list of scenario ###
+############################
+[PassScenario]
+pass_scenario_support=yes
+pass_num_scenarios=28
+
+[Scenario0]
+name=AppLaunch
+support=yes
+
+cpufreq_min_level=5
+cpufreq_max_level=5
+
+[Scenario1]
+name=MtpSendFile
+support=no
+
+[Scenario2]
+name=PowerSaving
+support=no
+
+[Scenario3]
+name=LowBattery
+support=no
+
+[Scenario4]
+name=Emergency
+support=no
+
+[Scenario5]
+name=CameraPreview
+support=yes
+
+cpufreq_min_level=3
+cpufreq_max_level=5
+
+[Scenario6]
+name=CameraBurstShot
+support=yes
+
+cpufreq_min_level=3
+cpufreq_max_level=5
+
+[Scenario7]
+name=CameraCaptureAtRec
+support=yes
+
+cpufreq_min_level=3
+cpufreq_max_level=5
+
+[Scenario8]
+name=Browser
+support=no
+
+[Scenario9]
+name=BrowserDash
+support=no
+
+[Scenario10]
+name=BrowserJavaScript
+support=no
+
+[Scenario11]
+name=BrowserLoading
+support=no
+
+[Scenario12]
+name=BrowserScroll
+support=no
+
+[Scenario13]
+name=GpuWakeup
+support=no
+
+[Scenario14]
+name=WifiThroughput
+support=no
+
+[Scenario15]
+name=SmemoZoom
+support=no
+
+[Scenario16]
+name=IMEInput
+support=no
+
+[Scenario17]
+name=CallSound
+support=no
+
+[Scenario18]
+name=LockScreen
+support=no
+
+[Scenario19]
+name=GalleryRotation
+support=no
+
+[Scenario20]
+name=ReservedMode
+support=no
+
+[Scenario21]
+name=GetDefaultLockTime
+support=no
+
+[Scenario22]
+name=GpuBoost
+support=no
+
+[Scenario23]
+name=WebappLaunch
+support=yes
+
+cpufreq_min_level=3
+cpufreq_max_level=5
+
+[Scenario24]
+name=ImageViewer
+support=no
+
+[Scenario25]
+name=PowerOff
+support=yes
+
+cpufreq_min_level=5
+cpufreq_max_level=5
+
+[Scenario26]
+name=ProcessCrashed
+support=yes
+
+cpufreq_min_level=5
+cpufreq_max_level=5
+
+[Scenario27]
+name=SVoice
+support=yes
+
+cpufreq_min_level=5
+cpufreq_max_level=5
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "pass.h"
+#include "pass-plugin.h"
+
+#include "core/config-parser.h"
+
+#define BUFF_MAX 255
+
+/* Linux standard sysfs node */
+#define CPUFREQ_SCALING_MAX_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+#define CPUFREQ_SCALING_MIN_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+#define CPUFREQ_SAMPLING_RATE "/sys/devices/system/cpu/cpufreq/ondemand/sampling_rate"
+#define CPUFREQ_UP_THRESHOLD "/sys/devices/system/cpu/cpufreq/ondemand/up_threshold"
+
+#define PROC_DT_COMPATIBLE "/proc/device-tree/compatible"
+
+/* PASS specific sysfs node */
+#define PASS_CPU_STATS "/sys/kernel/debug/cpufreq/cpu0/load_table"
+
+int get_pass_cpu_stats(struct pass_policy *policy)
+{
+ struct pass_cpu_stats *stats = policy->pass_cpu_stats;
+ char path[PATH_MAX] = PASS_CPU_STATS;
+ char str[BUFF_MAX];
+ FILE *fp_stats = NULL;
+ int i, j;
+ int ret = 1;
+
+ if (!stats) {
+ _E("invalid parameter of structure pass_cpu_stats");
+ return -EINVAL;
+ }
+
+ fp_stats = fopen(path, "r");
+ if (fp_stats == NULL)
+ return -EIO;
+
+ fgets(str, BUFF_MAX, fp_stats);
+ for (i = 0; i < policy->num_pass_cpu_stats; i++) {
+ ret = fscanf(fp_stats, "%lld %d %d %d",
+ &stats[i].time,
+ &stats[i].freq,
+ &stats[i].freq_new,
+ &stats[i].nr_runnings);
+
+ for (j = 0; j < policy->cpufreq.num_nr_cpus; j++)
+ ret = fscanf(fp_stats, "%d", &stats[i].load[j]);
+ }
+ fclose(fp_stats);
+
+ return 0;
+}
+
+/*
+ * Helper function
+ * - Read from sysfs entry
+ * - Write to sysfs entry
+ */
+static int sys_read_buf(char *file, char *buf)
+{
+ int fd;
+ int r;
+ int ret = 0;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -ENOENT;
+
+ r = read(fd, buf, BUFF_MAX);
+ if ((r >= 0) && (r < BUFF_MAX))
+ buf[r] = '\0';
+ else
+ ret = -EIO;
+
+ close(fd);
+
+ return ret;
+}
+
+static int sys_write_buf(char *file, char *buf)
+{
+ int fd;
+ int r;
+ int ret = 0;
+
+ fd = open(file, O_WRONLY);
+ if (fd == -1)
+ return -1;
+
+ r = write(fd, buf, strlen(buf));
+ if (r < 0)
+ ret = -EIO;
+
+ close(fd);
+
+ return ret;
+}
+
+static int sys_get_int(char *fname, int *val)
+{
+ char buf[BUFF_MAX];
+
+ if (sys_read_buf(fname, buf) == 0) {
+ *val = atoi(buf);
+ return 0;
+ } else {
+ *val = -1;
+ return -1;
+ }
+}
+
+static int sys_set_int(char *fname, int val)
+{
+ char buf[BUFF_MAX];
+ int r = -1;
+ snprintf(buf, sizeof(buf), "%d", val);
+
+ if (sys_write_buf(fname, buf) == 0)
+ r = 0;
+
+ return r;
+}
+
+/*
+ * Get/Set maximum cpu frequency
+ */
+#define GET_VALUE(name, path) \
+int get_##name(void) \
+{ \
+ int value, ret; \
+ \
+ ret = sys_get_int(path, &value); \
+ if (ret < 0) \
+ return -EAGAIN; \
+ \
+ return value; \
+} \
+
+#define SET_VALUE(name, path) \
+int set_##name(int value) \
+{ \
+ return sys_set_int(path, value); \
+} \
+
+GET_VALUE(cpufreq_scaling_max_freq, CPUFREQ_SCALING_MAX_FREQ);
+SET_VALUE(cpufreq_scaling_max_freq, CPUFREQ_SCALING_MAX_FREQ);
+
+GET_VALUE(cpufreq_scaling_min_freq, CPUFREQ_SCALING_MIN_FREQ);
+SET_VALUE(cpufreq_scaling_min_freq, CPUFREQ_SCALING_MIN_FREQ);
+
+GET_VALUE(cpufreq_sampling_rate, CPUFREQ_SAMPLING_RATE);
+SET_VALUE(cpufreq_sampling_rate, CPUFREQ_SAMPLING_RATE);
+
+GET_VALUE(cpufreq_up_threshold, CPUFREQ_UP_THRESHOLD);
+SET_VALUE(cpufreq_up_threshold, CPUFREQ_UP_THRESHOLD);
+
+int get_cpu_online(int cpu)
+{
+ char path[BUFF_MAX];
+ int online;
+ int ret;
+
+ ret = sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpu);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = sys_get_int(path, &online);
+ if (ret < 0)
+ return -EAGAIN;
+
+ return online;
+}
+int set_cpu_online(int cpu, int online)
+{
+ char path[BUFF_MAX];
+ int ret;
+
+ ret = sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpu);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = sys_set_int(path, online);
+ if (ret < 0)
+ return -EAGAIN;
+
+ return 0;
+}
+
+/***************************************************************************
+ * Parse pass.conf *
+ ***************************************************************************/
+
+static enum pass_state is_supported(char *value)
+{
+ enum pass_state state;
+
+ if (!value)
+ return -EINVAL;
+
+ if (MATCH(value, "yes"))
+ state = PASS_ON;
+ else if (MATCH(value, "no"))
+ state = PASS_OFF;
+ else
+ state = PASS_UNUSED;
+
+ return state;
+}
+
+static int pass_parse_scenario(struct parse_result *result, void *user_data,
+ unsigned int index)
+{
+ struct pass_policy *policy = user_data;
+ struct pass_scenario_policy *scenario = &policy->scenario;
+ char section_name[BUFF_MAX];
+ int i;
+
+ if (!policy && !scenario && !result)
+ return 0;
+
+ if (!result->section || !result->name || !result->value)
+ return 0;
+
+ /* Parse 'PassScenario' section */
+ if (MATCH(result->section, "PassScenario")) {
+ if (MATCH(result->name, "pass_scenario_support")) {
+ scenario->state = is_supported(result->value);
+ if (scenario->state < 0)
+ return -EINVAL;
+
+ } else if (MATCH(result->name, "pass_num_scenarios")) {
+ scenario->num_scenarios = atoi(result->value);
+
+ if (scenario->num_scenarios > 0 && !scenario->list) {
+ scenario->list = malloc(sizeof(struct pass_scenario)
+ * scenario->num_scenarios);
+ if (!scenario->list) {
+ _E("cannot allocate memory for Scenario\n");
+ return -EINVAL;
+ }
+ }
+ }
+ }
+
+ if (scenario->state != PASS_ON)
+ return 0;
+
+ if (!scenario->num_scenarios)
+ return 0;
+
+ if (index > scenario->num_scenarios || index == PASS_UNUSED)
+ return 0;
+
+ /* Parse 'Scenario' section */
+ if (MATCH(result->name, "name")) {
+ strcpy(scenario->list[index].name, result->value);
+ } else if (MATCH(result->name, "support")) {
+ scenario->list[index].state = is_supported(result->value);
+ if (scenario->list[index].state < 0)
+ return -EINVAL;
+ } else if (MATCH(result->name, "cpufreq_min_level")) {
+ scenario->list[index].cpufreq_min_level = atoi(result->value);
+ } else if (MATCH(result->name, "cpufreq_max_level")) {
+ scenario->list[index].cpufreq_max_level = atoi(result->value);
+ } else if (MATCH(result->name, "busfreq_min_level")) {
+ scenario->list[index].busfreq_min_level = atoi(result->value);
+ } else if (MATCH(result->name, "busfreq_max_level")) {
+ scenario->list[index].busfreq_max_level = atoi(result->value);
+ } else if (MATCH(result->name, "gpufreq_min_level")) {
+ scenario->list[index].gpufreq_min_level = atoi(result->value);
+ } else if (MATCH(result->name, "gpufreq_max_level")) {
+ scenario->list[index].gpufreq_max_level = atoi(result->value);
+ }
+
+ return 0;
+}
+
+static int pass_parse_cpufreq_level(struct parse_result *result,
+ void *user_data, int level)
+{
+ struct pass_policy *policy = user_data;
+ char section_name[BUFF_MAX];
+ int i, ret;
+
+ if (!result)
+ return 0;
+
+ if (!result->section || !result->name || !result->value)
+ return 0;
+
+ if (MATCH(result->name, "limit_max_freq"))
+ policy->pass_table[level].limit_max_freq = atoi(result->value);
+ else if (MATCH(result->name, "limit_max_cpu"))
+ policy->pass_table[level].limit_max_cpu = atoi(result->value);
+
+ else if (MATCH(result->name, "num_down_cond"))
+ policy->pass_table[level].num_down_cond = atoi(result->value);
+ else if (MATCH(result->name, "num_down_cond_freq"))
+ policy->pass_table[level].down_cond[0].freq = atoi(result->value);
+ else if (MATCH(result->name, "num_down_cond_nr_running"))
+ policy->pass_table[level].down_cond[0].nr_running = atoi(result->value);
+ else if (MATCH(result->name, "num_down_cond_busy_cpu"))
+ policy->pass_table[level].down_cond[0].busy_cpu = atoi(result->value);
+
+ else if (MATCH(result->name, "num_up_cond"))
+ policy->pass_table[level].num_up_cond = atoi(result->value);
+ else if (MATCH(result->name, "num_up_cond_freq"))
+ policy->pass_table[level].up_cond[0].freq = atoi(result->value);
+ else if (MATCH(result->name, "num_up_cond_nr_running"))
+ policy->pass_table[level].up_cond[0].nr_running = atoi(result->value);
+ else if (MATCH(result->name, "num_up_cond_busy_cpu"))
+ policy->pass_table[level].up_cond[0].busy_cpu = atoi(result->value);
+
+ else if (MATCH(result->name, "num_left_cond"))
+ policy->pass_table[level].num_left_cond = atoi(result->value);
+ else if (MATCH(result->name, "num_left_cond_freq"))
+ policy->pass_table[level].left_cond[0].freq = atoi(result->value);
+ else if (MATCH(result->name, "num_left_cond_nr_running"))
+ policy->pass_table[level].left_cond[0].nr_running = atoi(result->value);
+ else if (MATCH(result->name, "num_left_cond_busy_cpu"))
+ policy->pass_table[level].left_cond[0].busy_cpu = atoi(result->value);
+
+ else if (MATCH(result->name, "num_right_cond"))
+ policy->pass_table[level].num_right_cond = atoi(result->value);
+ else if (MATCH(result->name, "num_right_cond_freq"))
+ policy->pass_table[level].right_cond[0].freq = atoi(result->value);
+ else if (MATCH(result->name, "num_right_cond_nr_running"))
+ policy->pass_table[level].right_cond[0].nr_running = atoi(result->value);
+ else if (MATCH(result->name, "num_right_cond_busy_cpu"))
+ policy->pass_table[level].right_cond[0].busy_cpu = atoi(result->value);
+
+ return 0;
+}
+
+static int pass_parse_core(struct parse_result *result, void *user_data)
+{
+ struct pass_policy *policy = user_data;
+ char section_name[BUFF_MAX];
+ int i, ret;
+
+ if (!result)
+ return 0;
+
+ if (!result->section || !result->name || !result->value)
+ return 0;
+
+ if (MATCH(result->name, "pass_compatible")) {
+ char compatible[BUFF_MAX];
+
+ ret = sys_read_buf(PROC_DT_COMPATIBLE, compatible);
+ if (ret < 0)
+ return -EEXIST;
+
+ if (strcmp(compatible, result->value))
+ return -EINVAL;
+
+ _I("Match compatible string : %s\n", compatible);
+ } else if (MATCH(result->name, "pass_support"))
+ policy->state = atoi(result->value);
+ else if (MATCH(result->name, "pass_gov_type"))
+ policy->gov_type = atoi(result->value);
+ else if (MATCH(result->name, "pass_num_levels"))
+ policy->num_levels = atoi(result->value);
+ else if (MATCH(result->name, "pass_min_level"))
+ policy->min_level = atoi(result->value);
+ else if (MATCH(result->name, "pass_max_level"))
+ policy->max_level = atoi(result->value);
+ else if (MATCH(result->name, "pass_num_cpu_stats"))
+ policy->num_pass_cpu_stats = atoi(result->value);
+ else if (MATCH(result->name, "pass_cpu_threshold"))
+ policy->pass_cpu_threshold = atoi(result->value);
+ else if (MATCH(result->name, "pass_up_threshold"))
+ policy->up_threshold = atoi(result->value);
+ else if (MATCH(result->name, "pass_down_threshold"))
+ policy->down_threshold = atoi(result->value);
+ else if (MATCH(result->name, "pass_init_level"))
+ policy->init_level = atoi(result->value);
+ else if (MATCH(result->name, "pass_level_up_threshold"))
+ policy->level_up_threshold = atoi(result->value);
+ else if (MATCH(result->name, "pass_governor_timeout")) {
+ policy->gov_timeout = atof(result->value);
+
+ if (PASS_MIN_GOV_TIMEOUT > policy->gov_timeout)
+ policy->gov_timeout = PASS_MIN_GOV_TIMEOUT;
+ }
+
+ if (policy->num_levels > 0 && !policy->pass_table) {
+ policy->pass_table = malloc(sizeof(struct pass_table)
+ * policy->num_levels);
+ if (!policy->pass_table) {
+ _E("cannot allocate memory for pass_table\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int pass_load_config(struct parse_result *result, void *user_data)
+{
+ struct pass_policy *policy = user_data;
+ struct pass_scenario_policy *scenario = &policy->scenario;
+ char section_name[BUFF_MAX];
+ int level = PASS_UNUSED;
+ int index = PASS_UNUSED;
+ int i, ret;
+
+ if (!result)
+ return 0;
+
+ if (!result->section || !result->name || !result->value)
+ return 0;
+
+ /* Parsing 'PASS' section */
+ if (MATCH(result->section, "Pass")) {
+ ret = pass_parse_core(result, user_data);
+ if (ret < 0) {
+ _E("cannot parse the core part\n");
+ return ret;
+ }
+
+ goto out;
+ }
+
+ /* Parsing 'CpufreqLevel' section to get pass-table */
+ for (level = 0; level < policy->num_levels; level++) {
+ ret = sprintf(section_name, "CpufreqLevel%d", level);
+
+ if (MATCH(result->section, section_name)) {
+ ret = pass_parse_cpufreq_level(result, user_data, level);
+ if (ret < 0) {
+ _E("cannot parse 'Cpufreq' section\n");
+ return ret;
+ }
+
+ goto out;
+ }
+ }
+
+ /* Parsing 'PassScenario' section */
+ if (MATCH(result->section, "PassScenario")) {
+ ret = pass_parse_scenario(result, user_data, PASS_UNUSED);
+ if (ret < 0) {
+ _E("cannot parse 'PassScenario' section\n");
+ return ret;
+ }
+
+ goto out;
+ }
+
+ /* Parsing 'Scenario' section */
+ for (index = 0; index < scenario->num_scenarios; index++) {
+ ret = sprintf(section_name, "Scenario%d", index);
+
+ if (MATCH(result->section, section_name)) {
+ ret = pass_parse_scenario(result, user_data, index);
+ if (ret < 0) {
+ _E("cannot parse 'Scenario' section\n");
+ return ret;
+ }
+
+ goto out;
+ }
+ }
+
+out:
+ return 0;
+}
+
+int get_pass_table(struct pass_policy *policy, char *pass_conf_path)
+{
+ int ret;
+
+ policy->state = PASS_UNUSED;
+ policy->scenario.state = PASS_UNUSED;
+
+ ret = config_parse(pass_conf_path, pass_load_config, policy);
+ if (ret < 0) {
+ _E("cannot parse %s\n", pass_conf_path);
+ return -EINVAL;
+ }
+
+ if (policy->state == PASS_UNUSED)
+ return -EINVAL;
+
+ if (policy->scenario.state == PASS_UNUSED)
+ _W("%s don't include the list of pass-scenario\n");
+ else
+ _I("can%s use pass-scenario",
+ policy->scenario.state ? "" : "not");
+
+ return 0;
+}
+
+void put_pass_table(struct pass_policy *policy)
+{
+ if(policy->pass_table)
+ free(policy->pass_table);
+
+ if(policy->scenario.list)
+ free(policy->scenario.list);
+}
+
+/*
+ * get_time_ms - Return current time (unit: millisecond)
+ */
+int64_t get_time_ms(void)
+{
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ return (int64_t)(now.tv_sec * 1000 + now.tv_usec / 1000);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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_PLUGIN__
+#define __PASS_PLUGIN__
+
+#include "pass.h"
+
+int get_pass_cpu_stats(struct pass_policy *policy);
+
+int get_pass_table(struct pass_policy *policy, char *pass_conf_path);
+void put_pass_table(struct pass_policy *policy);
+
+int get_cpufreq_scaling_max_freq(void);
+int set_cpufreq_scaling_max_freq(int);
+
+int get_cpufreq_scaling_min_freq(void);
+int set_cpufreq_scaling_min_freq(int);
+
+int get_cpufreq_sampling_rate(void);
+int set_cpufreq_sampling_rate(int);
+
+int get_cpufreq_up_threshold(void);
+int set_cpufreq_up_threshold(int);
+
+int get_cpu_online(int);
+int set_cpu_online(int, int);
+
+int64_t get_time_ms(void);
+
+#endif /* __PASS_PLUGIN__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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_TARGET__
+#define __PASS_TARGET__
+
+enum pass_target_type {
+ PASS_TARGET_UNKNOWN = 0,
+ PASS_TARGET_REDWOOD_EXYNOS4412_STEP,
+ PASS_TARGET_REDWOOD_EXYNOS4412_RADIATION,
+ PASS_TARGET_W_EXYNOS4212,
+
+ PASS_TARGET_TYPE_END,
+};
+
+#endif /* __PASS_TARGET__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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_UTIL_H__
+#define __PASS_UTIL_H__
+
+#ifdef ENABLE_DEVICED_DLOG
+#define ENABLE_DLOG
+#endif
+
+#define LOG_TAG "PASS"
+#include "shared/log-macro.h"
+
+#endif /* __PASS_UTIL_H__ */
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2012 - 2015 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 <glib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pass.h"
+#include "pass-core.h"
+#include "pass-target.h"
+
+#include "core/devices.h"
+#include "core/common.h"
+#include "core/edbus-handler.h"
+
+#define PASS_DEFAULT_MIN_LEVEL 0
+#define PASS_DEFAULT_CPU_THRESHOLD 20
+#define PASS_DEFAULT_LEVEL_UP_THRESHOLD 30
+#define PASS_DEFAULT_LEVEL_DOWN_THRESHOLD 80
+
+/*
+ * Per-target pass policy
+ */
+static struct pass_policy policy;
+
+/******************************************************
+ * PASS D-Bus interface *
+ ******************************************************/
+static DBusMessage* e_dbus_start_cb(E_DBus_Object *obj, DBusMessage* msg)
+{
+ if (policy.governor)
+ policy.governor->update(&policy, PASS_GOV_START);
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage* e_dbus_stop_cb(E_DBus_Object *obj, DBusMessage* msg)
+{
+ if (policy.governor)
+ policy.governor->update(&policy, PASS_GOV_STOP);
+ return dbus_message_new_method_return(msg);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "start", NULL, NULL, e_dbus_start_cb },
+ { "stop", NULL, NULL, e_dbus_stop_cb },
+};
+
+/******************************************************
+ * PASS interface (Init/Exit) *
+ ******************************************************/
+
+/*
+ * pass_init - Initialize PASS(Power Aware System Service)
+ *
+ * @data: the instance of structre pass_policy
+ */
+static void pass_init(void *data)
+{
+ enum pass_target_type target_type;
+ int max_freq = 0;
+ int max_cpu = 0;
+ int ret;
+ int i;
+
+ /*
+ * Initialize pass-table by parsing pass.conf
+ */
+ ret = get_pass_table(&policy, PASS_CONF_PATH);
+ if (ret < 0) {
+ _E("cannot parse %s\n", PASS_CONF_PATH);
+ return;
+ }
+
+ /*
+ * Initialzie D-Bus interface of PASS. User can be able to
+ * turn on/off PASS through D-Bus interface.
+ */
+ ret = register_edbus_interface_and_method(DEVICED_PATH_PASS,
+ DEVICED_INTERFACE_PASS,
+ edbus_methods,
+ ARRAY_SIZE(edbus_methods));
+ if (ret < 0) {
+ _I("cannot initialize PASS D-Bus (%d)", ret);
+ return;
+ }
+
+ /* Check whether PASS is initialzied state or not */
+ if (policy.governor) {
+ _I("PASS is already active state");
+ return;
+ }
+
+ /*
+ * Set default value to global pass_policy instance
+ * if variable isn't initialized.
+ */
+ if (!policy.min_level)
+ policy.min_level = PASS_DEFAULT_MIN_LEVEL;
+ policy.default_min_level = policy.min_level;
+
+ if (!policy.max_level)
+ policy.max_level = policy.num_levels - 1;
+ policy.default_max_level = policy.max_level;
+
+ if (!policy.init_level)
+ policy.init_level = PASS_DEFAULT_MIN_LEVEL;
+
+ if (!policy.pass_cpu_threshold)
+ policy.pass_cpu_threshold = PASS_DEFAULT_CPU_THRESHOLD;
+
+ if (!policy.up_threshold)
+ policy.up_threshold = PASS_DEFAULT_LEVEL_UP_THRESHOLD;
+
+ if (!policy.down_threshold)
+ policy.down_threshold = PASS_DEFAULT_LEVEL_DOWN_THRESHOLD;
+
+ if (!policy.level_up_threshold)
+ policy.level_up_threshold = policy.max_level;
+
+ if (!policy.num_pass_cpu_stats)
+ policy.num_pass_cpu_stats = PASS_CPU_STATS_DEFAULT;
+
+ for (i = 0; i < policy.num_levels; i++) {
+ if (max_freq < policy.pass_table[i].limit_max_freq)
+ max_freq = policy.pass_table[i].limit_max_freq;
+ if (max_cpu < policy.pass_table[i].limit_max_cpu)
+ max_cpu = policy.pass_table[i].limit_max_cpu;
+ }
+ policy.cpufreq.max_freq = max_freq;
+ policy.cpufreq.num_nr_cpus = max_cpu;
+
+ /* Allocate memory according to the number of data and cpu */
+ policy.pass_cpu_stats = malloc(sizeof(struct pass_cpu_stats)
+ * policy.num_pass_cpu_stats);
+
+ for (i = 0; i < policy.num_pass_cpu_stats; i++) {
+ policy.pass_cpu_stats[i].load =
+ malloc(sizeof(unsigned int) * policy.cpufreq.num_nr_cpus);
+ policy.pass_cpu_stats[i].nr_running =
+ malloc(sizeof(unsigned int) * policy.cpufreq.num_nr_cpus);
+ policy.pass_cpu_stats[i].runnable_load =
+ malloc(sizeof(unsigned int) * policy.cpufreq.num_nr_cpus);
+ }
+
+ /* Get the instance of PASS governor */
+ policy.governor = pass_get_governor(&policy, policy.gov_type);
+ if (!policy.governor) {
+ _E("cannot get the instance of PASS governor");
+ return;
+ }
+ policy.governor->gov_timeout = policy.gov_timeout;
+
+ /* Get the instance of PASS hotplulg */
+ policy.hotplug = pass_get_hotplug(&policy, policy.gov_type);
+ if (!policy.hotplug) {
+ _E("cannot get the instance of PASS hotplug");
+ } else {
+ policy.hotplug->sequence = malloc(sizeof(int)
+ * policy.cpufreq.num_nr_cpus);
+ for (i = 0; i < policy.cpufreq.num_nr_cpus; i++)
+ policy.hotplug->sequence[i] = i;
+ }
+
+ if (policy.governor->init) {
+ ret = policy.governor->init(&policy);
+ if (ret < 0) {
+ _E("cannot initialize PASS governor");
+ return;
+ }
+ } else {
+ _E("cannot execute init() of PASS governor");
+ return;
+ }
+}
+
+/*
+ * pass_exit - Exit PASS
+ *
+ * @data: the instance of structre pass_policy
+ */
+static void pass_exit(void *data)
+{
+ int ret;
+
+ if (!policy.governor) {
+ _E("cannot exit PASS");
+ return;
+ }
+
+ put_pass_table(&policy);
+
+ if (policy.governor->exit) {
+ ret = policy.governor->exit(&policy);
+ if (ret < 0) {
+ _E("cannot exit PASS governor");
+ return;
+ }
+ } else {
+ _E("cannot execute exit() of PASS governor");
+ return;
+ }
+
+ policy.governor = NULL;
+}
+
+static const struct device_ops pass_device_ops = {
+ .name = "pass",
+ .init = pass_init,
+ .exit = pass_exit,
+};
+
+DEVICE_OPS_REGISTER(&pass_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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__
+#define __PASS__
+
+#include <Ecore.h>
+#include "pass-util.h"
+
+/******************************************************
+ * PASS Governors *
+ ******************************************************/
+#define PASS_NAME_LEN 128
+#define PASS_LEVEL_COND_MAX 3
+#define PASS_CPU_STATS_DEFAULT 20
+#define PASS_MIN_GOV_TIMEOUT 0.2
+
+#define PASS_CONF_PATH "/etc/deviced/pass.conf"
+
+struct pass_policy;
+
+/*
+ * PASS state
+ */
+enum pass_state {
+ PASS_UNUSED = -1,
+ PASS_OFF = 0,
+ PASS_ON = 1,
+};
+
+/*
+ * PASS Governor type
+ */
+enum pass_gov_type {
+ PASS_GOV_STEP,
+ PASS_GOV_RADIATION,
+
+ PASS_GOV_END,
+};
+
+enum pass_gov_state {
+ PASS_GOV_NONE = 0,
+ PASS_GOV_START,
+ PASS_GOV_STOP,
+};
+
+/*
+ * PASS cpu state
+ */
+enum pass_cpu_state {
+ PASS_CPU_DOWN = 0,
+ PASS_CPU_UP,
+};
+
+/*
+ * struct pass_governor
+ */
+struct pass_governor {
+ char name[PASS_NAME_LEN];
+ int (*init)(struct pass_policy *);
+ int (*exit)(struct pass_policy *);
+ int (*update)(struct pass_policy *, enum pass_gov_state state);
+ int (*governor)(struct pass_policy *);
+ Ecore_Timer *gov_timer_id;
+ double gov_timeout;
+};
+
+/******************************************************
+ * PASS basic data *
+ ******************************************************/
+
+/*
+ * struct pass_cpu_stats
+ *
+ * @time: current time
+ * @freq: current cpu frequency
+ * @freq: new cpu frequency
+ * @nr_runnings: the average number of running threads
+ * @nr_running[]: current number of running threads of each core
+ * @runnable_load[]: the runnable load of each core
+ * @busy_cpu: the number of busy cpu
+ * @avg_load: the average load of all CPUs
+ * @avg_runnable_load: the average runnable load of all CPUs
+ * @avg_thread_load: the Per-thread load
+ * @avg_thread_runnable_load: the Per-thread runnable load
+ */
+struct pass_cpu_stats {
+ int64_t time;
+ unsigned int freq;
+ unsigned int freq_new;
+ unsigned int nr_runnings;
+
+ unsigned int *load;
+ unsigned int *nr_running;
+ unsigned int *runnable_load;
+
+ unsigned int num_busy_cpu;
+ unsigned int avg_load;
+ unsigned int avg_runnable_load;
+ unsigned int avg_thread_load;
+ unsigned int avg_thread_runnable_load;
+};
+
+/******************************************************
+ * PASS interface *
+ ******************************************************/
+struct pass_level_condition {
+ int freq;
+ int nr_running;
+ int busy_cpu;
+ int avg_load;
+};
+
+struct pass_table {
+ /* Constraints condition for powersaving */
+ int limit_max_freq;
+ int limit_max_cpu;
+
+ /* Governor timer's timeout for each pass level */
+ double gov_timeout;
+
+ /* Condition to determine up/down of pass level */
+ struct pass_level_condition comm_cond;
+ struct pass_level_condition up_cond[PASS_LEVEL_COND_MAX];
+ struct pass_level_condition down_cond[PASS_LEVEL_COND_MAX];
+ struct pass_level_condition left_cond[PASS_LEVEL_COND_MAX];
+ struct pass_level_condition right_cond[PASS_LEVEL_COND_MAX];
+ int num_up_cond;
+ int num_down_cond;
+ int num_left_cond;
+ int num_right_cond;
+};
+
+/*
+ * struct pass_hotplug - store information of cpu hotplug
+ * @max_online: the possible maximum number of online cpu
+ * @online: the current number of online cpu
+ * @sequence: the sequence to turn on/off cpu
+ */
+struct pass_hotplug {
+ char name[PASS_NAME_LEN];
+ unsigned int max_online;
+ unsigned int online;
+ unsigned int *sequence;
+ int (*governor)(struct pass_policy *);
+};
+
+
+struct pass_cpufreq_policy {
+ unsigned int max_freq;
+ unsigned int num_nr_cpus;
+ unsigned int sampling_rate;
+ unsigned int up_threshold;
+};
+
+struct pass_busfreq_policy {
+ /* TODO */
+};
+
+struct pass_gpufreq_policy {
+ /* TODO */
+};
+
+struct pass_scenario {
+ char name[PASS_NAME_LEN];
+ enum pass_state state;
+ enum pass_state locked;
+ int64_t locked_time;
+
+ unsigned int cpufreq_min_level;
+ unsigned int cpufreq_max_level;
+
+ unsigned int busfreq_min_level;
+ unsigned int busfreq_max_level;
+
+ unsigned int gpufreq_min_level;
+ unsigned int gpufreq_max_level;
+};
+
+struct pass_scenario_policy {
+ enum pass_state state;
+ unsigned int num_scenarios;
+
+ struct pass_scenario *list;
+};
+
+/*
+ * struct pass_policy
+ */
+struct pass_policy {
+ enum pass_state state;
+ enum pass_gov_type gov_type;
+ enum pass_gov_state gov_state;
+ unsigned int pass_cpu_threshold;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+
+ unsigned int init_level;
+ unsigned int prev_level;
+ unsigned int curr_level;
+ unsigned int min_level;
+ unsigned int max_level;
+
+ unsigned int default_min_level;
+ unsigned int default_max_level;
+
+ unsigned int num_levels;
+ unsigned int level_up_threshold;
+
+ int64_t last_time;
+
+ struct pass_cpufreq_policy cpufreq;
+ struct pass_busfreq_policy busfreq;
+ struct pass_gpufreq_policy gpufreq;
+ struct pass_scenario_policy scenario;
+
+ struct pass_table *pass_table;
+ struct pass_cpu_stats *pass_cpu_stats;
+ int num_pass_cpu_stats;
+
+ struct pass_governor *governor;
+ double gov_timeout;
+ struct pass_hotplug *hotplug;
+};
+#endif /* __pass__ */