38924c2da349b7817a6e91fff319cd0e0232d9b9
[framework/system/system-server.git] / ss_cpu_handler.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15 */
16
17
18 #include <fcntl.h>
19
20 #include "ss_device_plugin.h"
21 #include "ss_log.h"
22 #include "include/ss_data.h"
23
24 #define DEFAULT_MAX_CPU_FREQ            12000000
25 #define DEFAULT_MIN_CPU_FREQ            1000000
26
27 static int max_cpu_freq_limit = -1;
28 static int min_cpu_freq_limit = -1;
29 static int cur_max_cpu_freq = INT_MIN;
30 static int cur_min_cpu_freq = INT_MAX;
31
32 static Eina_List *max_cpu_freq_list;
33 static Eina_List *min_cpu_freq_list;
34
35 struct cpu_freq_entry {
36         int pid;
37         int freq;
38 };
39
40 static void __set_freq_limit();
41 static int __is_entry_enble(int pid);
42 static int __remove_entry_from_max_cpu_freq_list(int pid);
43 static int __remove_entry_from_min_cpu_freq_list(int pid);
44 static int __add_entry_to_max_cpu_freq_list(int pid, int freq);
45 static int __add_entry_to_min_cpu_freq_list(int pid, int freq);
46 static int __write_max_cpu_freq(int freq);
47 static int __write_min_cpu_freq(int freq);
48
49 int set_max_frequency_action(int argc, char **argv)
50 {
51         int r = -1;
52         
53         if (argc < 2)
54                 return -1;
55
56         r = __add_entry_to_max_cpu_freq_list(atoi(argv[0]), atoi(argv[1]));
57         if (r < 0) {
58                 PRT_TRACE_ERR("Add entry failed");
59                 return -1;
60         }
61
62         r = __write_max_cpu_freq(cur_max_cpu_freq);
63         if (r < 0) {
64                 PRT_TRACE_ERR("Write entry failed");
65                 return -1;
66         }
67
68         return 0;
69 }
70
71 int set_min_frequency_action(int argc, char **argv)
72 {
73         int r = -1;
74         
75         if (argc < 2)
76                 return -1;
77
78         r = __add_entry_to_min_cpu_freq_list(atoi(argv[0]), atoi(argv[1]));
79         if (r < 0) {
80                 PRT_TRACE_ERR("Add entry failed");
81                 return -1;
82         }
83         
84         r = __write_min_cpu_freq(cur_min_cpu_freq);
85         if (r < 0) {
86                 PRT_TRACE_ERR("Write entry failed");
87                 return -1;
88         }
89
90         return 0;
91 }
92
93 int release_max_frequency_action(int argc, char **argv)
94 {
95         int r = -1;
96         if (argc < 1)
97                 return -1;
98         
99         r = __remove_entry_from_max_cpu_freq_list(atoi(argv[0]));
100         if (r < 0) {
101                 PRT_TRACE_ERR("Remove entry failed");
102                 return -1;
103         }
104
105         if (cur_max_cpu_freq == INT_MIN)
106                 cur_max_cpu_freq = max_cpu_freq_limit;
107
108         r = __write_max_cpu_freq(cur_max_cpu_freq);
109         if (r < 0) {
110                 PRT_TRACE_ERR("Write freq failed");
111                 return -1;
112         }
113
114         return 0;
115 }
116
117 int release_min_frequency_action(int argc, char **argv)
118 {
119         int r = -1;
120
121         if (argc < 1)
122                 return -1;
123
124         r = __remove_entry_from_min_cpu_freq_list(atoi(argv[0]));
125         if (r < 0) {
126                 PRT_TRACE_ERR("Remove entry failed");
127                 return -1;
128         }
129
130         if (cur_min_cpu_freq == INT_MAX)
131                 cur_min_cpu_freq = min_cpu_freq_limit;
132
133         r = __write_min_cpu_freq(cur_min_cpu_freq);
134         if (r < 0) {
135                 PRT_TRACE_ERR("Write entry failed");
136                 return -1;
137         }
138
139         return 0;
140 }
141
142 int ss_cpu_handler_init(void)
143 {
144         __set_freq_limit();
145         
146         ss_action_entry_add_internal(PREDEF_SET_MAX_FREQUENCY, set_max_frequency_action, NULL, NULL);
147         ss_action_entry_add_internal(PREDEF_SET_MIN_FREQUENCY, set_min_frequency_action, NULL, NULL);
148         ss_action_entry_add_internal(PREDEF_RELEASE_MAX_FREQUENCY, release_max_frequency_action, NULL, NULL);
149         ss_action_entry_add_internal(PREDEF_RELEASE_MIN_FREQUENCY, release_min_frequency_action, NULL, NULL);
150
151         return 0;
152 }
153
154 static void __set_freq_limit()
155 {
156         int ret;
157
158         ret = plugin_intf->OEM_sys_get_cpufreq_cpuinfo_max_freq(&max_cpu_freq_limit);
159         if (ret < 0) {
160                 PRT_TRACE_ERR("get cpufreq cpuinfo max readerror: %s", strerror(errno));
161                 max_cpu_freq_limit = DEFAULT_MAX_CPU_FREQ;
162         }
163
164         ret = plugin_intf->OEM_sys_get_cpufreq_cpuinfo_min_freq(&min_cpu_freq_limit);
165         if (ret < 0) {
166                 PRT_TRACE_ERR("get cpufreq cpuinfo min readerror: %s", strerror(errno));
167                 min_cpu_freq_limit = DEFAULT_MIN_CPU_FREQ;
168         }
169 }
170
171 static int __is_entry_enable(int pid)
172 {
173         char pid_path[PATH_MAX];
174         
175         snprintf(pid_path, PATH_MAX, "/proc/%d", pid);
176         if (access(pid_path, F_OK) < 0) {
177                 return 0;
178         }
179
180         return 1;
181 }
182
183 static int __remove_entry_from_max_cpu_freq_list(int pid)
184 {
185         Eina_List *tmp;
186         Eina_List *tmp_next;
187         struct cpu_freq_entry *entry;
188
189         cur_max_cpu_freq = INT_MIN;
190
191         EINA_LIST_FOREACH_SAFE(max_cpu_freq_list, tmp, tmp_next, entry) {
192                 if (entry != NULL) {
193                         if ((!__is_entry_enable(entry->pid)) || (entry->pid == pid)) {
194                                 max_cpu_freq_list = eina_list_remove(max_cpu_freq_list, entry);
195                                 free(entry);
196                                 continue;
197                         }
198
199                         if (entry->freq > cur_max_cpu_freq) {
200                                 cur_max_cpu_freq = entry->freq;
201                         }
202                 }
203         }
204
205         return 0;
206 }
207
208 static int __remove_entry_from_min_cpu_freq_list(int pid)
209 {
210         Eina_List *tmp;
211         Eina_List *tmp_next;
212         struct cpu_freq_entry *entry;
213
214         cur_min_cpu_freq = INT_MAX;
215
216         EINA_LIST_FOREACH_SAFE(min_cpu_freq_list, tmp, tmp_next, entry) {
217                 if (entry != NULL) {
218                         if ((!__is_entry_enable(entry->pid)) || (entry->pid == pid)) {
219                                 min_cpu_freq_list = eina_list_remove(min_cpu_freq_list, entry);
220                                 free(entry);
221                                 continue;
222                         }
223
224                         if (entry->freq < cur_min_cpu_freq) {
225                                 cur_min_cpu_freq = entry->freq;
226                         }
227
228                 }
229         }
230
231         return 0;
232 }
233
234 static int __add_entry_to_max_cpu_freq_list(int pid, int freq)
235 {
236         int r = -1;
237         struct cpu_freq_entry *entry;
238         
239         r = __remove_entry_from_max_cpu_freq_list(pid);
240         if (r < 0) {
241                 PRT_TRACE_ERR("Remove duplicated entry failed");
242         }
243
244         if (freq > cur_max_cpu_freq) {
245                 cur_max_cpu_freq = freq;
246         }
247
248         entry = malloc(sizeof(struct cpu_freq_entry));
249         if (!entry) {
250                 PRT_TRACE_ERR("Malloc failed");
251                 return -1;
252         }
253         
254         entry->pid = pid;
255         entry->freq = freq;
256
257         max_cpu_freq_list = eina_list_prepend(max_cpu_freq_list, entry);
258         if (!max_cpu_freq_list) {
259                 PRT_TRACE_ERR("eina_list_prepend failed");
260                 return -1;
261         }
262
263         return 0;
264 }
265
266 static int __add_entry_to_min_cpu_freq_list(int pid, int freq)
267 {
268         int r = -1;
269         struct cpu_freq_entry *entry;
270         
271         r = __remove_entry_from_min_cpu_freq_list(pid);
272         if (r < 0) {
273                 PRT_TRACE_ERR("Remove duplicated entry failed");
274         }
275
276         if (freq < cur_min_cpu_freq) {
277                 cur_min_cpu_freq = freq;
278         }
279
280         entry = malloc(sizeof(struct cpu_freq_entry));
281         if (!entry) {
282                 PRT_TRACE_ERR("Malloc failed");
283                 return -1;
284         }
285         
286         entry->pid = pid;
287         entry->freq = freq;
288
289         min_cpu_freq_list = eina_list_prepend(min_cpu_freq_list, entry);
290         if (!min_cpu_freq_list) {
291                 PRT_TRACE_ERR("eina_list_prepend failed");
292                 return -1;
293         }
294         
295         return 0;
296 }
297
298 static int __write_max_cpu_freq(int freq)
299 {
300         int ret;
301
302         ret = plugin_intf->OEM_sys_set_cpufreq_scaling_max_freq(freq);
303         if (ret < 0) {
304                 PRT_TRACE_ERR("set cpufreq max freq write error: %s", strerror(errno));
305                 return -1;
306         }
307         
308         return 0;
309 }
310
311 static int __write_min_cpu_freq(int freq)
312 {
313         int ret;
314
315         ret = plugin_intf->OEM_sys_set_cpufreq_scaling_min_freq(freq);
316         if (ret < 0) {
317                 PRT_TRACE_ERR("set cpufreq min freq write error: %s", strerror(errno));
318                 return -1;
319         }
320         
321         return 0;
322 }