4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <device-node.h>
24 #include "core/list.h"
26 #include "core/data.h"
27 #include "core/devices.h"
28 #include "core/edbus-handler.h"
29 #include "core/common.h"
30 #include "core/device-notifier.h"
31 #include "proc/proc-handler.h"
33 #define PREDEF_SET_MAX_FREQUENCY "set_max_frequency"
34 #define PREDEF_SET_MIN_FREQUENCY "set_min_frequency"
35 #define PREDEF_RELEASE_MAX_FREQUENCY "release_max_frequency"
36 #define PREDEF_RELEASE_MIN_FREQUENCY "release_min_frequency"
37 #define PREDEF_CPU_COUNT "set_cpu_count"
39 #define POWER_SAVING_CPU_FREQ_RATE (0.7)
41 #define DEFAULT_MAX_CPU_FREQ 1200000
42 #define DEFAULT_MIN_CPU_FREQ 100000
49 static int max_cpu_freq_limit = -1;
50 static int min_cpu_freq_limit = -1;
51 static int cur_max_cpu_freq = INT_MAX;
52 static int cur_min_cpu_freq = INT_MIN;
53 static int power_saving_freq = -1;
55 static dd_list *max_cpu_freq_list;
56 static dd_list *min_cpu_freq_list;
58 static int cpu_number_limit = -1;
59 static int cur_cpu_number = INT_MAX;
60 static dd_list *cpu_number_list;
62 struct cpu_freq_entry {
67 struct cpu_number_entry {
72 static int is_entry_enable(int pid)
74 char pid_path[PATH_MAX];
76 snprintf(pid_path, PATH_MAX, "/proc/%d", pid);
77 if (access(pid_path, F_OK) < 0) {
84 static int write_min_cpu_freq(int freq)
88 ret = device_set_property(DEVICE_TYPE_CPU, PROP_CPU_SCALING_MIN_FREQ, freq);
90 _E("set cpufreq min freq write error: %s", strerror(errno));
97 static int write_max_cpu_freq(int freq)
101 ret = device_set_property(DEVICE_TYPE_CPU, PROP_CPU_SCALING_MAX_FREQ, freq);
103 _E("set cpufreq max freq write error: %s", strerror(errno));
110 static int remove_entry_from_min_cpu_freq_list(int pid)
113 struct cpu_freq_entry *entry;
115 cur_min_cpu_freq = INT_MIN;
117 DD_LIST_FOREACH(min_cpu_freq_list, tmp, entry) {
118 if ((!is_entry_enable(entry->pid)) || (entry->pid == pid)) {
119 DD_LIST_REMOVE(min_cpu_freq_list, entry);
123 if (entry->freq > cur_min_cpu_freq) {
124 cur_min_cpu_freq = entry->freq;
131 static int remove_entry_from_max_cpu_freq_list(int pid)
134 struct cpu_freq_entry *entry;
136 cur_max_cpu_freq = INT_MAX;
138 DD_LIST_FOREACH(max_cpu_freq_list, tmp, entry) {
139 if ((!is_entry_enable(entry->pid)) || (entry->pid == pid)) {
140 DD_LIST_REMOVE(max_cpu_freq_list, entry);
144 if (entry->freq < cur_max_cpu_freq) {
145 cur_max_cpu_freq = entry->freq;
152 int release_max_frequency_action(int argc, char **argv)
159 r = remove_entry_from_max_cpu_freq_list(atoi(argv[0]));
161 _E("Remove entry failed");
165 if (cur_max_cpu_freq == INT_MAX)
166 cur_max_cpu_freq = max_cpu_freq_limit;
168 r = write_max_cpu_freq(cur_max_cpu_freq);
170 _E("Write freq failed");
177 int release_min_frequency_action(int argc, char **argv)
184 r = remove_entry_from_min_cpu_freq_list(atoi(argv[0]));
186 _E("Remove entry failed");
190 if (cur_min_cpu_freq == INT_MIN)
191 cur_min_cpu_freq = min_cpu_freq_limit;
193 r = write_min_cpu_freq(cur_min_cpu_freq);
195 _E("Write entry failed");
202 static int add_entry_to_max_cpu_freq_list(int pid, int freq)
205 struct cpu_freq_entry *entry;
207 r = remove_entry_from_max_cpu_freq_list(pid);
209 _E("Remove duplicated entry failed");
212 entry = malloc(sizeof(struct cpu_freq_entry));
221 DD_LIST_PREPEND(max_cpu_freq_list, entry);
222 if (!max_cpu_freq_list) {
223 _E("eina_list_prepend failed");
226 if (freq < cur_max_cpu_freq) {
227 cur_max_cpu_freq = freq;
232 static int add_entry_to_min_cpu_freq_list(int pid, int freq)
235 struct cpu_freq_entry *entry;
237 r = remove_entry_from_min_cpu_freq_list(pid);
239 _E("Remove duplicated entry failed");
242 entry = malloc(sizeof(struct cpu_freq_entry));
251 DD_LIST_PREPEND(min_cpu_freq_list, entry);
252 if (!min_cpu_freq_list) {
253 _E("eina_list_prepend failed");
256 if (freq > cur_min_cpu_freq) {
257 cur_min_cpu_freq = freq;
262 int set_max_frequency_action(int argc, char **argv)
269 r = add_entry_to_max_cpu_freq_list(atoi(argv[0]), atoi(argv[1]));
271 _E("Add entry failed");
275 r = write_max_cpu_freq(cur_max_cpu_freq);
277 _E("Write entry failed");
284 int set_min_frequency_action(int argc, char **argv)
291 r = add_entry_to_min_cpu_freq_list(atoi(argv[0]), atoi(argv[1]));
293 _E("Add entry failed");
297 r = write_min_cpu_freq(cur_min_cpu_freq);
299 _E("Write entry failed");
306 static int power_saving_cpu_cb(keynode_t *key_nodes, void *data)
310 int power_saving_cpu_stat = -1;
312 power_saving_cpu_stat = vconf_keynode_get_bool(key_nodes);
313 if (power_saving_cpu_stat == 1) {
315 ret = add_entry_to_max_cpu_freq_list(getpid(), power_saving_freq);
317 _E("Add entry failed");
321 ret = remove_entry_from_max_cpu_freq_list(getpid());
323 _E("Remove entry failed");
326 if (cur_max_cpu_freq == INT_MAX)
327 cur_max_cpu_freq = max_cpu_freq_limit;
329 ret = write_max_cpu_freq(cur_max_cpu_freq);
333 device_notify(DEVICE_NOTIFIER_PMQOS_POWERSAVING, (void*)val);
337 static void set_emergency_limit(void)
341 ret = vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &val);
343 _E("failed to get vconf key");
346 if (val != SETTING_PSMODE_EMERGENCY)
349 val = EMERGENCY_LOCK;
350 device_notify(DEVICE_NOTIFIER_PMQOS_EMERGENCY, (void*)val);
353 static int emergency_cpu_cb(keynode_t *key_nodes, void *data)
357 val = vconf_keynode_get_int(key_nodes);
358 if (val == SETTING_PSMODE_EMERGENCY)
359 val = EMERGENCY_LOCK;
361 val = EMERGENCY_UNLOCK;
363 device_notify(DEVICE_NOTIFIER_PMQOS_EMERGENCY, (void*)val);
367 static void set_freq_limit(void)
371 int power_saving_stat = -1;
372 int power_saving_cpu_stat = -1;
374 ret = device_get_property(DEVICE_TYPE_CPU, PROP_CPU_CPUINFO_MAX_FREQ,
375 &max_cpu_freq_limit);
377 _E("get cpufreq cpuinfo max readerror: %s", strerror(errno));
378 max_cpu_freq_limit = DEFAULT_MAX_CPU_FREQ;
381 ret = device_get_property(DEVICE_TYPE_CPU, PROP_CPU_CPUINFO_MIN_FREQ,
382 &min_cpu_freq_limit);
384 _E("get cpufreq cpuinfo min readerror: %s", strerror(errno));
385 min_cpu_freq_limit = DEFAULT_MIN_CPU_FREQ;
387 power_saving_freq = (int)(max_cpu_freq_limit * POWER_SAVING_CPU_FREQ_RATE);
388 _I("max(%d) , ps(%d), min(%d)",
393 ret = vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU,
394 &power_saving_cpu_stat);
396 _E("failed to get vconf key");
399 if (power_saving_cpu_stat != 1)
402 ret = add_entry_to_max_cpu_freq_list(getpid(), power_saving_freq);
404 _E("Add entry failed");
407 ret = write_max_cpu_freq(cur_max_cpu_freq);
409 _E("Write entry failed");
412 device_notify(DEVICE_NOTIFIER_PMQOS_POWERSAVING, (void*)val);
415 static void set_cpu_number_limit(void)
417 device_get_property(DEVICE_TYPE_CPU, PROP_CPU_ENABLE_MAX_NUMBER,
421 static int write_cpu_number(int number)
425 ret = device_set_property(DEVICE_TYPE_CPU, PROP_CPU_ENABLE_MAX_NUMBER,
428 _E("set cpu number max write error: %s", strerror(errno));
435 static int remove_entry_from_cpu_number_list(int pid)
438 struct cpu_number_entry *entry;
440 cur_cpu_number = INT_MAX;
442 DD_LIST_FOREACH(cpu_number_list, tmp, entry) {
443 if ((!is_entry_enable(entry->pid)) || (entry->pid == pid)) {
444 DD_LIST_REMOVE(cpu_number_list, entry);
448 if (entry->number < cur_cpu_number) {
449 cur_cpu_number = entry->number;
456 static int add_entry_to_cpu_number_list(int pid, int number)
459 struct cpu_number_entry *entry;
461 r = remove_entry_from_cpu_number_list(pid);
463 _E("Remove duplicated entry failed");
468 entry = malloc(sizeof(struct cpu_number_entry));
475 entry->number = number;
477 DD_LIST_PREPEND(cpu_number_list, entry);
478 if (!cpu_number_list) {
479 _E("eina_list_prepend failed");
482 if (number < cur_cpu_number) {
483 cur_cpu_number = number;
488 int set_cpu_number_action(int argc, char **argv)
492 if(cur_siop_level() != 0)
495 if (argc == 1) {// release cpu number
496 r = remove_entry_from_cpu_number_list(atoi(argv[0]));
498 _E("Remove entry failed");
502 if (cur_cpu_number == INT_MAX)
503 cur_cpu_number = cpu_number_limit;
505 r = write_cpu_number(cur_cpu_number);
507 _E("Write cpu number failed");
510 } else if (argc ==2) {//set cpu number
511 r = add_entry_to_cpu_number_list(atoi(argv[0]), atoi(argv[1]));
513 _E("Add entry failed");
517 r = write_cpu_number(cur_cpu_number);
519 _E("Write entry failed");
526 static int booting_done(void *data)
529 set_emergency_limit();
533 static DBusMessage *dbus_cpu_handler(E_DBus_Object *obj, DBusMessage *msg)
536 DBusMessageIter iter;
544 dbus_error_init(&err);
546 if (!dbus_message_get_args(msg, &err,
547 DBUS_TYPE_STRING, &type_str,
548 DBUS_TYPE_INT32, &argc,
549 DBUS_TYPE_STRING, &argv[0],
550 DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
551 _E("there is no message");
557 _E("message is invalid!");
562 pid = get_edbus_sender_pid(msg);
563 if (kill(pid, 0) == -1) {
564 _E("%d process does not exist, dbus ignored!", pid);
569 if (strncmp(type_str, PREDEF_SET_MAX_FREQUENCY, strlen(PREDEF_SET_MAX_FREQUENCY)) == 0)
570 ret = set_max_frequency_action(argc, (char **)&argv);
571 else if (strncmp(type_str, PREDEF_SET_MIN_FREQUENCY, strlen(PREDEF_SET_MIN_FREQUENCY)) == 0)
572 ret = set_min_frequency_action(argc, (char **)&argv);
573 else if (strncmp(type_str, PREDEF_RELEASE_MAX_FREQUENCY, strlen(PREDEF_RELEASE_MAX_FREQUENCY)) == 0)
574 ret = release_max_frequency_action(argc, (char **)&argv);
575 else if (strncmp(type_str, PREDEF_RELEASE_MIN_FREQUENCY, strlen(PREDEF_RELEASE_MIN_FREQUENCY)) == 0)
576 ret = release_min_frequency_action(argc, (char **)&argv);
578 reply = dbus_message_new_method_return(msg);
579 dbus_message_iter_init_append(reply, &iter);
580 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
585 static const struct edbus_method edbus_methods[] = {
586 { PREDEF_SET_MAX_FREQUENCY, "siss", "i", dbus_cpu_handler },
587 { PREDEF_SET_MIN_FREQUENCY, "siss", "i", dbus_cpu_handler },
588 { PREDEF_RELEASE_MAX_FREQUENCY, "siss", "i", dbus_cpu_handler },
589 { PREDEF_RELEASE_MIN_FREQUENCY, "siss", "i", dbus_cpu_handler },
592 static void cpu_init(void *data)
596 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
597 ret = register_edbus_method(DEVICED_PATH_SYSNOTI, edbus_methods, ARRAY_SIZE(edbus_methods));
599 _E("fail to init edbus method(%d)", ret);
600 set_cpu_number_limit();
601 register_action(PREDEF_SET_MAX_FREQUENCY, set_max_frequency_action, NULL, NULL);
602 register_action(PREDEF_SET_MIN_FREQUENCY, set_min_frequency_action, NULL, NULL);
603 register_action(PREDEF_RELEASE_MAX_FREQUENCY, release_max_frequency_action, NULL, NULL);
604 register_action(PREDEF_RELEASE_MIN_FREQUENCY, release_min_frequency_action, NULL, NULL);
605 register_action(PREDEF_CPU_COUNT, set_cpu_number_action, NULL, NULL);
607 vconf_notify_key_changed(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU, (void *)power_saving_cpu_cb, NULL);
608 vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, (void *)emergency_cpu_cb, NULL);
611 static const struct device_ops cpu_device_ops = {
612 .priority = DEVICE_PRIORITY_NORMAL,
617 DEVICE_OPS_REGISTER(&cpu_device_ops)