tizen 2.3 release
[framework/system/deviced.git] / src / pass / pass-plugin.c
1 /*
2  * deviced
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 <stdio.h>
21 #include <errno.h>
22 #include <fcntl.h>
23
24 #include "pass.h"
25 #include "pass-plugin.h"
26
27 #include "core/config-parser.h"
28
29 #define BUFF_MAX                        255
30
31 /* Linux standard sysfs node */
32 #define CPUFREQ_SCALING_MAX_FREQ        "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
33 #define CPUFREQ_SCALING_MIN_FREQ        "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
34 #define CPUFREQ_SAMPLING_RATE           "/sys/devices/system/cpu/cpufreq/ondemand/sampling_rate"
35 #define CPUFREQ_UP_THRESHOLD            "/sys/devices/system/cpu/cpufreq/ondemand/up_threshold"
36
37 #define PROC_DT_COMPATIBLE             "/proc/device-tree/compatible"
38
39 /* PASS specific sysfs node */
40 #define PASS_CPU_STATS                  "/sys/kernel/debug/cpufreq/cpu0/load_table"
41
42 int get_pass_cpu_stats(struct pass_policy *policy)
43 {
44         struct pass_cpu_stats *stats = policy->pass_cpu_stats;
45         char path[PATH_MAX] = PASS_CPU_STATS;
46         char str[BUFF_MAX];
47         FILE *fp_stats = NULL;
48         int i, j;
49         int ret = 1;
50
51         if (!stats) {
52                 _E("invalid parameter of structure pass_cpu_stats");
53                 return -EINVAL;
54         }
55
56         fp_stats = fopen(path, "r");
57         if (fp_stats == NULL)
58                 return -EIO;
59
60         fgets(str, BUFF_MAX, fp_stats);
61         for (i = 0; i < policy->num_pass_cpu_stats; i++) {
62                 ret = fscanf(fp_stats, "%lld %d %d %d",
63                         &stats[i].time,
64                         &stats[i].freq,
65                         &stats[i].freq_new,
66                         &stats[i].nr_runnings);
67
68                 for (j = 0; j < policy->cpufreq.num_nr_cpus; j++)
69                         ret = fscanf(fp_stats, "%d", &stats[i].load[j]);
70         }
71         fclose(fp_stats);
72
73         return 0;
74 }
75
76 /*
77  * Helper function
78  * - Read from sysfs entry
79  * - Write to sysfs entry
80  */
81 static int sys_read_buf(char *file, char *buf)
82 {
83         int fd;
84         int r;
85         int ret = 0;
86
87         fd = open(file, O_RDONLY);
88         if (fd == -1)
89                 return -ENOENT;
90
91         r = read(fd, buf, BUFF_MAX);
92         if ((r >= 0) && (r < BUFF_MAX))
93                 buf[r] = '\0';
94         else
95                 ret = -EIO;
96
97         close(fd);
98
99         return ret;
100 }
101
102 static int sys_write_buf(char *file, char *buf)
103 {
104         int fd;
105         int r;
106         int ret = 0;
107
108         fd = open(file, O_WRONLY);
109         if (fd == -1)
110                 return -1;
111
112         r = write(fd, buf, strlen(buf));
113         if (r < 0)
114                 ret = -EIO;
115
116         close(fd);
117
118         return ret;
119 }
120
121 static int sys_get_int(char *fname, int *val)
122 {
123         char buf[BUFF_MAX];
124
125         if (sys_read_buf(fname, buf) == 0) {
126                 *val = atoi(buf);
127                 return 0;
128         } else {
129                 *val = -1;
130                 return -1;
131         }
132 }
133
134 static int sys_set_int(char *fname, int val)
135 {
136         char buf[BUFF_MAX];
137         int r = -1;
138         snprintf(buf, sizeof(buf), "%d", val);
139
140         if (sys_write_buf(fname, buf) == 0)
141                 r = 0;
142
143         return r;
144 }
145
146 /*
147  * Get/Set maximum cpu frequency
148  */
149 #define GET_VALUE(name, path)                   \
150 int get_##name(void)                            \
151 {                                               \
152         int value, ret;                         \
153                                                 \
154         ret =  sys_get_int(path, &value);       \
155         if (ret < 0)                            \
156                 return -EAGAIN;                 \
157                                                 \
158         return value;                           \
159 }                                               \
160
161 #define SET_VALUE(name, path)                   \
162 int set_##name(int value)                       \
163 {                                               \
164         return sys_set_int(path, value);        \
165 }                                               \
166
167 GET_VALUE(cpufreq_scaling_max_freq, CPUFREQ_SCALING_MAX_FREQ);
168 SET_VALUE(cpufreq_scaling_max_freq, CPUFREQ_SCALING_MAX_FREQ);
169
170 GET_VALUE(cpufreq_scaling_min_freq, CPUFREQ_SCALING_MIN_FREQ);
171 SET_VALUE(cpufreq_scaling_min_freq, CPUFREQ_SCALING_MIN_FREQ);
172
173 GET_VALUE(cpufreq_sampling_rate, CPUFREQ_SAMPLING_RATE);
174 SET_VALUE(cpufreq_sampling_rate, CPUFREQ_SAMPLING_RATE);
175
176 GET_VALUE(cpufreq_up_threshold, CPUFREQ_UP_THRESHOLD);
177 SET_VALUE(cpufreq_up_threshold, CPUFREQ_UP_THRESHOLD);
178
179 int get_cpu_online(int cpu)
180 {
181         char path[BUFF_MAX];
182         int online;
183         int ret;
184
185         ret = sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpu);
186         if (ret < 0)
187                 return -EINVAL;
188
189         ret = sys_get_int(path, &online);
190         if (ret < 0)
191                 return -EAGAIN;
192
193         return online;
194 }
195 int set_cpu_online(int cpu, int online)
196 {
197         char path[BUFF_MAX];
198         int ret;
199
200         ret = sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpu);
201         if (ret < 0)
202                 return -EINVAL;
203
204         ret = sys_set_int(path, online);
205         if (ret < 0)
206                 return -EAGAIN;
207
208         return 0;
209 }
210
211 /***************************************************************************
212  *                            Parse pass.conf                              *
213  ***************************************************************************/
214
215 static enum pass_state is_supported(char *value)
216 {
217         enum pass_state state;
218
219         if (!value)
220                 return -EINVAL;
221
222         if (MATCH(value, "yes"))
223                 state = PASS_ON;
224         else if (MATCH(value, "no"))
225                 state = PASS_OFF;
226         else
227                 state = PASS_UNUSED;
228
229         return state;
230 }
231
232 static int pass_parse_scenario(struct parse_result *result, void *user_data,
233                                unsigned int index)
234 {
235         struct pass_policy *policy = user_data;
236         struct pass_scenario_policy *scenario = &policy->scenario;
237         char section_name[BUFF_MAX];
238         int i;
239
240         if (!policy && !scenario && !result)
241                 return 0;
242
243         if (!result->section || !result->name || !result->value)
244                 return 0;
245
246         /* Parse 'PassScenario' section */
247         if (MATCH(result->section, "PassScenario")) {
248                 if (MATCH(result->name, "pass_scenario_support")) {
249                         scenario->state = is_supported(result->value);
250                         if (scenario->state < 0)
251                                 return -EINVAL;
252
253                 } else if (MATCH(result->name, "pass_num_scenarios")) {
254                         scenario->num_scenarios = atoi(result->value);
255
256                         if (scenario->num_scenarios > 0 && !scenario->list) {
257                                 scenario->list = malloc(sizeof(struct pass_scenario)
258                                                         * scenario->num_scenarios);
259                                 if (!scenario->list) {
260                                         _E("cannot allocate memory for Scenario\n");
261                                         return -EINVAL;
262                                 }
263                         }
264                 }
265         }
266
267         if (scenario->state != PASS_ON)
268                 return 0;
269
270         if (!scenario->num_scenarios)
271                 return 0;
272
273         if (index > scenario->num_scenarios || index == PASS_UNUSED)
274                 return 0;
275
276         /* Parse 'Scenario' section */
277         if (MATCH(result->name, "name")) {
278                 strcpy(scenario->list[index].name, result->value);
279         } else if (MATCH(result->name, "support")) {
280                 scenario->list[index].state = is_supported(result->value);
281                 if (scenario->list[index].state < 0)
282                         return -EINVAL;
283         } else if (MATCH(result->name, "cpufreq_min_level")) {
284                 scenario->list[index].cpufreq_min_level = atoi(result->value);
285         } else if (MATCH(result->name, "cpufreq_max_level")) {
286                 scenario->list[index].cpufreq_max_level = atoi(result->value);
287         } else if (MATCH(result->name, "busfreq_min_level")) {
288                 scenario->list[index].busfreq_min_level = atoi(result->value);
289         } else if (MATCH(result->name, "busfreq_max_level")) {
290                 scenario->list[index].busfreq_max_level = atoi(result->value);
291         } else if (MATCH(result->name, "gpufreq_min_level")) {
292                 scenario->list[index].gpufreq_min_level = atoi(result->value);
293         } else if (MATCH(result->name, "gpufreq_max_level")) {
294                 scenario->list[index].gpufreq_max_level = atoi(result->value);
295         }
296
297         return 0;
298 }
299
300 static int  pass_parse_cpufreq_level(struct parse_result *result,
301                                     void *user_data, int level)
302 {
303         struct pass_policy *policy = user_data;
304         char section_name[BUFF_MAX];
305         int i, ret;
306
307         if (!result)
308                 return 0;
309
310         if (!result->section || !result->name || !result->value)
311                 return 0;
312
313         if (MATCH(result->name, "limit_max_freq"))
314                 policy->pass_table[level].limit_max_freq = atoi(result->value);
315         else if (MATCH(result->name, "limit_max_cpu"))
316                 policy->pass_table[level].limit_max_cpu = atoi(result->value);
317
318         else if (MATCH(result->name, "num_down_cond"))
319                 policy->pass_table[level].num_down_cond = atoi(result->value);
320         else if (MATCH(result->name, "num_down_cond_freq"))
321                 policy->pass_table[level].down_cond[0].freq = atoi(result->value);
322         else if (MATCH(result->name, "num_down_cond_nr_running"))
323                 policy->pass_table[level].down_cond[0].nr_running = atoi(result->value);
324         else if (MATCH(result->name, "num_down_cond_busy_cpu"))
325                 policy->pass_table[level].down_cond[0].busy_cpu = atoi(result->value);
326
327         else if (MATCH(result->name, "num_up_cond"))
328                 policy->pass_table[level].num_up_cond = atoi(result->value);
329         else if (MATCH(result->name, "num_up_cond_freq"))
330                 policy->pass_table[level].up_cond[0].freq = atoi(result->value);
331         else if (MATCH(result->name, "num_up_cond_nr_running"))
332                 policy->pass_table[level].up_cond[0].nr_running = atoi(result->value);
333         else if (MATCH(result->name, "num_up_cond_busy_cpu"))
334                 policy->pass_table[level].up_cond[0].busy_cpu = atoi(result->value);
335
336         else if (MATCH(result->name, "num_left_cond"))
337                 policy->pass_table[level].num_left_cond = atoi(result->value);
338         else if (MATCH(result->name, "num_left_cond_freq"))
339                 policy->pass_table[level].left_cond[0].freq = atoi(result->value);
340         else if (MATCH(result->name, "num_left_cond_nr_running"))
341                 policy->pass_table[level].left_cond[0].nr_running = atoi(result->value);
342         else if (MATCH(result->name, "num_left_cond_busy_cpu"))
343                 policy->pass_table[level].left_cond[0].busy_cpu = atoi(result->value);
344
345         else if (MATCH(result->name, "num_right_cond"))
346                 policy->pass_table[level].num_right_cond = atoi(result->value);
347         else if (MATCH(result->name, "num_right_cond_freq"))
348                 policy->pass_table[level].right_cond[0].freq = atoi(result->value);
349         else if (MATCH(result->name, "num_right_cond_nr_running"))
350                 policy->pass_table[level].right_cond[0].nr_running = atoi(result->value);
351         else if (MATCH(result->name, "num_right_cond_busy_cpu"))
352                 policy->pass_table[level].right_cond[0].busy_cpu = atoi(result->value);
353
354         return 0;
355 }
356
357 static int pass_parse_core(struct parse_result *result, void *user_data)
358 {
359         struct pass_policy *policy = user_data;
360         char section_name[BUFF_MAX];
361         int i, ret;
362
363         if (!result)
364                 return 0;
365
366         if (!result->section || !result->name || !result->value)
367                 return 0;
368
369         if (MATCH(result->name, "pass_compatible")) {
370                 char compatible[BUFF_MAX];
371
372                 ret = sys_read_buf(PROC_DT_COMPATIBLE, compatible);
373                 if (ret < 0)
374                         return -EEXIST;
375
376                 if (strcmp(compatible, result->value))
377                         return -EINVAL;
378
379                 _I("Match compatible string : %s\n", compatible);
380        } else if (MATCH(result->name, "pass_support"))
381                 policy->state = atoi(result->value);
382         else if (MATCH(result->name, "pass_gov_type"))
383                 policy->gov_type = atoi(result->value);
384         else if (MATCH(result->name, "pass_num_levels"))
385                 policy->num_levels = atoi(result->value);
386         else if (MATCH(result->name, "pass_min_level"))
387                 policy->min_level = atoi(result->value);
388         else if (MATCH(result->name, "pass_max_level"))
389                 policy->max_level = atoi(result->value);
390         else if (MATCH(result->name, "pass_num_cpu_stats"))
391                 policy->num_pass_cpu_stats = atoi(result->value);
392         else if (MATCH(result->name, "pass_cpu_threshold"))
393                 policy->pass_cpu_threshold = atoi(result->value);
394         else if (MATCH(result->name, "pass_up_threshold"))
395                 policy->up_threshold = atoi(result->value);
396         else if (MATCH(result->name, "pass_down_threshold"))
397                 policy->down_threshold = atoi(result->value);
398         else if (MATCH(result->name, "pass_init_level"))
399                 policy->init_level = atoi(result->value);
400         else if (MATCH(result->name, "pass_level_up_threshold"))
401                 policy->level_up_threshold = atoi(result->value);
402         else if (MATCH(result->name, "pass_governor_timeout")) {
403                 policy->gov_timeout = atof(result->value);
404
405                 if (PASS_MIN_GOV_TIMEOUT > policy->gov_timeout)
406                         policy->gov_timeout = PASS_MIN_GOV_TIMEOUT;
407         }
408
409         if (policy->num_levels > 0 && !policy->pass_table) {
410                 policy->pass_table = malloc(sizeof(struct pass_table)
411                                * policy->num_levels);
412                 if (!policy->pass_table) {
413                         _E("cannot allocate memory for pass_table\n");
414                         return -EINVAL;
415                 }
416         }
417
418         return 0;
419 }
420
421 static int pass_load_config(struct parse_result *result, void *user_data)
422 {
423         struct pass_policy *policy = user_data;
424         struct pass_scenario_policy *scenario = &policy->scenario;
425         char section_name[BUFF_MAX];
426         int level = PASS_UNUSED;
427         int index = PASS_UNUSED;
428         int i, ret;
429
430         if (!result)
431                 return 0;
432
433         if (!result->section || !result->name || !result->value)
434                 return 0;
435
436         /* Parsing 'PASS' section */
437         if (MATCH(result->section, "Pass")) {
438                 ret = pass_parse_core(result, user_data);
439                 if (ret < 0) {
440                         _E("cannot parse the core part\n");
441                         return ret;
442                 }
443
444                 goto out;
445         }
446
447         /* Parsing 'CpufreqLevel' section to get pass-table */
448         for (level = 0; level < policy->num_levels; level++) {
449                 ret = sprintf(section_name, "CpufreqLevel%d", level);
450
451                 if (MATCH(result->section, section_name)) {
452                         ret = pass_parse_cpufreq_level(result, user_data, level);
453                         if (ret < 0) {
454                                 _E("cannot parse 'Cpufreq' section\n");
455                                 return ret;
456                         }
457
458                         goto out;
459                 }
460         }
461
462         /* Parsing 'PassScenario' section */
463         if (MATCH(result->section, "PassScenario")) {
464                 ret = pass_parse_scenario(result, user_data, PASS_UNUSED);
465                 if (ret < 0) {
466                         _E("cannot parse 'PassScenario' section\n");
467                         return ret;
468                 }
469
470                 goto out;
471         }
472
473         /* Parsing 'Scenario' section */
474         for (index = 0; index < scenario->num_scenarios; index++) {
475                 ret = sprintf(section_name, "Scenario%d", index);
476
477                 if (MATCH(result->section, section_name)) {
478                         ret = pass_parse_scenario(result, user_data, index);
479                         if (ret < 0) {
480                                 _E("cannot parse 'Scenario' section\n");
481                                 return ret;
482                         }
483
484                         goto out;
485                 }
486         }
487
488 out:
489         return 0;
490 }
491
492 int get_pass_table(struct pass_policy *policy, char *pass_conf_path)
493 {
494         int ret;
495
496         policy->state = PASS_UNUSED;
497         policy->scenario.state = PASS_UNUSED;
498
499         ret = config_parse(pass_conf_path, pass_load_config, policy);
500         if (ret < 0) {
501                 _E("cannot parse %s\n", pass_conf_path);
502                 return -EINVAL;
503         }
504
505         if (policy->state == PASS_UNUSED)
506                 return -EINVAL;
507
508         if (policy->scenario.state == PASS_UNUSED)
509                 _W("%s don't include the list of pass-scenario\n");
510         else
511                 _I("can%s use pass-scenario",
512                                 policy->scenario.state ? "" : "not");
513
514         return 0;
515 }
516
517 void put_pass_table(struct pass_policy *policy)
518 {
519         if(policy->pass_table)
520                 free(policy->pass_table);
521
522         if(policy->scenario.list)
523                 free(policy->scenario.list);
524 }
525
526 /*
527  * get_time_ms - Return current time (unit: millisecond)
528  */
529 int64_t get_time_ms(void)
530 {
531         struct timeval now;
532
533         gettimeofday(&now, NULL);
534
535         return (int64_t)(now.tv_sec * 1000 + now.tv_usec / 1000);
536 }