pass: Add PASS (Power Aware System Service) to support the power management
authorChanwoo Choi <cw00.choi@samsung.com>
Thu, 2 Jun 2016 04:22:40 +0000 (13:22 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Mon, 16 Jan 2017 11:35:37 +0000 (20:35 +0900)
This patch adds the support for PASS (Power Aware System Service) which is used
for power management of Tizen platform. PASS uses the CPU utilization, current CPU
frequency and the number of running tasks to determine the required system
resource currently. PASS has the two governors as following:
- Step governor
- Radiation governor

Change-Id: I3c43978701a0ebe02fab7c5b50847e57cc345090
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
[wook16.song: Make git-am work without any failure]
Signed-off-by: Wook Song <wook16.song@samsung.com>
15 files changed:
CMakeLists.txt
packaging/pass.spec
src/pass/pass-core.c [new file with mode: 0644]
src/pass/pass-core.h [new file with mode: 0644]
src/pass/pass-gov-radiation.c [new file with mode: 0644]
src/pass/pass-gov-step.c [new file with mode: 0644]
src/pass/pass-gov.h [new file with mode: 0644]
src/pass/pass-hotplug.h [new file with mode: 0644]
src/pass/pass-micro.conf [new file with mode: 0644]
src/pass/pass-plugin.c [new file with mode: 0644]
src/pass/pass-plugin.h [new file with mode: 0644]
src/pass/pass-target.h [new file with mode: 0644]
src/pass/pass-util.h [new file with mode: 0644]
src/pass/pass.c [new file with mode: 0644]
src/pass/pass.h [new file with mode: 0644]

index da7746a..a760077 100644 (file)
@@ -80,6 +80,11 @@ SET(SRCS
        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)
index 560c23d..cdf60ee 100644 (file)
@@ -12,6 +12,7 @@
 
 # Support two pattern combination vibration
 %define standard_mix off
+%define pass_module on
 
 %if "%{?profile}" == "mobile"
 %endif
@@ -105,6 +106,7 @@ PASS systemd daemon.
        -DENGINEER_MODE=%{engineer_mode} \
        -DPROFILE=%{profile} \
        -DSTANDARD_MIX=%{standard_mix} \
+       -DPASS_MODULE=%{pass_module} \
        #eol
 
 %build
diff --git a/src/pass/pass-core.c b/src/pass/pass-core.c
new file mode 100644 (file)
index 0000000..50fd9bb
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ * 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;
+}
diff --git a/src/pass/pass-core.h b/src/pass/pass-core.h
new file mode 100644 (file)
index 0000000..4c201fa
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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__ */
diff --git a/src/pass/pass-gov-radiation.c b/src/pass/pass-gov-radiation.c
new file mode 100644 (file)
index 0000000..98b634f
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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;
+}
diff --git a/src/pass/pass-gov-step.c b/src/pass/pass-gov-step.c
new file mode 100644 (file)
index 0000000..61632bd
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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;
+}
diff --git a/src/pass/pass-gov.h b/src/pass/pass-gov.h
new file mode 100644 (file)
index 0000000..6b1aee9
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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__ */
diff --git a/src/pass/pass-hotplug.h b/src/pass/pass-hotplug.h
new file mode 100644 (file)
index 0000000..64f2e51
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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__ */
diff --git a/src/pass/pass-micro.conf b/src/pass/pass-micro.conf
new file mode 100644 (file)
index 0000000..ac68745
--- /dev/null
@@ -0,0 +1,245 @@
+[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
diff --git a/src/pass/pass-plugin.c b/src/pass/pass-plugin.c
new file mode 100644 (file)
index 0000000..fd20683
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * 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);
+}
diff --git a/src/pass/pass-plugin.h b/src/pass/pass-plugin.h
new file mode 100644 (file)
index 0000000..0b8a762
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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__ */
diff --git a/src/pass/pass-target.h b/src/pass/pass-target.h
new file mode 100644 (file)
index 0000000..4451eaf
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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__ */
diff --git a/src/pass/pass-util.h b/src/pass/pass-util.h
new file mode 100644 (file)
index 0000000..918a284
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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__ */
diff --git a/src/pass/pass.c b/src/pass/pass.c
new file mode 100644 (file)
index 0000000..087993f
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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)
diff --git a/src/pass/pass.h b/src/pass/pass.h
new file mode 100644 (file)
index 0000000..a8f73a9
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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__ */