pass-hal: tm2: Update hotplug ops for set/get functions of min/max online CPUs
[platform/adaptation/tm2/pass-hal-tm2.git] / src / cpu / cpu.c
1 #include <errno.h>
2 #include <limits.h>
3 #include <pass/hal.h>
4 #include <pass/hal-log.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "../shared/sysfs.h"
10
11 /* TODO: Version! */
12 #define HAL_VERSION     MAKE_2B_CODE_4(VER_MAJOR,VER_MINOR,VER_REVISION,VER_RELEASE)
13 #define DEV_VERSION_CPU MAKE_2B_CODE_2(1,0)
14
15 #define CPUFREQ_PATH_PREFIX                     "/sys/devices/system/cpu/"
16 #define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX       "/cpufreq/scaling_governor"
17 #define CPUFREQ_AVAIL_GOVERNOR_PATH_SUFFIX      "/cpufreq/scaling_available_governors"
18
19 /*
20  * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy
21  * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy.
22  */
23 #define CPUFREQ_CURR_FREQ_PATH_SUFFIX           "/cpufreq/cpuinfo_cur_freq"
24 #define CPUFREQ_MIN_FREQ_PATH_SUFFIX            "/cpufreq/scaling_min_freq"
25 #define CPUFREQ_MAX_FREQ_PATH_SUFFIX            "/cpufreq/scaling_max_freq"
26 #define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX        "/cpufreq/ondemand/up_threshold"
27
28 #define LOADTABLE_PATH_PREFIX                   "/sys/kernel/debug/cpufreq/"
29 #define LOADTABLE_PATH_SUFFIX                   "/load_table"
30
31 #define CPU_ONLINE_PATH_PREFIX                  "/sys/devices/system/cpu/cpu"
32 #define CPU_ONLINE_PATH_SUFFIX                  "/online"
33 #define CPU_ONLINE_STATE_ON                     1
34 #define CPU_ONLINE_STATE_OFF                    0
35
36 #define TMU_PATH_PREFIX                         "/sys/class/thermal/thermal_zone"
37 #define TMU_TEMP_PATH_SUFFIX                    "/temp"
38 #define TMU_POLICY_PATH_SUFFIX                  "/policy"
39
40 #define TM2_CPU_MIN_NUM                         0
41 #define TM2_CPU_MAX_NUM                         7
42
43 #define TM2_CPU_LITTLE_RESNAME                  "cpu0"
44 #define TM2_CPU_BIG_RESNAME                     "cpu4"
45 #define TM2_CPU_LITTLE_THERMAL_ZONE_NUM         3
46 #define TM2_CPU_BIG_THERMAL_ZONE_NUM            0
47
48
49 static int tm2_dvfs_get_curr_governor(char *res_name, char *governor)
50 {
51         char path[PATH_MAX];
52         int ret;
53
54         if ((!res_name) || (!governor))
55                 return -EINVAL;
56
57         snprintf(path, PATH_MAX, "%s%s%s",
58                 CPUFREQ_PATH_PREFIX,
59                 res_name,
60                 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
61
62         ret = sysfs_read_str(path, governor, BUFF_MAX);
63         if (ret < 0)
64                 return ret;
65
66         return 0;
67 }
68
69 static int tm2_dvfs_set_curr_governor(char *res_name, char *governor)
70 {
71         char path[PATH_MAX];
72         int ret;
73
74         if ((!res_name) || (!governor))
75                 return -EINVAL;
76
77         snprintf(path, PATH_MAX, "%s%s%s",
78                 CPUFREQ_PATH_PREFIX,
79                 res_name,
80                 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
81
82         ret = sysfs_write_str(path, governor);
83         if (ret < 0)
84                 return ret;
85
86         return 0;
87 }
88
89 static int tm2_dvfs_get_curr_freq(char *res_name)
90 {
91         char path[PATH_MAX];
92         int freq, ret;
93
94         if (!res_name)
95                 return -EINVAL;
96
97         snprintf(path, PATH_MAX, "%s%s%s",
98                 CPUFREQ_PATH_PREFIX,
99                 res_name,
100                 CPUFREQ_CURR_FREQ_PATH_SUFFIX);
101
102         ret = sysfs_read_int(path, &freq);
103         if (ret < 0)
104                 return ret;
105
106         return freq;
107 }
108
109 static int tm2_dvfs_get_min_freq(char *res_name)
110 {
111         char path[PATH_MAX];
112         int freq, ret;
113
114         if (!res_name)
115                 return -EINVAL;
116
117         snprintf(path, PATH_MAX, "%s%s%s",
118                 CPUFREQ_PATH_PREFIX,
119                 res_name,
120                 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
121
122         ret = sysfs_read_int(path, &freq);
123         if (ret < 0)
124                 return ret;
125
126         return freq;
127 }
128
129 static int tm2_dvfs_set_min_freq(char *res_name, int freq)
130 {
131         char path[PATH_MAX];
132         int ret;
133
134         if ((!res_name) || (freq < 0))
135                 return -EINVAL;
136
137         snprintf(path, PATH_MAX, "%s%s%s",
138                 CPUFREQ_PATH_PREFIX,
139                 res_name,
140                 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
141
142         ret = sysfs_write_int(path, freq);
143         if (ret < 0)
144                 return ret;
145
146         return 0;
147 }
148
149 static int tm2_dvfs_get_max_freq(char *res_name)
150 {
151         char path[PATH_MAX];
152         int freq, ret;
153
154         if (!res_name)
155                 return -EINVAL;
156
157         snprintf(path, PATH_MAX, "%s%s%s",
158                 CPUFREQ_PATH_PREFIX,
159                 res_name,
160                 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
161
162         ret = sysfs_read_int(path, &freq);
163         if (ret < 0)
164                 return ret;
165
166         return freq;
167 }
168
169 static int tm2_dvfs_set_max_freq(char *res_name, int freq)
170 {
171         char path[PATH_MAX];
172         int ret;
173
174         if ((!res_name) || (freq < 0))
175                 return -EINVAL;
176
177         snprintf(path, PATH_MAX, "%s%s%s",
178                 CPUFREQ_PATH_PREFIX,
179                 res_name,
180                 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
181
182         ret = sysfs_write_int(path, freq);
183         if (ret < 0)
184                 return ret;
185         return 0;
186 }
187
188 static int tm2_dvfs_get_up_threshold(char *res_name)
189 {
190         char path[PATH_MAX];
191         int val, ret;
192
193         if (!res_name)
194                 return -EINVAL;
195
196         snprintf(path, PATH_MAX, "%s%s%s",
197                 CPUFREQ_PATH_PREFIX,
198                 res_name,
199                 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
200
201         ret = sysfs_read_int(path, &val);
202         if (ret < 0)
203                 return ret;
204
205         return val;
206 }
207
208 static int tm2_dvfs_set_up_threshold(char *res_name, int up_threshold)
209 {
210         char path[PATH_MAX];
211         int ret;
212
213         if ((!res_name) || (up_threshold < 0))
214                 return -EINVAL;
215
216         snprintf(path, PATH_MAX, "%s%s%s",
217                 CPUFREQ_PATH_PREFIX,
218                 res_name,
219                 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
220
221         ret = sysfs_write_int(path, up_threshold);
222         if (ret < 0)
223                 return ret;
224
225         return 0;
226 }
227
228 static int tm2_dvfs_get_load_table(char *res_name, void *pass_cpu_load_table)
229 {
230         return 0;
231 }
232
233 static struct pass_resource_dvfs_ops tm2_cpu_dvfs_ops =  {
234         .get_curr_governor = tm2_dvfs_get_curr_governor,
235         .set_curr_governor = tm2_dvfs_set_curr_governor,
236         .get_avail_governor = NULL,
237         .get_curr_freq = tm2_dvfs_get_curr_freq,
238         .get_min_freq = tm2_dvfs_get_min_freq,
239         .set_min_freq = tm2_dvfs_set_min_freq,
240         .get_max_freq = tm2_dvfs_get_max_freq,
241         .set_max_freq = tm2_dvfs_set_max_freq,
242         .get_up_threshold = tm2_dvfs_get_up_threshold,
243         .set_up_threshold = tm2_dvfs_set_up_threshold,
244         .get_load_table = tm2_dvfs_get_load_table,
245 };
246
247 static int tm2_hotplug_get_online_state(char *res_name, int cpu)
248 {
249         char path[PATH_MAX];
250         int ret, online;
251
252         if ((!res_name))
253                 return -EINVAL;
254         if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
255                 return -EINVAL;
256
257         snprintf(path, PATH_MAX, "%s%d%s",
258                 CPU_ONLINE_PATH_PREFIX,
259                 cpu,
260                 CPU_ONLINE_PATH_SUFFIX);
261
262         ret = sysfs_read_int(path, &online);
263         if (ret < 0)
264                 return ret;
265
266         return online;
267 }
268
269 static int tm2_hotplug_set_online_state(char *res_name, int cpu, int on)
270 {
271         char path[PATH_MAX];
272         int ret;
273
274
275         if ((!res_name))
276                 return -EINVAL;
277         if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
278                 return -EINVAL;
279         if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
280                 return -EINVAL;
281
282         /* TODO: Can we turn off CPU0? */
283
284         snprintf(path, PATH_MAX, "%s%d%s",
285                 CPU_ONLINE_PATH_PREFIX,
286                 cpu,
287                 CPU_ONLINE_PATH_SUFFIX);
288
289         ret = sysfs_write_int(path, on);
290         if (ret < 0)
291                 return ret;
292
293         return 0;
294 }
295
296 static struct pass_resource_hotplug_ops tm2_cpu_hotplus_ops = {
297         .get_online_state = tm2_hotplug_get_online_state,
298         .set_online_state = tm2_hotplug_set_online_state,
299         .get_online_min_num = NULL,
300         .set_online_min_num = NULL,
301         .get_online_max_num = NULL,
302         .set_online_max_num = NULL,
303 };
304
305 static int tm2_tmu_get_temp(char *res_name)
306 {
307         char path[PATH_MAX];
308         int tz_num, temp;
309         int ret;
310
311         if (!res_name)
312                 return -EINVAL;
313
314         if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME))
315                 tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM;
316         else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME))
317                 tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM;
318         else
319                 return -EINVAL;
320
321         snprintf(path, PATH_MAX, "%s%d%s",
322                 TMU_PATH_PREFIX,
323                 tz_num,
324                 TMU_TEMP_PATH_SUFFIX);
325
326         ret = sysfs_read_int(path, &temp);
327         if (ret < 0)
328                 return ret;
329
330         return temp;
331 }
332
333 static int tm2_tmu_get_policy(char *res_name, char *policy)
334 {
335         char path[PATH_MAX];
336         int ret, tz_num;
337
338         if ((!res_name) || (!policy))
339                 return -EINVAL;
340
341         if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME))
342                 tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM;
343         else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME))
344                 tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM;
345         else
346                 return -EINVAL;
347
348         snprintf(path, PATH_MAX, "%s%d%s",
349                 TMU_PATH_PREFIX,
350                 tz_num,
351                 TMU_POLICY_PATH_SUFFIX);
352
353         ret = sysfs_read_str(path, policy, BUFF_MAX);
354         if (ret < 0)
355                 return ret;
356
357         return 0;
358 }
359
360 static struct pass_resource_tmu_ops tm2_cpu_tmu_ops = {
361         .get_temp = tm2_tmu_get_temp,
362         .get_policy = tm2_tmu_get_policy,
363 };
364
365 static int tm2_cpu_open(struct pass_resource_info *info,
366                 struct pass_resource_common **common)
367 {
368         struct pass_resource_cpu *cpu_res;
369
370         if (!info)
371                 return -EINVAL;
372
373         /* TODO: Possibility of a memory leak */
374         cpu_res = calloc(1, sizeof(struct pass_resource_cpu));
375         if (!cpu_res)
376                 return -ENOMEM;
377
378         cpu_res->common.info = info;
379         cpu_res->dvfs = tm2_cpu_dvfs_ops;
380         cpu_res->hotplug = tm2_cpu_hotplus_ops;
381         cpu_res->tmu = tm2_cpu_tmu_ops;
382
383         *common = (struct pass_resource_common *) cpu_res;
384
385         return 0;
386 }
387
388 static int tm2_cpu_close(struct pass_resource_common *common)
389 {
390         if (!common)
391                 return -EINVAL;
392
393         free(common);
394
395         return 0;
396 }
397
398 HAL_MODULE_STRUCTURE = {
399         .magic = HAL_INFO_TAG,
400         .hal_version = HAL_VERSION,
401         .device_version = DEV_VERSION_CPU,
402         .id = PASS_RESOURCE_CPU_ID,
403         .name = PASS_RESOURCE_CPU_NAME,
404         .author = "Wook Song <wook16.song@samsung.com>",
405         .open = tm2_cpu_open,
406         .close = tm2_cpu_close,
407 };