tizen 2.3 release
[framework/system/deviced.git] / src / pass / pass.c
1 /*
2  * PASS (Power Aware System Service)
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <glib.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "pass.h"
26 #include "pass-core.h"
27 #include "pass-target.h"
28
29 #include "core/devices.h"
30 #include "core/common.h"
31 #include "core/edbus-handler.h"
32
33 #define PASS_DEFAULT_MIN_LEVEL                  0
34 #define PASS_DEFAULT_CPU_THRESHOLD              20
35 #define PASS_DEFAULT_LEVEL_UP_THRESHOLD         30
36 #define PASS_DEFAULT_LEVEL_DOWN_THRESHOLD       80
37
38 /*
39  * Per-target pass policy
40  */
41 static struct pass_policy policy;
42
43 /******************************************************
44  *                PASS D-Bus interface                *
45  ******************************************************/
46 static DBusMessage* e_dbus_start_cb(E_DBus_Object *obj, DBusMessage* msg)
47 {
48         if (policy.governor)
49                 policy.governor->update(&policy, PASS_GOV_START);
50         return dbus_message_new_method_return(msg);
51 }
52
53 static DBusMessage* e_dbus_stop_cb(E_DBus_Object *obj, DBusMessage* msg)
54 {
55         if (policy.governor)
56                 policy.governor->update(&policy, PASS_GOV_STOP);
57         return dbus_message_new_method_return(msg);
58 }
59
60 static const struct edbus_method edbus_methods[] = {
61         { "start",           NULL,  NULL, e_dbus_start_cb },
62         { "stop",            NULL,  NULL, e_dbus_stop_cb },
63 };
64
65 /******************************************************
66  *                PASS interface (Init/Exit)          *
67  ******************************************************/
68
69 /*
70  * pass_init - Initialize PASS(Power Aware System Service)
71  *
72  * @data: the instance of structre pass_policy
73  */
74 static void pass_init(void *data)
75 {
76         enum pass_target_type target_type;
77         int max_freq = 0;
78         int max_cpu = 0;
79         int ret;
80         int i;
81
82         /*
83          * Initialize pass-table by parsing pass.conf
84          */
85         ret = get_pass_table(&policy, PASS_CONF_PATH);
86         if (ret < 0) {
87                 _E("cannot parse %s\n", PASS_CONF_PATH);
88                 return;
89         }
90
91         /*
92          * Initialzie D-Bus interface of PASS. User can be able to
93          * turn on/off PASS through D-Bus interface.
94          */
95         ret = register_edbus_method(DEVICED_PATH_PASS, edbus_methods,
96                                     ARRAY_SIZE(edbus_methods));
97         if (ret < 0) {
98                 _I("cannot initialize PASS D-Bus (%d)", ret);
99                 return;
100         }
101
102         /* Check whether PASS is initialzied state or not */
103         if (policy.governor) {
104                 _I("PASS is already active state");
105                 return;
106         }
107
108         /*
109          * Set default value to global pass_policy instance
110          * if variable isn't initialized.
111          */
112         if (!policy.min_level)
113                 policy.min_level = PASS_DEFAULT_MIN_LEVEL;
114         policy.default_min_level = policy.min_level;
115
116         if (!policy.max_level)
117                 policy.max_level = policy.num_levels - 1;
118         policy.default_max_level = policy.max_level;
119
120         if (!policy.init_level)
121                 policy.init_level = PASS_DEFAULT_MIN_LEVEL;
122
123         if (!policy.pass_cpu_threshold)
124                 policy.pass_cpu_threshold = PASS_DEFAULT_CPU_THRESHOLD;
125
126         if (!policy.up_threshold)
127                 policy.up_threshold = PASS_DEFAULT_LEVEL_UP_THRESHOLD;
128
129         if (!policy.down_threshold)
130                 policy.down_threshold = PASS_DEFAULT_LEVEL_DOWN_THRESHOLD;
131
132         if (!policy.level_up_threshold)
133                 policy.level_up_threshold = policy.max_level;
134
135         if (!policy.num_pass_cpu_stats)
136                 policy.num_pass_cpu_stats = PASS_CPU_STATS_DEFAULT;
137
138         for (i = 0; i < policy.num_levels; i++) {
139                 if (max_freq < policy.pass_table[i].limit_max_freq)
140                         max_freq = policy.pass_table[i].limit_max_freq;
141                 if (max_cpu < policy.pass_table[i].limit_max_cpu)
142                         max_cpu = policy.pass_table[i].limit_max_cpu;
143         }
144         policy.cpufreq.max_freq = max_freq;
145         policy.cpufreq.num_nr_cpus = max_cpu;
146
147         /* Allocate memory according to the number of data and cpu */
148         policy.pass_cpu_stats = malloc(sizeof(struct pass_cpu_stats)
149                                                 * policy.num_pass_cpu_stats);
150
151         for (i = 0; i < policy.num_pass_cpu_stats; i++) {
152                 policy.pass_cpu_stats[i].load =
153                         malloc(sizeof(unsigned int) * policy.cpufreq.num_nr_cpus);
154                 policy.pass_cpu_stats[i].nr_running =
155                         malloc(sizeof(unsigned int) * policy.cpufreq.num_nr_cpus);
156                 policy.pass_cpu_stats[i].runnable_load =
157                         malloc(sizeof(unsigned int) * policy.cpufreq.num_nr_cpus);
158         }
159
160         /* Get the instance of PASS governor */
161         policy.governor = pass_get_governor(&policy, policy.gov_type);
162         if (!policy.governor) {
163                 _E("cannot get the instance of PASS governor");
164                 return;
165         }
166         policy.governor->gov_timeout    = policy.gov_timeout;
167
168         /* Get the instance of PASS hotplulg */
169         policy.hotplug = pass_get_hotplug(&policy, policy.gov_type);
170         if (!policy.hotplug) {
171                 _E("cannot get the instance of PASS hotplug");
172         } else {
173                 policy.hotplug->sequence = malloc(sizeof(int)
174                                                   * policy.cpufreq.num_nr_cpus);
175                 for (i = 0; i < policy.cpufreq.num_nr_cpus; i++)
176                         policy.hotplug->sequence[i] = i;
177         }
178
179         if (policy.governor->init) {
180                 ret = policy.governor->init(&policy);
181                 if (ret < 0) {
182                         _E("cannot initialize PASS governor");
183                         return;
184                 }
185         } else {
186                 _E("cannot execute init() of PASS governor");
187                 return;
188         }
189 }
190
191 /*
192  * pass_exit - Exit PASS
193  *
194  * @data: the instance of structre pass_policy
195  */
196 static void pass_exit(void *data)
197 {
198         int ret;
199
200         if (!policy.governor) {
201                 _E("cannot exit PASS");
202                 return;
203         }
204
205         put_pass_table(&policy);
206
207         if (policy.governor->exit) {
208                 ret = policy.governor->exit(&policy);
209                 if (ret < 0) {
210                         _E("cannot exit PASS governor");
211                         return;
212                 }
213         } else {
214                 _E("cannot execute exit() of PASS governor");
215                 return;
216         }
217
218         policy.governor = NULL;
219 }
220
221 static const struct device_ops pass_device_ops = {
222         .priority = DEVICE_PRIORITY_NORMAL,
223         .name     = "pass",
224         .init     = pass_init,
225         .exit     = pass_exit,
226 };
227
228 DEVICE_OPS_REGISTER(&pass_device_ops)