arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / tools / power / cpupower / lib / cpufreq.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
4  */
5
6
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15
16 #include "cpufreq.h"
17 #include "cpupower_intern.h"
18
19 /* CPUFREQ sysfs access **************************************************/
20
21 /* helper function to read file from /sys into given buffer */
22 /* fname is a relative path under "cpuX/cpufreq" dir */
23 static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname,
24                                             char *buf, size_t buflen)
25 {
26         char path[SYSFS_PATH_MAX];
27
28         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
29                          cpu, fname);
30         return cpupower_read_sysfs(path, buf, buflen);
31 }
32
33 /* helper function to write a new value to a /sys file */
34 /* fname is a relative path under "cpuX/cpufreq" dir */
35 static unsigned int sysfs_cpufreq_write_file(unsigned int cpu,
36                                              const char *fname,
37                                              const char *value, size_t len)
38 {
39         char path[SYSFS_PATH_MAX];
40         int fd;
41         ssize_t numwrite;
42
43         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
44                          cpu, fname);
45
46         fd = open(path, O_WRONLY);
47         if (fd == -1)
48                 return 0;
49
50         numwrite = write(fd, value, len);
51         if (numwrite < 1) {
52                 close(fd);
53                 return 0;
54         }
55
56         close(fd);
57
58         return (unsigned int) numwrite;
59 }
60
61 /* read access to files which contain one numeric value */
62
63 enum cpufreq_value {
64         CPUINFO_CUR_FREQ,
65         CPUINFO_MIN_FREQ,
66         CPUINFO_MAX_FREQ,
67         CPUINFO_LATENCY,
68         SCALING_CUR_FREQ,
69         SCALING_MIN_FREQ,
70         SCALING_MAX_FREQ,
71         STATS_NUM_TRANSITIONS,
72         MAX_CPUFREQ_VALUE_READ_FILES
73 };
74
75 static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
76         [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq",
77         [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq",
78         [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq",
79         [CPUINFO_LATENCY]  = "cpuinfo_transition_latency",
80         [SCALING_CUR_FREQ] = "scaling_cur_freq",
81         [SCALING_MIN_FREQ] = "scaling_min_freq",
82         [SCALING_MAX_FREQ] = "scaling_max_freq",
83         [STATS_NUM_TRANSITIONS] = "stats/total_trans"
84 };
85
86 unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
87                                                  const char **table,
88                                                  unsigned int index,
89                                                  unsigned int size)
90 {
91         unsigned long value;
92         unsigned int len;
93         char linebuf[MAX_LINE_LEN];
94         char *endp;
95
96         if (!table || index >= size || !table[index])
97                 return 0;
98
99         len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
100                                       sizeof(linebuf));
101
102         if (len == 0)
103                 return 0;
104
105         value = strtoul(linebuf, &endp, 0);
106
107         if (endp == linebuf || errno == ERANGE)
108                 return 0;
109
110         return value;
111 }
112
113 static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
114                                                  enum cpufreq_value which)
115 {
116         return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
117                                                   which,
118                                                   MAX_CPUFREQ_VALUE_READ_FILES);
119 }
120
121 /* read access to files which contain one string */
122
123 enum cpufreq_string {
124         SCALING_DRIVER,
125         SCALING_GOVERNOR,
126         MAX_CPUFREQ_STRING_FILES
127 };
128
129 static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
130         [SCALING_DRIVER] = "scaling_driver",
131         [SCALING_GOVERNOR] = "scaling_governor",
132 };
133
134
135 static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
136                                           enum cpufreq_string which)
137 {
138         char linebuf[MAX_LINE_LEN];
139         char *result;
140         unsigned int len;
141
142         if (which >= MAX_CPUFREQ_STRING_FILES)
143                 return NULL;
144
145         len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which],
146                                 linebuf, sizeof(linebuf));
147         if (len == 0)
148                 return NULL;
149
150         result = strdup(linebuf);
151         if (result == NULL)
152                 return NULL;
153
154         if (result[strlen(result) - 1] == '\n')
155                 result[strlen(result) - 1] = '\0';
156
157         return result;
158 }
159
160 /* write access */
161
162 enum cpufreq_write {
163         WRITE_SCALING_MIN_FREQ,
164         WRITE_SCALING_MAX_FREQ,
165         WRITE_SCALING_GOVERNOR,
166         WRITE_SCALING_SET_SPEED,
167         MAX_CPUFREQ_WRITE_FILES
168 };
169
170 static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = {
171         [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq",
172         [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq",
173         [WRITE_SCALING_GOVERNOR] = "scaling_governor",
174         [WRITE_SCALING_SET_SPEED] = "scaling_setspeed",
175 };
176
177 static int sysfs_cpufreq_write_one_value(unsigned int cpu,
178                                          enum cpufreq_write which,
179                                          const char *new_value, size_t len)
180 {
181         if (which >= MAX_CPUFREQ_WRITE_FILES)
182                 return 0;
183
184         if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which],
185                                         new_value, len) != len)
186                 return -ENODEV;
187
188         return 0;
189 };
190
191 unsigned long cpufreq_get_freq_kernel(unsigned int cpu)
192 {
193         return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ);
194 }
195
196 unsigned long cpufreq_get_freq_hardware(unsigned int cpu)
197 {
198         return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ);
199 }
200
201 unsigned long cpufreq_get_transition_latency(unsigned int cpu)
202 {
203         return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
204 }
205
206 int cpufreq_get_hardware_limits(unsigned int cpu,
207                                 unsigned long *min,
208                                 unsigned long *max)
209 {
210         if ((!min) || (!max))
211                 return -EINVAL;
212
213         *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ);
214         if (!*min)
215                 return -ENODEV;
216
217         *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ);
218         if (!*max)
219                 return -ENODEV;
220
221         return 0;
222 }
223
224 char *cpufreq_get_driver(unsigned int cpu)
225 {
226         return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER);
227 }
228
229 void cpufreq_put_driver(char *ptr)
230 {
231         if (!ptr)
232                 return;
233         free(ptr);
234 }
235
236 struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu)
237 {
238         struct cpufreq_policy *policy;
239
240         policy = malloc(sizeof(struct cpufreq_policy));
241         if (!policy)
242                 return NULL;
243
244         policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR);
245         if (!policy->governor) {
246                 free(policy);
247                 return NULL;
248         }
249         policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
250         policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ);
251         if ((!policy->min) || (!policy->max)) {
252                 free(policy->governor);
253                 free(policy);
254                 return NULL;
255         }
256
257         return policy;
258 }
259
260 void cpufreq_put_policy(struct cpufreq_policy *policy)
261 {
262         if ((!policy) || (!policy->governor))
263                 return;
264
265         free(policy->governor);
266         policy->governor = NULL;
267         free(policy);
268 }
269
270 struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned
271                                                                 int cpu)
272 {
273         struct cpufreq_available_governors *first = NULL;
274         struct cpufreq_available_governors *current = NULL;
275         char linebuf[MAX_LINE_LEN];
276         unsigned int pos, i;
277         unsigned int len;
278
279         len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors",
280                                 linebuf, sizeof(linebuf));
281         if (len == 0)
282                 return NULL;
283
284         pos = 0;
285         for (i = 0; i < len; i++) {
286                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
287                         if (i - pos < 2)
288                                 continue;
289                         if (current) {
290                                 current->next = malloc(sizeof(*current));
291                                 if (!current->next)
292                                         goto error_out;
293                                 current = current->next;
294                         } else {
295                                 first = malloc(sizeof(*first));
296                                 if (!first)
297                                         return NULL;
298                                 current = first;
299                         }
300                         current->first = first;
301                         current->next = NULL;
302
303                         current->governor = malloc(i - pos + 1);
304                         if (!current->governor)
305                                 goto error_out;
306
307                         memcpy(current->governor, linebuf + pos, i - pos);
308                         current->governor[i - pos] = '\0';
309                         pos = i + 1;
310                 }
311         }
312
313         return first;
314
315  error_out:
316         while (first) {
317                 current = first->next;
318                 if (first->governor)
319                         free(first->governor);
320                 free(first);
321                 first = current;
322         }
323         return NULL;
324 }
325
326 void cpufreq_put_available_governors(struct cpufreq_available_governors *any)
327 {
328         struct cpufreq_available_governors *tmp, *next;
329
330         if (!any)
331                 return;
332
333         tmp = any->first;
334         while (tmp) {
335                 next = tmp->next;
336                 if (tmp->governor)
337                         free(tmp->governor);
338                 free(tmp);
339                 tmp = next;
340         }
341 }
342
343
344 struct cpufreq_available_frequencies
345 *cpufreq_get_available_frequencies(unsigned int cpu)
346 {
347         struct cpufreq_available_frequencies *first = NULL;
348         struct cpufreq_available_frequencies *current = NULL;
349         char one_value[SYSFS_PATH_MAX];
350         char linebuf[MAX_LINE_LEN];
351         unsigned int pos, i;
352         unsigned int len;
353
354         len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
355                                       linebuf, sizeof(linebuf));
356         if (len == 0)
357                 return NULL;
358
359         pos = 0;
360         for (i = 0; i < len; i++) {
361                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
362                         if (i - pos < 2)
363                                 continue;
364                         if (i - pos >= SYSFS_PATH_MAX)
365                                 goto error_out;
366                         if (current) {
367                                 current->next = malloc(sizeof(*current));
368                                 if (!current->next)
369                                         goto error_out;
370                                 current = current->next;
371                         } else {
372                                 first = malloc(sizeof(*first));
373                                 if (!first)
374                                         return NULL;
375                                 current = first;
376                         }
377                         current->first = first;
378                         current->next = NULL;
379
380                         memcpy(one_value, linebuf + pos, i - pos);
381                         one_value[i - pos] = '\0';
382                         if (sscanf(one_value, "%lu", &current->frequency) != 1)
383                                 goto error_out;
384
385                         pos = i + 1;
386                 }
387         }
388
389         return first;
390
391  error_out:
392         while (first) {
393                 current = first->next;
394                 free(first);
395                 first = current;
396         }
397         return NULL;
398 }
399
400 struct cpufreq_available_frequencies
401 *cpufreq_get_boost_frequencies(unsigned int cpu)
402 {
403         struct cpufreq_available_frequencies *first = NULL;
404         struct cpufreq_available_frequencies *current = NULL;
405         char one_value[SYSFS_PATH_MAX];
406         char linebuf[MAX_LINE_LEN];
407         unsigned int pos, i;
408         unsigned int len;
409
410         len = sysfs_cpufreq_read_file(cpu, "scaling_boost_frequencies",
411                                       linebuf, sizeof(linebuf));
412         if (len == 0)
413                 return NULL;
414
415         pos = 0;
416         for (i = 0; i < len; i++) {
417                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
418                         if (i - pos < 2)
419                                 continue;
420                         if (i - pos >= SYSFS_PATH_MAX)
421                                 goto error_out;
422                         if (current) {
423                                 current->next = malloc(sizeof(*current));
424                                 if (!current->next)
425                                         goto error_out;
426                                 current = current->next;
427                         } else {
428                                 first = malloc(sizeof(*first));
429                                 if (!first)
430                                         return NULL;
431                                 current = first;
432                         }
433                         current->first = first;
434                         current->next = NULL;
435
436                         memcpy(one_value, linebuf + pos, i - pos);
437                         one_value[i - pos] = '\0';
438                         if (sscanf(one_value, "%lu", &current->frequency) != 1)
439                                 goto error_out;
440
441                         pos = i + 1;
442                 }
443         }
444
445         return first;
446
447  error_out:
448         while (first) {
449                 current = first->next;
450                 free(first);
451                 first = current;
452         }
453         return NULL;
454 }
455
456 void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies *any)
457 {
458         struct cpufreq_available_frequencies *tmp, *next;
459
460         if (!any)
461                 return;
462
463         tmp = any->first;
464         while (tmp) {
465                 next = tmp->next;
466                 free(tmp);
467                 tmp = next;
468         }
469 }
470
471 void cpufreq_put_boost_frequencies(struct cpufreq_available_frequencies *any)
472 {
473         cpufreq_put_available_frequencies(any);
474 }
475
476 static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
477                                                         const char *file)
478 {
479         struct cpufreq_affected_cpus *first = NULL;
480         struct cpufreq_affected_cpus *current = NULL;
481         char one_value[SYSFS_PATH_MAX];
482         char linebuf[MAX_LINE_LEN];
483         unsigned int pos, i;
484         unsigned int len;
485
486         len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf));
487         if (len == 0)
488                 return NULL;
489
490         pos = 0;
491         for (i = 0; i < len; i++) {
492                 if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') {
493                         if (i - pos  < 1)
494                                 continue;
495                         if (i - pos >= SYSFS_PATH_MAX)
496                                 goto error_out;
497                         if (current) {
498                                 current->next = malloc(sizeof(*current));
499                                 if (!current->next)
500                                         goto error_out;
501                                 current = current->next;
502                         } else {
503                                 first = malloc(sizeof(*first));
504                                 if (!first)
505                                         return NULL;
506                                 current = first;
507                         }
508                         current->first = first;
509                         current->next = NULL;
510
511                         memcpy(one_value, linebuf + pos, i - pos);
512                         one_value[i - pos] = '\0';
513
514                         if (sscanf(one_value, "%u", &current->cpu) != 1)
515                                 goto error_out;
516
517                         pos = i + 1;
518                 }
519         }
520
521         return first;
522
523  error_out:
524         while (first) {
525                 current = first->next;
526                 free(first);
527                 first = current;
528         }
529         return NULL;
530 }
531
532 struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu)
533 {
534         return sysfs_get_cpu_list(cpu, "affected_cpus");
535 }
536
537 void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any)
538 {
539         struct cpufreq_affected_cpus *tmp, *next;
540
541         if (!any)
542                 return;
543
544         tmp = any->first;
545         while (tmp) {
546                 next = tmp->next;
547                 free(tmp);
548                 tmp = next;
549         }
550 }
551
552
553 struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu)
554 {
555         return sysfs_get_cpu_list(cpu, "related_cpus");
556 }
557
558 void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any)
559 {
560         cpufreq_put_affected_cpus(any);
561 }
562
563 static int verify_gov(char *new_gov, char *passed_gov)
564 {
565         unsigned int i, j = 0;
566
567         if (!passed_gov || (strlen(passed_gov) > 19))
568                 return -EINVAL;
569
570         strncpy(new_gov, passed_gov, 20);
571         for (i = 0; i < 20; i++) {
572                 if (j) {
573                         new_gov[i] = '\0';
574                         continue;
575                 }
576                 if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z'))
577                         continue;
578
579                 if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z'))
580                         continue;
581
582                 if (new_gov[i] == '-')
583                         continue;
584
585                 if (new_gov[i] == '_')
586                         continue;
587
588                 if (new_gov[i] == '\0') {
589                         j = 1;
590                         continue;
591                 }
592                 return -EINVAL;
593         }
594         new_gov[19] = '\0';
595         return 0;
596 }
597
598 int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy)
599 {
600         char min[SYSFS_PATH_MAX];
601         char max[SYSFS_PATH_MAX];
602         char gov[SYSFS_PATH_MAX];
603         int ret;
604         unsigned long old_min;
605         int write_max_first;
606
607         if (!policy || !(policy->governor))
608                 return -EINVAL;
609
610         if (policy->max < policy->min)
611                 return -EINVAL;
612
613         if (verify_gov(gov, policy->governor))
614                 return -EINVAL;
615
616         snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min);
617         snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max);
618
619         old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
620         write_max_first = (old_min && (policy->max < old_min) ? 0 : 1);
621
622         if (write_max_first) {
623                 ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
624                                                     max, strlen(max));
625                 if (ret)
626                         return ret;
627         }
628
629         ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min,
630                                             strlen(min));
631         if (ret)
632                 return ret;
633
634         if (!write_max_first) {
635                 ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
636                                                     max, strlen(max));
637                 if (ret)
638                         return ret;
639         }
640
641         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
642                                              gov, strlen(gov));
643 }
644
645
646 int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq)
647 {
648         char value[SYSFS_PATH_MAX];
649
650         snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq);
651
652         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ,
653                                              value, strlen(value));
654 }
655
656
657 int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq)
658 {
659         char value[SYSFS_PATH_MAX];
660
661         snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq);
662
663         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
664                                              value, strlen(value));
665 }
666
667 int cpufreq_modify_policy_governor(unsigned int cpu, char *governor)
668 {
669         char new_gov[SYSFS_PATH_MAX];
670
671         if ((!governor) || (strlen(governor) > 19))
672                 return -EINVAL;
673
674         if (verify_gov(new_gov, governor))
675                 return -EINVAL;
676
677         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
678                                              new_gov, strlen(new_gov));
679 }
680
681 int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency)
682 {
683         struct cpufreq_policy *pol = cpufreq_get_policy(cpu);
684         char userspace_gov[] = "userspace";
685         char freq[SYSFS_PATH_MAX];
686         int ret;
687
688         if (!pol)
689                 return -ENODEV;
690
691         if (strncmp(pol->governor, userspace_gov, 9) != 0) {
692                 ret = cpufreq_modify_policy_governor(cpu, userspace_gov);
693                 if (ret) {
694                         cpufreq_put_policy(pol);
695                         return ret;
696                 }
697         }
698
699         cpufreq_put_policy(pol);
700
701         snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency);
702
703         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED,
704                                              freq, strlen(freq));
705 }
706
707 struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
708                                         unsigned long long *total_time)
709 {
710         struct cpufreq_stats *first = NULL;
711         struct cpufreq_stats *current = NULL;
712         char one_value[SYSFS_PATH_MAX];
713         char linebuf[MAX_LINE_LEN];
714         unsigned int pos, i;
715         unsigned int len;
716
717         len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state",
718                                 linebuf, sizeof(linebuf));
719         if (len == 0)
720                 return NULL;
721
722         *total_time = 0;
723         pos = 0;
724         for (i = 0; i < len; i++) {
725                 if (i == strlen(linebuf) || linebuf[i] == '\n') {
726                         if (i - pos < 2)
727                                 continue;
728                         if ((i - pos) >= SYSFS_PATH_MAX)
729                                 goto error_out;
730                         if (current) {
731                                 current->next = malloc(sizeof(*current));
732                                 if (!current->next)
733                                         goto error_out;
734                                 current = current->next;
735                         } else {
736                                 first = malloc(sizeof(*first));
737                                 if (!first)
738                                         return NULL;
739                                 current = first;
740                         }
741                         current->first = first;
742                         current->next = NULL;
743
744                         memcpy(one_value, linebuf + pos, i - pos);
745                         one_value[i - pos] = '\0';
746                         if (sscanf(one_value, "%lu %llu",
747                                         &current->frequency,
748                                         &current->time_in_state) != 2)
749                                 goto error_out;
750
751                         *total_time = *total_time + current->time_in_state;
752                         pos = i + 1;
753                 }
754         }
755
756         return first;
757
758  error_out:
759         while (first) {
760                 current = first->next;
761                 free(first);
762                 first = current;
763         }
764         return NULL;
765 }
766
767 void cpufreq_put_stats(struct cpufreq_stats *any)
768 {
769         struct cpufreq_stats *tmp, *next;
770
771         if (!any)
772                 return;
773
774         tmp = any->first;
775         while (tmp) {
776                 next = tmp->next;
777                 free(tmp);
778                 tmp = next;
779         }
780 }
781
782 unsigned long cpufreq_get_transitions(unsigned int cpu)
783 {
784         return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS);
785 }