arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / tools / power / cpupower / lib / powercap.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  (C) 2016 SUSE Software Solutions GmbH
4  *           Thomas Renninger <trenn@suse.de>
5  */
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <dirent.h>
15
16 #include "powercap.h"
17
18 static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
19 {
20         int fd;
21         ssize_t numread;
22
23         fd = open(path, O_RDONLY);
24         if (fd == -1)
25                 return 0;
26
27         numread = read(fd, buf, buflen - 1);
28         if (numread < 1) {
29                 close(fd);
30                 return 0;
31         }
32
33         buf[numread] = '\0';
34         close(fd);
35
36         return (unsigned int) numread;
37 }
38
39 static int sysfs_get_enabled(char *path, int *mode)
40 {
41         int fd;
42         char yes_no;
43         int ret = 0;
44
45         *mode = 0;
46
47         fd = open(path, O_RDONLY);
48         if (fd == -1) {
49                 ret = -1;
50                 goto out;
51         }
52
53         if (read(fd, &yes_no, 1) != 1) {
54                 ret = -1;
55                 goto out_close;
56         }
57
58         if (yes_no == '1') {
59                 *mode = 1;
60                 goto out_close;
61         } else if (yes_no == '0') {
62                 goto out_close;
63         } else {
64                 ret = -1;
65                 goto out_close;
66         }
67 out_close:
68         close(fd);
69 out:
70         return ret;
71 }
72
73 int powercap_get_enabled(int *mode)
74 {
75         char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/intel-rapl/enabled";
76
77         return sysfs_get_enabled(path, mode);
78 }
79
80 /*
81  * Hardcoded, because rapl is the only powercap implementation
82 - * this needs to get more generic if more powercap implementations
83  * should show up
84  */
85 int powercap_get_driver(char *driver, int buflen)
86 {
87         char file[SYSFS_PATH_MAX] = PATH_TO_RAPL;
88
89         struct stat statbuf;
90
91         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
92                 driver = "";
93                 return -1;
94         } else if (buflen > 10) {
95                 strcpy(driver, "intel-rapl");
96                 return 0;
97         } else
98                 return -1;
99 }
100
101 enum powercap_get64 {
102         GET_ENERGY_UJ,
103         GET_MAX_ENERGY_RANGE_UJ,
104         GET_POWER_UW,
105         GET_MAX_POWER_RANGE_UW,
106         MAX_GET_64_FILES
107 };
108
109 static const char *powercap_get64_files[MAX_GET_64_FILES] = {
110         [GET_POWER_UW] = "power_uw",
111         [GET_MAX_POWER_RANGE_UW] = "max_power_range_uw",
112         [GET_ENERGY_UJ] = "energy_uj",
113         [GET_MAX_ENERGY_RANGE_UJ] = "max_energy_range_uj",
114 };
115
116 static int sysfs_powercap_get64_val(struct powercap_zone *zone,
117                                       enum powercap_get64 which,
118                                       uint64_t *val)
119 {
120         char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/";
121         int ret;
122         char buf[MAX_LINE_LEN];
123
124         strcat(file, zone->sys_name);
125         strcat(file, "/");
126         strcat(file, powercap_get64_files[which]);
127
128         ret = sysfs_read_file(file, buf, MAX_LINE_LEN);
129         if (ret < 0)
130                 return ret;
131         if (ret == 0)
132                 return -1;
133
134         *val = strtoll(buf, NULL, 10);
135         return 0;
136 }
137
138 int powercap_get_max_energy_range_uj(struct powercap_zone *zone, uint64_t *val)
139 {
140         return sysfs_powercap_get64_val(zone, GET_MAX_ENERGY_RANGE_UJ, val);
141 }
142
143 int powercap_get_energy_uj(struct powercap_zone *zone, uint64_t *val)
144 {
145         return sysfs_powercap_get64_val(zone, GET_ENERGY_UJ, val);
146 }
147
148 int powercap_get_max_power_range_uw(struct powercap_zone *zone, uint64_t *val)
149 {
150         return sysfs_powercap_get64_val(zone, GET_MAX_POWER_RANGE_UW, val);
151 }
152
153 int powercap_get_power_uw(struct powercap_zone *zone, uint64_t *val)
154 {
155         return sysfs_powercap_get64_val(zone, GET_POWER_UW, val);
156 }
157
158 int powercap_zone_get_enabled(struct powercap_zone *zone, int *mode)
159 {
160         char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
161
162         if ((strlen(PATH_TO_POWERCAP) + strlen(zone->sys_name)) +
163             strlen("/enabled") + 1 >= SYSFS_PATH_MAX)
164                 return -1;
165
166         strcat(path, "/");
167         strcat(path, zone->sys_name);
168         strcat(path, "/enabled");
169
170         return sysfs_get_enabled(path, mode);
171 }
172
173 int powercap_zone_set_enabled(struct powercap_zone *zone, int mode)
174 {
175         /* To be done if needed */
176         return 0;
177 }
178
179
180 int powercap_read_zone(struct powercap_zone *zone)
181 {
182         struct dirent *dent;
183         DIR *zone_dir;
184         char sysfs_dir[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
185         struct powercap_zone *child_zone;
186         char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
187         int i, ret = 0;
188         uint64_t val = 0;
189
190         strcat(sysfs_dir, "/");
191         strcat(sysfs_dir, zone->sys_name);
192
193         zone_dir = opendir(sysfs_dir);
194         if (zone_dir == NULL)
195                 return -1;
196
197         strcat(file, "/");
198         strcat(file, zone->sys_name);
199         strcat(file, "/name");
200         sysfs_read_file(file, zone->name, MAX_LINE_LEN);
201         if (zone->parent)
202                 zone->tree_depth = zone->parent->tree_depth + 1;
203         ret = powercap_get_energy_uj(zone, &val);
204         if (ret == 0)
205                 zone->has_energy_uj = 1;
206         ret = powercap_get_power_uw(zone, &val);
207         if (ret == 0)
208                 zone->has_power_uw = 1;
209
210         while ((dent = readdir(zone_dir)) != NULL) {
211                 struct stat st;
212
213                 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
214                         continue;
215
216                 if (stat(dent->d_name, &st) != 0 || !S_ISDIR(st.st_mode))
217                         if (fstatat(dirfd(zone_dir), dent->d_name, &st, 0) < 0)
218                                 continue;
219
220                 if (strncmp(dent->d_name, "intel-rapl:", 11) != 0)
221                         continue;
222
223                 child_zone = calloc(1, sizeof(struct powercap_zone));
224                 if (child_zone == NULL)
225                         return -1;
226                 for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {
227                         if (zone->children[i] == NULL) {
228                                 zone->children[i] = child_zone;
229                                 break;
230                         }
231                         if (i == POWERCAP_MAX_CHILD_ZONES - 1) {
232                                 free(child_zone);
233                                 fprintf(stderr, "Reached POWERCAP_MAX_CHILD_ZONES %d\n",
234                                        POWERCAP_MAX_CHILD_ZONES);
235                                 return -1;
236                         }
237                 }
238                 strcpy(child_zone->sys_name, zone->sys_name);
239                 strcat(child_zone->sys_name, "/");
240                 strcat(child_zone->sys_name, dent->d_name);
241                 child_zone->parent = zone;
242                 if (zone->tree_depth >= POWERCAP_MAX_TREE_DEPTH) {
243                         fprintf(stderr, "Maximum zone hierarchy depth[%d] reached\n",
244                                 POWERCAP_MAX_TREE_DEPTH);
245                         ret = -1;
246                         break;
247                 }
248                 powercap_read_zone(child_zone);
249         }
250         closedir(zone_dir);
251         return ret;
252 }
253
254 struct powercap_zone *powercap_init_zones(void)
255 {
256         int enabled;
257         struct powercap_zone *root_zone;
258         int ret;
259         char file[SYSFS_PATH_MAX] = PATH_TO_RAPL "/enabled";
260
261         ret = sysfs_get_enabled(file, &enabled);
262
263         if (ret)
264                 return NULL;
265
266         if (!enabled)
267                 return NULL;
268
269         root_zone = calloc(1, sizeof(struct powercap_zone));
270         if (!root_zone)
271                 return NULL;
272
273         strcpy(root_zone->sys_name, "intel-rapl/intel-rapl:0");
274
275         powercap_read_zone(root_zone);
276
277         return root_zone;
278 }
279
280 /* Call function *f on the passed zone and all its children */
281
282 int powercap_walk_zones(struct powercap_zone *zone,
283                         int (*f)(struct powercap_zone *zone))
284 {
285         int i, ret;
286
287         if (!zone)
288                 return -1;
289
290         ret = f(zone);
291         if (ret)
292                 return ret;
293
294         for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {
295                 if (zone->children[i] != NULL)
296                         powercap_walk_zones(zone->children[i], f);
297         }
298         return 0;
299 }