root/tools/power/cpupower/utils/helpers/sysfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sysfs_read_file
  2. sysfs_is_cpu_online
  3. sysfs_idlestate_file_exists
  4. sysfs_idlestate_read_file
  5. sysfs_idlestate_write_file
  6. sysfs_idlestate_get_one_value
  7. sysfs_idlestate_get_one_string
  8. sysfs_is_idlestate_disabled
  9. sysfs_idlestate_disable
  10. sysfs_get_idlestate_latency
  11. sysfs_get_idlestate_usage
  12. sysfs_get_idlestate_time
  13. sysfs_get_idlestate_name
  14. sysfs_get_idlestate_desc
  15. sysfs_get_idlestate_count
  16. sysfs_cpuidle_read_file
  17. sysfs_cpuidle_get_one_string
  18. sysfs_get_cpuidle_governor
  19. sysfs_get_cpuidle_driver
  20. sysfs_get_sched
  21. sysfs_set_sched

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
   4  *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
   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 "helpers/sysfs.h"
  17 
  18 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 /*
  40  * Detect whether a CPU is online
  41  *
  42  * Returns:
  43  *     1 -> if CPU is online
  44  *     0 -> if CPU is offline
  45  *     negative errno values in error case
  46  */
  47 int sysfs_is_cpu_online(unsigned int cpu)
  48 {
  49         char path[SYSFS_PATH_MAX];
  50         int fd;
  51         ssize_t numread;
  52         unsigned long long value;
  53         char linebuf[MAX_LINE_LEN];
  54         char *endp;
  55         struct stat statbuf;
  56 
  57         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
  58 
  59         if (stat(path, &statbuf) != 0)
  60                 return 0;
  61 
  62         /*
  63          * kernel without CONFIG_HOTPLUG_CPU
  64          * -> cpuX directory exists, but not cpuX/online file
  65          */
  66         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
  67         if (stat(path, &statbuf) != 0)
  68                 return 1;
  69 
  70         fd = open(path, O_RDONLY);
  71         if (fd == -1)
  72                 return -errno;
  73 
  74         numread = read(fd, linebuf, MAX_LINE_LEN - 1);
  75         if (numread < 1) {
  76                 close(fd);
  77                 return -EIO;
  78         }
  79         linebuf[numread] = '\0';
  80         close(fd);
  81 
  82         value = strtoull(linebuf, &endp, 0);
  83         if (value > 1)
  84                 return -EINVAL;
  85 
  86         return value;
  87 }
  88 
  89 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
  90 
  91 
  92 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
  93 
  94 /*
  95  * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
  96  * exists.
  97  * For example the functionality to disable c-states was introduced in later
  98  * kernel versions, this function can be used to explicitly check for this
  99  * feature.
 100  *
 101  * returns 1 if the file exists, 0 otherwise.
 102  */
 103 unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
 104                                          unsigned int idlestate,
 105                                          const char *fname)
 106 {
 107         char path[SYSFS_PATH_MAX];
 108         struct stat statbuf;
 109 
 110 
 111         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
 112                  cpu, idlestate, fname);
 113         if (stat(path, &statbuf) != 0)
 114                 return 0;
 115         return 1;
 116 }
 117 
 118 /*
 119  * helper function to read file from /sys into given buffer
 120  * fname is a relative path under "cpuX/cpuidle/stateX/" dir
 121  * cstates starting with 0, C0 is not counted as cstate.
 122  * This means if you want C1 info, pass 0 as idlestate param
 123  */
 124 unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
 125                              const char *fname, char *buf, size_t buflen)
 126 {
 127         char path[SYSFS_PATH_MAX];
 128         int fd;
 129         ssize_t numread;
 130 
 131         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
 132                  cpu, idlestate, fname);
 133 
 134         fd = open(path, O_RDONLY);
 135         if (fd == -1)
 136                 return 0;
 137 
 138         numread = read(fd, buf, buflen - 1);
 139         if (numread < 1) {
 140                 close(fd);
 141                 return 0;
 142         }
 143 
 144         buf[numread] = '\0';
 145         close(fd);
 146 
 147         return (unsigned int) numread;
 148 }
 149 
 150 /* 
 151  * helper function to write a new value to a /sys file
 152  * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
 153  *
 154  * Returns the number of bytes written or 0 on error
 155  */
 156 static
 157 unsigned int sysfs_idlestate_write_file(unsigned int cpu,
 158                                         unsigned int idlestate,
 159                                         const char *fname,
 160                                         const char *value, size_t len)
 161 {
 162         char path[SYSFS_PATH_MAX];
 163         int fd;
 164         ssize_t numwrite;
 165 
 166         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
 167                  cpu, idlestate, fname);
 168 
 169         fd = open(path, O_WRONLY);
 170         if (fd == -1)
 171                 return 0;
 172 
 173         numwrite = write(fd, value, len);
 174         if (numwrite < 1) {
 175                 close(fd);
 176                 return 0;
 177         }
 178 
 179         close(fd);
 180 
 181         return (unsigned int) numwrite;
 182 }
 183 
 184 /* read access to files which contain one numeric value */
 185 
 186 enum idlestate_value {
 187         IDLESTATE_USAGE,
 188         IDLESTATE_POWER,
 189         IDLESTATE_LATENCY,
 190         IDLESTATE_TIME,
 191         IDLESTATE_DISABLE,
 192         MAX_IDLESTATE_VALUE_FILES
 193 };
 194 
 195 static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
 196         [IDLESTATE_USAGE] = "usage",
 197         [IDLESTATE_POWER] = "power",
 198         [IDLESTATE_LATENCY] = "latency",
 199         [IDLESTATE_TIME]  = "time",
 200         [IDLESTATE_DISABLE]  = "disable",
 201 };
 202 
 203 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
 204                                                      unsigned int idlestate,
 205                                                      enum idlestate_value which)
 206 {
 207         unsigned long long value;
 208         unsigned int len;
 209         char linebuf[MAX_LINE_LEN];
 210         char *endp;
 211 
 212         if (which >= MAX_IDLESTATE_VALUE_FILES)
 213                 return 0;
 214 
 215         len = sysfs_idlestate_read_file(cpu, idlestate,
 216                                         idlestate_value_files[which],
 217                                         linebuf, sizeof(linebuf));
 218         if (len == 0)
 219                 return 0;
 220 
 221         value = strtoull(linebuf, &endp, 0);
 222 
 223         if (endp == linebuf || errno == ERANGE)
 224                 return 0;
 225 
 226         return value;
 227 }
 228 
 229 /* read access to files which contain one string */
 230 
 231 enum idlestate_string {
 232         IDLESTATE_DESC,
 233         IDLESTATE_NAME,
 234         MAX_IDLESTATE_STRING_FILES
 235 };
 236 
 237 static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
 238         [IDLESTATE_DESC] = "desc",
 239         [IDLESTATE_NAME] = "name",
 240 };
 241 
 242 
 243 static char *sysfs_idlestate_get_one_string(unsigned int cpu,
 244                                         unsigned int idlestate,
 245                                         enum idlestate_string which)
 246 {
 247         char linebuf[MAX_LINE_LEN];
 248         char *result;
 249         unsigned int len;
 250 
 251         if (which >= MAX_IDLESTATE_STRING_FILES)
 252                 return NULL;
 253 
 254         len = sysfs_idlestate_read_file(cpu, idlestate,
 255                                         idlestate_string_files[which],
 256                                         linebuf, sizeof(linebuf));
 257         if (len == 0)
 258                 return NULL;
 259 
 260         result = strdup(linebuf);
 261         if (result == NULL)
 262                 return NULL;
 263 
 264         if (result[strlen(result) - 1] == '\n')
 265                 result[strlen(result) - 1] = '\0';
 266 
 267         return result;
 268 }
 269 
 270 /*
 271  * Returns:
 272  *    1  if disabled
 273  *    0  if enabled
 274  *    -1 if idlestate is not available
 275  *    -2 if disabling is not supported by the kernel
 276  */
 277 int sysfs_is_idlestate_disabled(unsigned int cpu,
 278                                 unsigned int idlestate)
 279 {
 280         if (sysfs_get_idlestate_count(cpu) <= idlestate)
 281                 return -1;
 282 
 283         if (!sysfs_idlestate_file_exists(cpu, idlestate,
 284                                  idlestate_value_files[IDLESTATE_DISABLE]))
 285                 return -2;
 286         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
 287 }
 288 
 289 /*
 290  * Pass 1 as last argument to disable or 0 to enable the state
 291  * Returns:
 292  *    0  on success
 293  *    negative values on error, for example:
 294  *      -1 if idlestate is not available
 295  *      -2 if disabling is not supported by the kernel
 296  *      -3 No write access to disable/enable C-states
 297  */
 298 int sysfs_idlestate_disable(unsigned int cpu,
 299                             unsigned int idlestate,
 300                             unsigned int disable)
 301 {
 302         char value[SYSFS_PATH_MAX];
 303         int bytes_written;
 304 
 305         if (sysfs_get_idlestate_count(cpu) <= idlestate)
 306                 return -1;
 307 
 308         if (!sysfs_idlestate_file_exists(cpu, idlestate,
 309                                  idlestate_value_files[IDLESTATE_DISABLE]))
 310                 return -2;
 311 
 312         snprintf(value, SYSFS_PATH_MAX, "%u", disable);
 313 
 314         bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
 315                                                    value, sizeof(disable));
 316         if (bytes_written)
 317                 return 0;
 318         return -3;
 319 }
 320 
 321 unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
 322                                           unsigned int idlestate)
 323 {
 324         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
 325 }
 326 
 327 unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
 328                                         unsigned int idlestate)
 329 {
 330         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
 331 }
 332 
 333 unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
 334                                         unsigned int idlestate)
 335 {
 336         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
 337 }
 338 
 339 char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
 340 {
 341         return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
 342 }
 343 
 344 char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
 345 {
 346         return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
 347 }
 348 
 349 /*
 350  * Returns number of supported C-states of CPU core cpu
 351  * Negativ in error case
 352  * Zero if cpuidle does not export any C-states
 353  */
 354 unsigned int sysfs_get_idlestate_count(unsigned int cpu)
 355 {
 356         char file[SYSFS_PATH_MAX];
 357         struct stat statbuf;
 358         int idlestates = 1;
 359 
 360 
 361         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
 362         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
 363                 return 0;
 364 
 365         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
 366         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
 367                 return 0;
 368 
 369         while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
 370                 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
 371                          "cpu%u/cpuidle/state%d", cpu, idlestates);
 372                 idlestates++;
 373         }
 374         idlestates--;
 375         return idlestates;
 376 }
 377 
 378 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
 379 
 380 /*
 381  * helper function to read file from /sys into given buffer
 382  * fname is a relative path under "cpu/cpuidle/" dir
 383  */
 384 static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
 385                                             size_t buflen)
 386 {
 387         char path[SYSFS_PATH_MAX];
 388 
 389         snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
 390 
 391         return sysfs_read_file(path, buf, buflen);
 392 }
 393 
 394 
 395 
 396 /* read access to files which contain one string */
 397 
 398 enum cpuidle_string {
 399         CPUIDLE_GOVERNOR,
 400         CPUIDLE_GOVERNOR_RO,
 401         CPUIDLE_DRIVER,
 402         MAX_CPUIDLE_STRING_FILES
 403 };
 404 
 405 static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
 406         [CPUIDLE_GOVERNOR]      = "current_governor",
 407         [CPUIDLE_GOVERNOR_RO]   = "current_governor_ro",
 408         [CPUIDLE_DRIVER]        = "current_driver",
 409 };
 410 
 411 
 412 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
 413 {
 414         char linebuf[MAX_LINE_LEN];
 415         char *result;
 416         unsigned int len;
 417 
 418         if (which >= MAX_CPUIDLE_STRING_FILES)
 419                 return NULL;
 420 
 421         len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
 422                                 linebuf, sizeof(linebuf));
 423         if (len == 0)
 424                 return NULL;
 425 
 426         result = strdup(linebuf);
 427         if (result == NULL)
 428                 return NULL;
 429 
 430         if (result[strlen(result) - 1] == '\n')
 431                 result[strlen(result) - 1] = '\0';
 432 
 433         return result;
 434 }
 435 
 436 char *sysfs_get_cpuidle_governor(void)
 437 {
 438         char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
 439         if (!tmp)
 440                 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
 441         else
 442                 return tmp;
 443 }
 444 
 445 char *sysfs_get_cpuidle_driver(void)
 446 {
 447         return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
 448 }
 449 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
 450 
 451 /*
 452  * Get sched_mc or sched_smt settings
 453  * Pass "mc" or "smt" as argument
 454  *
 455  * Returns negative value on failure
 456  */
 457 int sysfs_get_sched(const char *smt_mc)
 458 {
 459         return -ENODEV;
 460 }
 461 
 462 /*
 463  * Get sched_mc or sched_smt settings
 464  * Pass "mc" or "smt" as argument
 465  *
 466  * Returns negative value on failure
 467  */
 468 int sysfs_set_sched(const char *smt_mc, int val)
 469 {
 470         return -ENODEV;
 471 }

/* [<][>][^][v][top][bottom][index][help] */