arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / tools / power / cpupower / lib / cpupower.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
4  */
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <errno.h>
12 #include <stdlib.h>
13
14 #include "cpupower.h"
15 #include "cpupower_intern.h"
16
17 int is_valid_path(const char *path)
18 {
19         if (access(path, F_OK) == -1)
20                 return 0;
21         return 1;
22 }
23
24 unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen)
25 {
26         ssize_t numread;
27         int fd;
28
29         fd = open(path, O_RDONLY);
30         if (fd == -1)
31                 return 0;
32
33         numread = read(fd, buf, buflen - 1);
34         if (numread < 1) {
35                 close(fd);
36                 return 0;
37         }
38
39         buf[numread] = '\0';
40         close(fd);
41
42         return (unsigned int) numread;
43 }
44
45 unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen)
46 {
47         ssize_t numwritten;
48         int fd;
49
50         fd = open(path, O_WRONLY);
51         if (fd == -1)
52                 return 0;
53
54         numwritten = write(fd, buf, buflen - 1);
55         if (numwritten < 1) {
56                 perror(path);
57                 close(fd);
58                 return -1;
59         }
60
61         close(fd);
62
63         return (unsigned int) numwritten;
64 }
65
66 /*
67  * Detect whether a CPU is online
68  *
69  * Returns:
70  *     1 -> if CPU is online
71  *     0 -> if CPU is offline
72  *     negative errno values in error case
73  */
74 int cpupower_is_cpu_online(unsigned int cpu)
75 {
76         char path[SYSFS_PATH_MAX];
77         int fd;
78         ssize_t numread;
79         unsigned long long value;
80         char linebuf[MAX_LINE_LEN];
81         char *endp;
82         struct stat statbuf;
83
84         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
85
86         if (stat(path, &statbuf) != 0)
87                 return 0;
88
89         /*
90          * kernel without CONFIG_HOTPLUG_CPU
91          * -> cpuX directory exists, but not cpuX/online file
92          */
93         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
94         if (stat(path, &statbuf) != 0)
95                 return 1;
96
97         fd = open(path, O_RDONLY);
98         if (fd == -1)
99                 return -errno;
100
101         numread = read(fd, linebuf, MAX_LINE_LEN - 1);
102         if (numread < 1) {
103                 close(fd);
104                 return -EIO;
105         }
106         linebuf[numread] = '\0';
107         close(fd);
108
109         value = strtoull(linebuf, &endp, 0);
110         if (value > 1)
111                 return -EINVAL;
112
113         return value;
114 }
115
116 /* returns -1 on failure, 0 on success */
117 static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
118 {
119         char linebuf[MAX_LINE_LEN];
120         char *endp;
121         char path[SYSFS_PATH_MAX];
122
123         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
124                          cpu, fname);
125         if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0)
126                 return -1;
127         *result = strtol(linebuf, &endp, 0);
128         if (endp == linebuf || errno == ERANGE)
129                 return -1;
130         return 0;
131 }
132
133 static int __compare(const void *t1, const void *t2)
134 {
135         struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
136         struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
137         if (top1->pkg < top2->pkg)
138                 return -1;
139         else if (top1->pkg > top2->pkg)
140                 return 1;
141         else if (top1->core < top2->core)
142                 return -1;
143         else if (top1->core > top2->core)
144                 return 1;
145         else if (top1->cpu < top2->cpu)
146                 return -1;
147         else if (top1->cpu > top2->cpu)
148                 return 1;
149         else
150                 return 0;
151 }
152
153 /*
154  * Returns amount of cpus, negative on error, cpu_top must be
155  * passed to cpu_topology_release to free resources
156  *
157  * Array is sorted after ->pkg, ->core, then ->cpu
158  */
159 int get_cpu_topology(struct cpupower_topology *cpu_top)
160 {
161         int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
162
163         cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
164         if (cpu_top->core_info == NULL)
165                 return -ENOMEM;
166         cpu_top->pkgs = cpu_top->cores = 0;
167         for (cpu = 0; cpu < cpus; cpu++) {
168                 cpu_top->core_info[cpu].cpu = cpu;
169                 cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu);
170                 if(sysfs_topology_read_file(
171                         cpu,
172                         "physical_package_id",
173                         &(cpu_top->core_info[cpu].pkg)) < 0) {
174                         cpu_top->core_info[cpu].pkg = -1;
175                         cpu_top->core_info[cpu].core = -1;
176                         continue;
177                 }
178                 if(sysfs_topology_read_file(
179                         cpu,
180                         "core_id",
181                         &(cpu_top->core_info[cpu].core)) < 0) {
182                         cpu_top->core_info[cpu].pkg = -1;
183                         cpu_top->core_info[cpu].core = -1;
184                         continue;
185                 }
186         }
187
188         qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
189               __compare);
190
191         /* Count the number of distinct pkgs values. This works
192            because the primary sort of the core_info struct was just
193            done by pkg value. */
194         last_pkg = cpu_top->core_info[0].pkg;
195         for(cpu = 1; cpu < cpus; cpu++) {
196                 if (cpu_top->core_info[cpu].pkg != last_pkg &&
197                                 cpu_top->core_info[cpu].pkg != -1) {
198
199                         last_pkg = cpu_top->core_info[cpu].pkg;
200                         cpu_top->pkgs++;
201                 }
202         }
203         if (!(cpu_top->core_info[0].pkg == -1))
204                 cpu_top->pkgs++;
205
206         /* Intel's cores count is not consecutively numbered, there may
207          * be a core_id of 3, but none of 2. Assume there always is 0
208          * Get amount of cores by counting duplicates in a package
209         for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
210                 if (cpu_top->core_info[cpu].core == 0)
211         cpu_top->cores++;
212         */
213         return cpus;
214 }
215
216 void cpu_topology_release(struct cpupower_topology cpu_top)
217 {
218         free(cpu_top.core_info);
219 }