1 // SPDX-License-Identifier: GPL-2.0-only
3 * (C) 2016 SUSE Software Solutions GmbH
4 * Thomas Renninger <trenn@suse.de>
18 static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
23 fd = open(path, O_RDONLY);
27 numread = read(fd, buf, buflen - 1);
36 return (unsigned int) numread;
39 static int sysfs_get_enabled(char *path, int *mode)
47 fd = open(path, O_RDONLY);
53 if (read(fd, &yes_no, 1) != 1) {
61 } else if (yes_no == '0') {
73 int powercap_get_enabled(int *mode)
75 char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/intel-rapl/enabled";
77 return sysfs_get_enabled(path, mode);
81 * Hardcoded, because rapl is the only powercap implementation
82 - * this needs to get more generic if more powercap implementations
85 int powercap_get_driver(char *driver, int buflen)
87 char file[SYSFS_PATH_MAX] = PATH_TO_RAPL;
91 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
94 } else if (buflen > 10) {
95 strcpy(driver, "intel-rapl");
101 enum powercap_get64 {
103 GET_MAX_ENERGY_RANGE_UJ,
105 GET_MAX_POWER_RANGE_UW,
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",
116 static int sysfs_powercap_get64_val(struct powercap_zone *zone,
117 enum powercap_get64 which,
120 char file[SYSFS_PATH_MAX] = PATH_TO_POWERCAP "/";
122 char buf[MAX_LINE_LEN];
124 strcat(file, zone->sys_name);
126 strcat(file, powercap_get64_files[which]);
128 ret = sysfs_read_file(file, buf, MAX_LINE_LEN);
134 *val = strtoll(buf, NULL, 10);
138 int powercap_get_max_energy_range_uj(struct powercap_zone *zone, uint64_t *val)
140 return sysfs_powercap_get64_val(zone, GET_MAX_ENERGY_RANGE_UJ, val);
143 int powercap_get_energy_uj(struct powercap_zone *zone, uint64_t *val)
145 return sysfs_powercap_get64_val(zone, GET_ENERGY_UJ, val);
148 int powercap_get_max_power_range_uw(struct powercap_zone *zone, uint64_t *val)
150 return sysfs_powercap_get64_val(zone, GET_MAX_POWER_RANGE_UW, val);
153 int powercap_get_power_uw(struct powercap_zone *zone, uint64_t *val)
155 return sysfs_powercap_get64_val(zone, GET_POWER_UW, val);
158 int powercap_zone_get_enabled(struct powercap_zone *zone, int *mode)
160 char path[SYSFS_PATH_MAX] = PATH_TO_POWERCAP;
162 if ((strlen(PATH_TO_POWERCAP) + strlen(zone->sys_name)) +
163 strlen("/enabled") + 1 >= SYSFS_PATH_MAX)
167 strcat(path, zone->sys_name);
168 strcat(path, "/enabled");
170 return sysfs_get_enabled(path, mode);
173 int powercap_zone_set_enabled(struct powercap_zone *zone, int mode)
175 /* To be done if needed */
180 int powercap_read_zone(struct powercap_zone *zone)
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;
190 strcat(sysfs_dir, "/");
191 strcat(sysfs_dir, zone->sys_name);
193 zone_dir = opendir(sysfs_dir);
194 if (zone_dir == NULL)
198 strcat(file, zone->sys_name);
199 strcat(file, "/name");
200 sysfs_read_file(file, zone->name, MAX_LINE_LEN);
202 zone->tree_depth = zone->parent->tree_depth + 1;
203 ret = powercap_get_energy_uj(zone, &val);
205 zone->has_energy_uj = 1;
206 ret = powercap_get_power_uw(zone, &val);
208 zone->has_power_uw = 1;
210 while ((dent = readdir(zone_dir)) != NULL) {
213 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
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)
220 if (strncmp(dent->d_name, "intel-rapl:", 11) != 0)
223 child_zone = calloc(1, sizeof(struct powercap_zone));
224 if (child_zone == NULL)
226 for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {
227 if (zone->children[i] == NULL) {
228 zone->children[i] = child_zone;
231 if (i == POWERCAP_MAX_CHILD_ZONES - 1) {
233 fprintf(stderr, "Reached POWERCAP_MAX_CHILD_ZONES %d\n",
234 POWERCAP_MAX_CHILD_ZONES);
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);
248 powercap_read_zone(child_zone);
254 struct powercap_zone *powercap_init_zones(void)
257 struct powercap_zone *root_zone;
259 char file[SYSFS_PATH_MAX] = PATH_TO_RAPL "/enabled";
261 ret = sysfs_get_enabled(file, &enabled);
269 root_zone = calloc(1, sizeof(struct powercap_zone));
273 strcpy(root_zone->sys_name, "intel-rapl/intel-rapl:0");
275 powercap_read_zone(root_zone);
280 /* Call function *f on the passed zone and all its children */
282 int powercap_walk_zones(struct powercap_zone *zone,
283 int (*f)(struct powercap_zone *zone))
294 for (i = 0; i < POWERCAP_MAX_CHILD_ZONES; i++) {
295 if (zone->children[i] != NULL)
296 powercap_walk_zones(zone->children[i], f);