pass: Add the multi-cluster support for big.LITTLE core
authorChanwoo Choi <cw00.choi@samsung.com>
Tue, 30 Jun 2015 09:59:23 +0000 (18:59 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Mon, 16 Jan 2017 11:35:37 +0000 (20:35 +0900)
This patch add the multi-cluser support for big.LITTLE core because previous
PASS (Power Aware System Service) only have supported the only one cluster.

Change-Id: Ib84ddce38ea4b54f25745e9b889f332217bd2ec4
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
src/pass/pass-core.c
src/pass/pass-plugin.c
src/pass/pass-plugin.h
src/pass/pass-target.h [deleted file]
src/pass/pass.c
src/pass/pass.h

index 50fd9bb7758867614b1ff8b506c448c1ec7c75e5..2a7d814f2a6719c2be36be6d106c530426cabf16 100644 (file)
@@ -64,7 +64,8 @@ static int pass_governor_change_level_scope(struct pass_policy *policy,
  * 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;
+static struct pass_policy *policy_pmqos[PASS_CLUSTER_MAX];
+static int num_policy_pmqos = 0;
 
 /*
  * is_pmqos_enabled - Check state of whether to support PM_QOS for scenario
@@ -141,9 +142,9 @@ static int find_scenario_index(struct pass_scenario_policy *scenario,
  * pass_notifier_pmqos - Callback function of DEVICE_NOTIFIER_PMQOS notifier
  * @data: the scenario name
  */
-static int pass_notifier_pmqos(void *data)
+
+static int pass_notifier_pmqos_func(struct pass_policy *policy, 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;
@@ -236,6 +237,23 @@ static int pass_notifier_pmqos(void *data)
        return 0;
 }
 
+static int pass_notifier_pmqos(void *data)
+{
+       int i;
+
+       if (num_policy_pmqos == 0)
+               return 0;
+
+       for (i = 0; i < num_policy_pmqos; i++) {
+               if (policy_pmqos[i]->state == PASS_ON
+                       && policy_pmqos[i]->governor != NULL) {
+                       pass_notifier_pmqos_func(policy_pmqos[i], data);
+               }
+       }
+
+       return 0;
+}
+
 /*
  * pass_notifier_booting_done - Callback function of DEVICE_NOTIFIER_BOOTING_
  *                              DONE notifier
@@ -243,12 +261,19 @@ static int pass_notifier_pmqos(void *data)
  */
 static int pass_notifier_booting_done(void *data)
 {
-       if (!policy_pmqos)
+       int i;
+
+       if (num_policy_pmqos == 0)
                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);
+       for (i = 0; i < num_policy_pmqos; i++) {
+               if (policy_pmqos[i]->state == PASS_ON
+                       && policy_pmqos[i]->governor != NULL) {
+                       policy_pmqos[i]->governor->update(policy_pmqos[i],
+                                                       PASS_GOV_START);
+               }
+       }
 
        return 0;
 }
@@ -272,7 +297,7 @@ static int pass_notifier_init(struct pass_policy *policy)
         * instance. This code must be modified after changing deviced's
         * notifier feature.
         */
-       policy_pmqos = policy;
+       policy_pmqos[num_policy_pmqos++] = policy;
 
        return 0;
 }
@@ -362,16 +387,6 @@ static int pass_hotplug_dummy_governor(struct pass_policy *policy)
        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
  *
@@ -380,10 +395,18 @@ static struct pass_hotplug pass_hotplug_dummy = {
 struct pass_hotplug* pass_get_hotplug(struct pass_policy *policy,
                                        enum pass_gov_type type)
 {
+       struct pass_hotplug *hotplug;
+
        switch (type) {
        case PASS_GOV_STEP:
        case PASS_GOV_RADIATION:
-               return &pass_hotplug_dummy;
+               hotplug = malloc(sizeof(struct pass_hotplug));
+               if (!hotplug) {
+                       _E("cannot allocate the memory of struct pass_hotplug");
+                       return NULL;
+               }
+               hotplug->governor = pass_hotplug_dummy_governor;
+               return hotplug;
        default:
                _E("Unknown hotplug type");
                break;
@@ -443,21 +466,23 @@ static int pass_governor_change_level(struct pass_policy *policy, int new_level)
                else
                        online = 1;
 
-               curr_max_freq = get_cpufreq_scaling_max_freq();
-               curr_min_freq = get_cpufreq_scaling_min_freq();
+               curr_max_freq = get_cpufreq_scaling_max_freq(policy->cluster.cpu);
+               curr_min_freq = get_cpufreq_scaling_min_freq(policy->cluster.cpu);
 
-               set_cpufreq_scaling_min_freq(curr_max_freq);
+               set_cpufreq_scaling_min_freq(policy->cluster.cpu, curr_max_freq);
 
                pass_hotplug_set_online(policy, online);
 
-               set_cpufreq_scaling_min_freq(curr_min_freq);
+               set_cpufreq_scaling_min_freq(policy->cluster.cpu, curr_min_freq);
+
        }
 
        /* Set maximum CPU frequency */
-       set_cpufreq_scaling_max_freq(limit_max_freq);
+       set_cpufreq_scaling_max_freq(policy->cluster.cpu, limit_max_freq);
 
        /*
-       _I("Level %4s '%d->%d' : '%d'Hz/'%d'Core\n",
+       _I("[PASS %d] Level %4s '%d->%d' : '%d'Hz/'%d'Core\n",
+               policy->cluster.id,
                (curr_level > new_level ? "DOWN" : "UP"),
                curr_level, new_level, limit_max_freq, limit_max_cpu);
        */
@@ -728,14 +753,14 @@ static int pass_governor_init(struct pass_policy *policy)
                return -EINVAL;
        }
 
+       _I("Initialize PASS (Power Aware System Service)");
+
        /* 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;
 }
 
@@ -766,6 +791,12 @@ static int pass_governor_exit(struct pass_policy *policy)
        if (policy->hotplug)
                free(policy->hotplug->sequence);
 
+       if (num_policy_pmqos > 0) {
+               for (i = 0; i < num_policy_pmqos; i++)
+                       policy_pmqos[i] = NULL;
+               num_policy_pmqos = 0;
+       }
+
        /* Set pass_policy structure as default value */
        policy->pass_cpu_threshold = 0;
        policy->up_threshold = 0;
index fd2068362bf4a4de3e6deb950712a17de192e0aa..8b5ddaf90ae959b06bce955b2bb7a2864a2db1d4 100644 (file)
 #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"
+#define CPU_KERNEL_MAX                 "/sys/devices/system/cpu/kernel_max"
+#define PROC_DT_COMPATIBLE             "/proc/device-tree/compatible"
 
 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) {
+       if (!policy || !policy->cluster.path_load_table || !stats) {
                _E("invalid parameter of structure pass_cpu_stats");
                return -EINVAL;
        }
 
-       fp_stats = fopen(path, "r");
+       fp_stats = fopen(policy->cluster.path_load_table, "r");
        if (fp_stats == NULL)
                return -EIO;
 
@@ -146,35 +138,79 @@ static int sys_set_int(char *fname, int val)
 /*
  * 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_cpufreq_scaling_max_freq(int cpu)
+{
+       char path[BUFF_MAX];
+       int online;
+       int ret;
+
+       ret = sprintf(path,
+               "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = sys_get_int(path, &online);
+       if (ret < 0)
+               return -EAGAIN;
+
+       return online;
+}
+
+int set_cpufreq_scaling_max_freq(int cpu, int freq)
+{
+       char path[BUFF_MAX];
+       int ret;
+
+       ret = sprintf(path,
+               "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
+       if (ret < 0) {
+               return -EINVAL;
+       }
+
+       ret = sys_set_int(path, freq);
+       if (ret < 0) {
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+int get_cpufreq_scaling_min_freq(int cpu)
+{
+       char path[BUFF_MAX];
+       int online;
+       int ret;
+
+       ret = sprintf(path,
+               "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = sys_get_int(path, &online);
+       if (ret < 0)
+               return -EAGAIN;
+
+       return online;
+}
+
+int set_cpufreq_scaling_min_freq(int cpu, int freq)
+{
+       char path[BUFF_MAX];
+       int ret;
+
+       ret = sprintf(path,
+               "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
+       if (ret < 0) {
+               return -EINVAL;
+       }
+
+       ret = sys_set_int(path, freq);
+       if (ret < 0) {
+               return -EAGAIN;
+       }
+
+       return 0;
+}
 
 int get_cpu_online(int cpu)
 {
@@ -208,6 +244,22 @@ int set_cpu_online(int cpu, int online)
        return 0;
 }
 
+int get_num_cpus(void)
+{
+       int num_cpus;
+       int ret;
+
+       ret = sys_get_int(CPU_KERNEL_MAX, &num_cpus);
+       if (ret < 0)
+               return -EAGAIN;
+
+       /*
+        * Return the number of cpus with plus 1 because of index of first CPU
+        * is 0 (zero). (e.g., Octa cores have the '7' value of CPU_KERNEL_MAX)
+        */
+       return (num_cpus + 1);
+}
+
 /***************************************************************************
  *                            Parse pass.conf                              *
  ***************************************************************************/
@@ -368,15 +420,17 @@ static int pass_parse_core(struct parse_result *result, void *user_data)
 
        if (MATCH(result->name, "pass_compatible")) {
                char compatible[BUFF_MAX];
+               int len;
 
                ret = sys_read_buf(PROC_DT_COMPATIBLE, compatible);
                if (ret < 0)
                        return -EEXIST;
 
-               if (strcmp(compatible, result->value))
+               len = strlen(result->value);
+               if (strncmp(compatible, result->value, len)) {
+                       _I("Mismatch compatible string : %s\n", 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"))
@@ -523,6 +577,96 @@ void put_pass_table(struct pass_policy *policy)
                free(policy->scenario.list);
 }
 
+static int  pass_parse_cpu_cluster_data(struct parse_result *result,
+                                   void *user_data, int id)
+{
+       struct pass_cluster *cluster = user_data;
+       char section_name[BUFF_MAX];
+       int i, ret;
+
+       if (!result)
+               return 0;
+
+       if (MATCH(result->name, "pass_cpu_cluster_id")) {
+               cluster->cpu[id].id = atoi(result->value);
+       } else if (MATCH(result->name, "pass_cpu_cluster_first_cpu")) {
+               cluster->cpu[id].cpu = atoi(result->value);
+       } else if (MATCH(result->name, "pass_cpu_cluster_path_conf_file")) {
+               int len = strlen(result->value);
+               strncpy(cluster->cpu[id].path_conf_file, result->value, len);
+       } else if (MATCH(result->name, "pass_cpu_cluster_path_load_table")) {
+               int len = strlen(result->value);
+               strncpy(cluster->cpu[id].path_load_table, result->value, len);
+       }
+
+       return 0;
+}
+
+static int pass_cluster_config(struct parse_result *result, void *user_data)
+{
+       struct pass_cluster *cluster = user_data;
+       char section_name[BUFF_MAX];
+       int id, ret;
+
+       if (!result)
+               return 0;
+
+       if (!result->section || !result->name || !result->value)
+               return 0;
+
+       /* Parsing 'PassCluster' section */
+       if (MATCH(result->section, "PassCluster")) {
+               if (MATCH(result->name, "pass_compatible")) {
+                       char compatible[BUFF_MAX];
+                       int len;
+
+                       ret = sys_get_str(PROC_DT_COMPATIBLE, compatible);
+                       if (ret < 0)
+                               return -EEXIST;
+
+                       len = strlen(result->value);
+                       if (strncmp(compatible, result->value, len)) {
+                               _I("Mismatch compatible string : %s\n",
+                                                       result->value);
+                               return -EINVAL;
+                       }
+               } else if (MATCH(result->name, "pass_num_cpu_clusters")) {
+                       cluster->num_cpu_clusters = atoi(result->value);
+               } else {
+                       _E("cannot parse the number of cluster\n");
+                       return -ENOENT;
+               }
+       }
+
+       /* Parsing 'ClusterX' section */
+       for (id = 0; id < cluster->num_cpu_clusters; id++) {
+               ret = sprintf(section_name, "CpuCluster%d", id);
+
+               if (MATCH(result->section, section_name)) {
+                       ret = pass_parse_cpu_cluster_data(result, user_data, id);
+                       if (ret < 0) {
+                               _E("cannot parse 'CpuCluster' section\n");
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int get_pass_cluster(struct pass_cluster *cluster, char *pass_conf_path)
+{
+       int ret;
+
+       ret = config_parse(pass_conf_path, pass_cluster_config, cluster);
+       if (ret < 0) {
+               _E("cannot parse %s\n", pass_conf_path);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /*
  * get_time_ms - Return current time (unit: millisecond)
  */
index 0b8a762374f33e0aca8bc5c0a1aef88c5aaf98ed..0e35608c07ca2eabe31a9c5faada248be6f71d53 100644 (file)
@@ -27,21 +27,17 @@ 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_max_freq(int cpu);
+int set_cpufreq_scaling_max_freq(int cpu, int freq);
 
-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_cpufreq_scaling_min_freq(int cpu);
+int set_cpufreq_scaling_min_freq(int cpu, int freq);
 
 int get_cpu_online(int);
 int set_cpu_online(int, int);
 
+int get_num_cpus(void);
+
 int64_t get_time_ms(void);
 
 #endif /* __PASS_PLUGIN__ */
diff --git a/src/pass/pass-target.h b/src/pass/pass-target.h
deleted file mode 100644 (file)
index 4451eaf..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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__ */
index 087993f64acd21d1c19c21077367479ce18ee59d..d725728d7da982b4dd232838e389c8eddb48eaca 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "pass.h"
 #include "pass-core.h"
-#include "pass-target.h"
+#include "pass-plugin.h"
 
 #include "core/devices.h"
 #include "core/common.h"
 /*
  * Per-target pass policy
  */
-static struct pass_policy policy;
+static struct pass_policy *policy_list;
+static struct pass_cluster cluster;
 
 /******************************************************
  *                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);
+       DBusMessage *ret = NULL;
+       int i;
+
+       for (i = 0; i < cluster.num_cpu_clusters; i++) {
+               if (policy_list[i].governor)
+                       policy_list[i].governor->update(&policy_list[i],
+                                                       PASS_GOV_START);
+               ret = dbus_message_new_method_return(msg);
+               if (!ret)
+                       return ret;
+       }
+
+       return ret;
 }
 
 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);
+       DBusMessage *ret = NULL;
+       int i;
+
+       for (i = 0; i < cluster.num_cpu_clusters; i++) {
+               if (policy_list[i].governor)
+                       policy_list[i].governor->update(&policy_list[i], PASS_GOV_STOP);
+               ret = dbus_message_new_method_return(msg);
+               if (!ret)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static const struct edbus_method edbus_methods[] = {
@@ -66,158 +86,221 @@ static const struct edbus_method edbus_methods[] = {
  *                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)
+static int pass_cluster_init(struct pass_policy *policy)
 {
-       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;
+       if (!policy) {
+               _E("cannot initialize PASS\n");
+               return -1;
        }
 
        /*
-        * Initialzie D-Bus interface of PASS. User can be able to
-        * turn on/off PASS through D-Bus interface.
+        * Initialize pass-table by parsing pass.conf
         */
-       ret = register_edbus_interface_and_method(DEVICED_PATH_PASS,
-                                       DEVICED_INTERFACE_PASS,
-                                       edbus_methods,
-                                       ARRAY_SIZE(edbus_methods));
+       ret = get_pass_table(policy, policy->cluster.path_conf_file);
        if (ret < 0) {
-               _I("cannot initialize PASS D-Bus (%d)", ret);
-               return;
+               _E("cannot parse %s\n", policy->cluster.path_conf_file);
+               return -1;
        }
 
        /* Check whether PASS is initialzied state or not */
-       if (policy.governor) {
+       if (policy->governor) {
                _I("PASS is already active state");
-               return;
+               return -1;
        }
 
        /*
         * 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->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->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->init_level)
+               policy->init_level = PASS_DEFAULT_MIN_LEVEL;
 
-       if (!policy.pass_cpu_threshold)
-               policy.pass_cpu_threshold = PASS_DEFAULT_CPU_THRESHOLD;
+       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->up_threshold)
+               policy->up_threshold = PASS_DEFAULT_LEVEL_UP_THRESHOLD;
 
-       if (!policy.down_threshold)
-               policy.down_threshold = PASS_DEFAULT_LEVEL_DOWN_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->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;
+       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;
+       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;
+       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);
+       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) {
+       policy->governor = pass_get_governor(policy, policy->gov_type);
+       if (!policy->governor) {
                _E("cannot get the instance of PASS governor");
-               return;
+               return -1;
        }
-       policy.governor->gov_timeout    = policy.gov_timeout;
+       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) {
+       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;
+               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 + policy->cluster.cpu;
        }
 
-       if (policy.governor->init) {
-               ret = policy.governor->init(&policy);
+       if (policy->governor->init) {
+               ret = policy->governor->init(policy);
                if (ret < 0) {
                        _E("cannot initialize PASS governor");
-                       return;
+                       return -1;
                }
        } else {
                _E("cannot execute init() of PASS governor");
-               return;
+               return -1;
        }
+
+       return 0;
 }
 
-/*
- * pass_exit - Exit PASS
- *
- * @data: the instance of structre pass_policy
- */
-static void pass_exit(void *data)
+static int pass_cluster_exit(struct pass_policy *policy)
 {
        int ret;
 
-       if (!policy.governor) {
+       if (!policy->governor) {
                _E("cannot exit PASS");
-               return;
+               return -1;
        }
 
-       put_pass_table(&policy);
+       put_pass_table(policy);
 
-       if (policy.governor->exit) {
-               ret = policy.governor->exit(&policy);
+       if (policy->governor->exit) {
+               ret = policy->governor->exit(policy);
                if (ret < 0) {
                        _E("cannot exit PASS governor");
-                       return;
+                       return -1;
                }
        } else {
                _E("cannot execute exit() of PASS governor");
+               return -1;
+       }
+
+       policy->governor = NULL;
+
+       return 0;
+}
+
+/*
+ * pass_init - Initialize PASS(Power Aware System Service)
+ *
+ * @data: the instance of structre pass_policy
+ */
+
+static void pass_init(void *data2)
+{
+       int i, ret;
+
+       /*
+        * Initialize pass cluster data by parsing pass.conf
+        */
+       ret = get_pass_cluster(&cluster, "/etc/deviced/pass.conf");
+       if (ret < 0) {
+               _E("cannot parse /etc/deviced/pass.conf\n");
+               return -1;
+       }
+
+       policy_list = malloc(sizeof(struct pass_policy)
+                                       * cluster.num_cpu_clusters);
+       if (!policy_list) {
+               _E("cannot allocate the memory for pass_policy array\n");
+               return;
+       }
+
+       if (!policy_list) {
+               _E("cannot allocate the memory for pass_policy array\n");
+               return;
+       }
+
+       for (i = 0; i < cluster.num_cpu_clusters; i++) {
+               policy_list[i].cluster.id = cluster.cpu[i].id;
+               policy_list[i].cluster.cpu = cluster.cpu[i].cpu;
+               strcpy(policy_list[i].cluster.path_conf_file, cluster.cpu[i].path_conf_file);
+               strcpy(policy_list[i].cluster.path_load_table, cluster.cpu[i].path_load_table);
+
+               _I("i(%d) PASS: %d\n", i, policy_list[i].cluster.id);
+               _I("i(%d) PASS: %d\n", i, policy_list[i].cluster.cpu);
+               _I("i(%d) PASS: %s\n", i, policy_list[i].cluster.path_conf_file);
+               _I("i(%d) PASS: %s\n", i, policy_list[i].cluster.path_load_table);
+       }
+
+       /*
+        * 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;
        }
 
-       policy.governor = NULL;
+       for (i = 0; i < cluster.num_cpu_clusters; i++) {
+               ret = pass_cluster_init(&policy_list[i]);
+               if (ret < 0) {
+                       _E("cannot initialize the pass cluster\n");
+                       return;
+               }
+       }
+}
+
+/*
+ * pass_exit - Exit PASS
+ *
+ * @data: the instance of structre pass_policy
+ */
+static void pass_exit(void *data)
+{
+       int i;
+
+       for (i = 0; i < cluster.num_cpu_clusters; i++) {
+               pass_cluster_exit(&policy_list[i]);
 }
 
 static const struct device_ops pass_device_ops = {
index a8f73a9ce0a029a806efc0ecd00e6422373415c8..072972bba4bf6f81dae246e314a41a138d5abd3c 100644 (file)
 #define PASS_LEVEL_COND_MAX    3
 #define PASS_CPU_STATS_DEFAULT 20
 #define PASS_MIN_GOV_TIMEOUT   0.2
+#define PASS_MAX_CLUSTER       2
 
-#define PASS_CONF_PATH         "/etc/deviced/pass.conf"
+#define PASS_CLUSTER_0                 0
+#define PASS_CLUSTER_1                 1
+#define PASS_CLUSTER_MAX               2
 
 struct pass_policy;
 
@@ -88,6 +91,7 @@ struct pass_governor {
 /*
  * struct pass_cpu_stats
  *
+ * @path: the path of load_table on kernel interface
  * @time: current time
  * @freq: current cpu frequency
  * @freq: new cpu frequency
@@ -101,6 +105,8 @@ struct pass_governor {
  * @avg_thread_runnable_load: the Per-thread runnable load
  */
 struct pass_cpu_stats {
+       const char *path;
+
        int64_t time;
        unsigned int freq;
        unsigned int freq_new;
@@ -117,6 +123,34 @@ struct pass_cpu_stats {
        unsigned int avg_thread_runnable_load;
 };
 
+/******************************************************
+ *                   PASS cluster data                *
+ ******************************************************/
+/*
+ * struct pass_cluster_data - Include the specific data of each cluster
+ *
+ * @id: the unique id of cluster
+ * @cpu: the first cpu in cluster
+ * @path_conf_file: the path for PASS configuration file
+ * @path_load_table: the path for load_table entry from kernel
+ */
+struct pass_cluster_data {
+       unsigned int id;
+       unsigned int cpu;
+       char path_conf_file[128];
+       char path_load_table[128];
+};
+
+/*
+ * struct pass_cluster - Include the information of all clusters
+ *
+ * @num_cluster: the number of supported clusters
+ */
+struct pass_cluster {
+       unsigned int num_cpu_clusters;
+       struct pass_cluster_data cpu[PASS_MAX_CLUSTER];
+};
+
 /******************************************************
  *                   PASS interface             *
  ******************************************************/
@@ -237,5 +271,7 @@ struct pass_policy {
        struct pass_governor *governor;
        double gov_timeout;
        struct pass_hotplug *hotplug;
+
+       struct pass_cluster_data cluster;
 };
 #endif /* __pass__ */