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