root/tools/power/cpupower/lib/cpufreq.c

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

DEFINITIONS

This source file includes following definitions.
  1. sysfs_cpufreq_read_file
  2. sysfs_cpufreq_write_file
  3. sysfs_cpufreq_get_one_value
  4. sysfs_cpufreq_get_one_string
  5. sysfs_cpufreq_write_one_value
  6. cpufreq_get_freq_kernel
  7. cpufreq_get_freq_hardware
  8. cpufreq_get_transition_latency
  9. cpufreq_get_hardware_limits
  10. cpufreq_get_driver
  11. cpufreq_put_driver
  12. cpufreq_get_policy
  13. cpufreq_put_policy
  14. cpufreq_get_available_governors
  15. cpufreq_put_available_governors
  16. cpufreq_get_available_frequencies
  17. cpufreq_get_boost_frequencies
  18. cpufreq_put_available_frequencies
  19. cpufreq_put_boost_frequencies
  20. sysfs_get_cpu_list
  21. cpufreq_get_affected_cpus
  22. cpufreq_put_affected_cpus
  23. cpufreq_get_related_cpus
  24. cpufreq_put_related_cpus
  25. verify_gov
  26. cpufreq_set_policy
  27. cpufreq_modify_policy_min
  28. cpufreq_modify_policy_max
  29. cpufreq_modify_policy_governor
  30. cpufreq_set_frequency
  31. cpufreq_get_stats
  32. cpufreq_put_stats
  33. cpufreq_get_transitions

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
   4  */
   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 "cpufreq.h"
  17 #include "cpupower_intern.h"
  18 
  19 /* CPUFREQ sysfs access **************************************************/
  20 
  21 /* helper function to read file from /sys into given buffer */
  22 /* fname is a relative path under "cpuX/cpufreq" dir */
  23 static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname,
  24                                             char *buf, size_t buflen)
  25 {
  26         char path[SYSFS_PATH_MAX];
  27 
  28         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
  29                          cpu, fname);
  30         return cpupower_read_sysfs(path, buf, buflen);
  31 }
  32 
  33 /* helper function to write a new value to a /sys file */
  34 /* fname is a relative path under "cpuX/cpufreq" dir */
  35 static unsigned int sysfs_cpufreq_write_file(unsigned int cpu,
  36                                              const char *fname,
  37                                              const char *value, size_t len)
  38 {
  39         char path[SYSFS_PATH_MAX];
  40         int fd;
  41         ssize_t numwrite;
  42 
  43         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
  44                          cpu, fname);
  45 
  46         fd = open(path, O_WRONLY);
  47         if (fd == -1)
  48                 return 0;
  49 
  50         numwrite = write(fd, value, len);
  51         if (numwrite < 1) {
  52                 close(fd);
  53                 return 0;
  54         }
  55 
  56         close(fd);
  57 
  58         return (unsigned int) numwrite;
  59 }
  60 
  61 /* read access to files which contain one numeric value */
  62 
  63 enum cpufreq_value {
  64         CPUINFO_CUR_FREQ,
  65         CPUINFO_MIN_FREQ,
  66         CPUINFO_MAX_FREQ,
  67         CPUINFO_LATENCY,
  68         SCALING_CUR_FREQ,
  69         SCALING_MIN_FREQ,
  70         SCALING_MAX_FREQ,
  71         STATS_NUM_TRANSITIONS,
  72         MAX_CPUFREQ_VALUE_READ_FILES
  73 };
  74 
  75 static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
  76         [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq",
  77         [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq",
  78         [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq",
  79         [CPUINFO_LATENCY]  = "cpuinfo_transition_latency",
  80         [SCALING_CUR_FREQ] = "scaling_cur_freq",
  81         [SCALING_MIN_FREQ] = "scaling_min_freq",
  82         [SCALING_MAX_FREQ] = "scaling_max_freq",
  83         [STATS_NUM_TRANSITIONS] = "stats/total_trans"
  84 };
  85 
  86 
  87 static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
  88                                                  enum cpufreq_value which)
  89 {
  90         unsigned long value;
  91         unsigned int len;
  92         char linebuf[MAX_LINE_LEN];
  93         char *endp;
  94 
  95         if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
  96                 return 0;
  97 
  98         len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
  99                                 linebuf, sizeof(linebuf));
 100 
 101         if (len == 0)
 102                 return 0;
 103 
 104         value = strtoul(linebuf, &endp, 0);
 105 
 106         if (endp == linebuf || errno == ERANGE)
 107                 return 0;
 108 
 109         return value;
 110 }
 111 
 112 /* read access to files which contain one string */
 113 
 114 enum cpufreq_string {
 115         SCALING_DRIVER,
 116         SCALING_GOVERNOR,
 117         MAX_CPUFREQ_STRING_FILES
 118 };
 119 
 120 static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
 121         [SCALING_DRIVER] = "scaling_driver",
 122         [SCALING_GOVERNOR] = "scaling_governor",
 123 };
 124 
 125 
 126 static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
 127                                            enum cpufreq_string which)
 128 {
 129         char linebuf[MAX_LINE_LEN];
 130         char *result;
 131         unsigned int len;
 132 
 133         if (which >= MAX_CPUFREQ_STRING_FILES)
 134                 return NULL;
 135 
 136         len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which],
 137                                 linebuf, sizeof(linebuf));
 138         if (len == 0)
 139                 return NULL;
 140 
 141         result = strdup(linebuf);
 142         if (result == NULL)
 143                 return NULL;
 144 
 145         if (result[strlen(result) - 1] == '\n')
 146                 result[strlen(result) - 1] = '\0';
 147 
 148         return result;
 149 }
 150 
 151 /* write access */
 152 
 153 enum cpufreq_write {
 154         WRITE_SCALING_MIN_FREQ,
 155         WRITE_SCALING_MAX_FREQ,
 156         WRITE_SCALING_GOVERNOR,
 157         WRITE_SCALING_SET_SPEED,
 158         MAX_CPUFREQ_WRITE_FILES
 159 };
 160 
 161 static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = {
 162         [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq",
 163         [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq",
 164         [WRITE_SCALING_GOVERNOR] = "scaling_governor",
 165         [WRITE_SCALING_SET_SPEED] = "scaling_setspeed",
 166 };
 167 
 168 static int sysfs_cpufreq_write_one_value(unsigned int cpu,
 169                                          enum cpufreq_write which,
 170                                          const char *new_value, size_t len)
 171 {
 172         if (which >= MAX_CPUFREQ_WRITE_FILES)
 173                 return 0;
 174 
 175         if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which],
 176                                         new_value, len) != len)
 177                 return -ENODEV;
 178 
 179         return 0;
 180 };
 181 
 182 unsigned long cpufreq_get_freq_kernel(unsigned int cpu)
 183 {
 184         return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ);
 185 }
 186 
 187 unsigned long cpufreq_get_freq_hardware(unsigned int cpu)
 188 {
 189         return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ);
 190 }
 191 
 192 unsigned long cpufreq_get_transition_latency(unsigned int cpu)
 193 {
 194         return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
 195 }
 196 
 197 int cpufreq_get_hardware_limits(unsigned int cpu,
 198                                 unsigned long *min,
 199                                 unsigned long *max)
 200 {
 201         if ((!min) || (!max))
 202                 return -EINVAL;
 203 
 204         *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ);
 205         if (!*min)
 206                 return -ENODEV;
 207 
 208         *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ);
 209         if (!*max)
 210                 return -ENODEV;
 211 
 212         return 0;
 213 }
 214 
 215 char *cpufreq_get_driver(unsigned int cpu)
 216 {
 217         return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER);
 218 }
 219 
 220 void cpufreq_put_driver(char *ptr)
 221 {
 222         if (!ptr)
 223                 return;
 224         free(ptr);
 225 }
 226 
 227 struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu)
 228 {
 229         struct cpufreq_policy *policy;
 230 
 231         policy = malloc(sizeof(struct cpufreq_policy));
 232         if (!policy)
 233                 return NULL;
 234 
 235         policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR);
 236         if (!policy->governor) {
 237                 free(policy);
 238                 return NULL;
 239         }
 240         policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
 241         policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ);
 242         if ((!policy->min) || (!policy->max)) {
 243                 free(policy->governor);
 244                 free(policy);
 245                 return NULL;
 246         }
 247 
 248         return policy;
 249 }
 250 
 251 void cpufreq_put_policy(struct cpufreq_policy *policy)
 252 {
 253         if ((!policy) || (!policy->governor))
 254                 return;
 255 
 256         free(policy->governor);
 257         policy->governor = NULL;
 258         free(policy);
 259 }
 260 
 261 struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned
 262                                                                 int cpu)
 263 {
 264         struct cpufreq_available_governors *first = NULL;
 265         struct cpufreq_available_governors *current = NULL;
 266         char linebuf[MAX_LINE_LEN];
 267         unsigned int pos, i;
 268         unsigned int len;
 269 
 270         len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors",
 271                                 linebuf, sizeof(linebuf));
 272         if (len == 0)
 273                 return NULL;
 274 
 275         pos = 0;
 276         for (i = 0; i < len; i++) {
 277                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
 278                         if (i - pos < 2)
 279                                 continue;
 280                         if (current) {
 281                                 current->next = malloc(sizeof(*current));
 282                                 if (!current->next)
 283                                         goto error_out;
 284                                 current = current->next;
 285                         } else {
 286                                 first = malloc(sizeof(*first));
 287                                 if (!first)
 288                                         goto error_out;
 289                                 current = first;
 290                         }
 291                         current->first = first;
 292                         current->next = NULL;
 293 
 294                         current->governor = malloc(i - pos + 1);
 295                         if (!current->governor)
 296                                 goto error_out;
 297 
 298                         memcpy(current->governor, linebuf + pos, i - pos);
 299                         current->governor[i - pos] = '\0';
 300                         pos = i + 1;
 301                 }
 302         }
 303 
 304         return first;
 305 
 306  error_out:
 307         while (first) {
 308                 current = first->next;
 309                 if (first->governor)
 310                         free(first->governor);
 311                 free(first);
 312                 first = current;
 313         }
 314         return NULL;
 315 }
 316 
 317 void cpufreq_put_available_governors(struct cpufreq_available_governors *any)
 318 {
 319         struct cpufreq_available_governors *tmp, *next;
 320 
 321         if (!any)
 322                 return;
 323 
 324         tmp = any->first;
 325         while (tmp) {
 326                 next = tmp->next;
 327                 if (tmp->governor)
 328                         free(tmp->governor);
 329                 free(tmp);
 330                 tmp = next;
 331         }
 332 }
 333 
 334 
 335 struct cpufreq_available_frequencies
 336 *cpufreq_get_available_frequencies(unsigned int cpu)
 337 {
 338         struct cpufreq_available_frequencies *first = NULL;
 339         struct cpufreq_available_frequencies *current = NULL;
 340         char one_value[SYSFS_PATH_MAX];
 341         char linebuf[MAX_LINE_LEN];
 342         unsigned int pos, i;
 343         unsigned int len;
 344 
 345         len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
 346                                       linebuf, sizeof(linebuf));
 347         if (len == 0)
 348                 return NULL;
 349 
 350         pos = 0;
 351         for (i = 0; i < len; i++) {
 352                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
 353                         if (i - pos < 2)
 354                                 continue;
 355                         if (i - pos >= SYSFS_PATH_MAX)
 356                                 goto error_out;
 357                         if (current) {
 358                                 current->next = malloc(sizeof(*current));
 359                                 if (!current->next)
 360                                         goto error_out;
 361                                 current = current->next;
 362                         } else {
 363                                 first = malloc(sizeof(*first));
 364                                 if (!first)
 365                                         goto error_out;
 366                                 current = first;
 367                         }
 368                         current->first = first;
 369                         current->next = NULL;
 370 
 371                         memcpy(one_value, linebuf + pos, i - pos);
 372                         one_value[i - pos] = '\0';
 373                         if (sscanf(one_value, "%lu", &current->frequency) != 1)
 374                                 goto error_out;
 375 
 376                         pos = i + 1;
 377                 }
 378         }
 379 
 380         return first;
 381 
 382  error_out:
 383         while (first) {
 384                 current = first->next;
 385                 free(first);
 386                 first = current;
 387         }
 388         return NULL;
 389 }
 390 
 391 struct cpufreq_available_frequencies
 392 *cpufreq_get_boost_frequencies(unsigned int cpu)
 393 {
 394         struct cpufreq_available_frequencies *first = NULL;
 395         struct cpufreq_available_frequencies *current = NULL;
 396         char one_value[SYSFS_PATH_MAX];
 397         char linebuf[MAX_LINE_LEN];
 398         unsigned int pos, i;
 399         unsigned int len;
 400 
 401         len = sysfs_cpufreq_read_file(cpu, "scaling_boost_frequencies",
 402                                       linebuf, sizeof(linebuf));
 403         if (len == 0)
 404                 return NULL;
 405 
 406         pos = 0;
 407         for (i = 0; i < len; i++) {
 408                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
 409                         if (i - pos < 2)
 410                                 continue;
 411                         if (i - pos >= SYSFS_PATH_MAX)
 412                                 goto error_out;
 413                         if (current) {
 414                                 current->next = malloc(sizeof(*current));
 415                                 if (!current->next)
 416                                         goto error_out;
 417                                 current = current->next;
 418                         } else {
 419                                 first = malloc(sizeof(*first));
 420                                 if (!first)
 421                                         goto error_out;
 422                                 current = first;
 423                         }
 424                         current->first = first;
 425                         current->next = NULL;
 426 
 427                         memcpy(one_value, linebuf + pos, i - pos);
 428                         one_value[i - pos] = '\0';
 429                         if (sscanf(one_value, "%lu", &current->frequency) != 1)
 430                                 goto error_out;
 431 
 432                         pos = i + 1;
 433                 }
 434         }
 435 
 436         return first;
 437 
 438  error_out:
 439         while (first) {
 440                 current = first->next;
 441                 free(first);
 442                 first = current;
 443         }
 444         return NULL;
 445 }
 446 
 447 void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies *any)
 448 {
 449         struct cpufreq_available_frequencies *tmp, *next;
 450 
 451         if (!any)
 452                 return;
 453 
 454         tmp = any->first;
 455         while (tmp) {
 456                 next = tmp->next;
 457                 free(tmp);
 458                 tmp = next;
 459         }
 460 }
 461 
 462 void cpufreq_put_boost_frequencies(struct cpufreq_available_frequencies *any)
 463 {
 464         cpufreq_put_available_frequencies(any);
 465 }
 466 
 467 static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
 468                                                         const char *file)
 469 {
 470         struct cpufreq_affected_cpus *first = NULL;
 471         struct cpufreq_affected_cpus *current = NULL;
 472         char one_value[SYSFS_PATH_MAX];
 473         char linebuf[MAX_LINE_LEN];
 474         unsigned int pos, i;
 475         unsigned int len;
 476 
 477         len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf));
 478         if (len == 0)
 479                 return NULL;
 480 
 481         pos = 0;
 482         for (i = 0; i < len; i++) {
 483                 if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') {
 484                         if (i - pos  < 1)
 485                                 continue;
 486                         if (i - pos >= SYSFS_PATH_MAX)
 487                                 goto error_out;
 488                         if (current) {
 489                                 current->next = malloc(sizeof(*current));
 490                                 if (!current->next)
 491                                         goto error_out;
 492                                 current = current->next;
 493                         } else {
 494                                 first = malloc(sizeof(*first));
 495                                 if (!first)
 496                                         goto error_out;
 497                                 current = first;
 498                         }
 499                         current->first = first;
 500                         current->next = NULL;
 501 
 502                         memcpy(one_value, linebuf + pos, i - pos);
 503                         one_value[i - pos] = '\0';
 504 
 505                         if (sscanf(one_value, "%u", &current->cpu) != 1)
 506                                 goto error_out;
 507 
 508                         pos = i + 1;
 509                 }
 510         }
 511 
 512         return first;
 513 
 514  error_out:
 515         while (first) {
 516                 current = first->next;
 517                 free(first);
 518                 first = current;
 519         }
 520         return NULL;
 521 }
 522 
 523 struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu)
 524 {
 525         return sysfs_get_cpu_list(cpu, "affected_cpus");
 526 }
 527 
 528 void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any)
 529 {
 530         struct cpufreq_affected_cpus *tmp, *next;
 531 
 532         if (!any)
 533                 return;
 534 
 535         tmp = any->first;
 536         while (tmp) {
 537                 next = tmp->next;
 538                 free(tmp);
 539                 tmp = next;
 540         }
 541 }
 542 
 543 
 544 struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu)
 545 {
 546         return sysfs_get_cpu_list(cpu, "related_cpus");
 547 }
 548 
 549 void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any)
 550 {
 551         cpufreq_put_affected_cpus(any);
 552 }
 553 
 554 static int verify_gov(char *new_gov, char *passed_gov)
 555 {
 556         unsigned int i, j = 0;
 557 
 558         if (!passed_gov || (strlen(passed_gov) > 19))
 559                 return -EINVAL;
 560 
 561         strncpy(new_gov, passed_gov, 20);
 562         for (i = 0; i < 20; i++) {
 563                 if (j) {
 564                         new_gov[i] = '\0';
 565                         continue;
 566                 }
 567                 if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z'))
 568                         continue;
 569 
 570                 if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z'))
 571                         continue;
 572 
 573                 if (new_gov[i] == '-')
 574                         continue;
 575 
 576                 if (new_gov[i] == '_')
 577                         continue;
 578 
 579                 if (new_gov[i] == '\0') {
 580                         j = 1;
 581                         continue;
 582                 }
 583                 return -EINVAL;
 584         }
 585         new_gov[19] = '\0';
 586         return 0;
 587 }
 588 
 589 int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy)
 590 {
 591         char min[SYSFS_PATH_MAX];
 592         char max[SYSFS_PATH_MAX];
 593         char gov[SYSFS_PATH_MAX];
 594         int ret;
 595         unsigned long old_min;
 596         int write_max_first;
 597 
 598         if (!policy || !(policy->governor))
 599                 return -EINVAL;
 600 
 601         if (policy->max < policy->min)
 602                 return -EINVAL;
 603 
 604         if (verify_gov(gov, policy->governor))
 605                 return -EINVAL;
 606 
 607         snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min);
 608         snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max);
 609 
 610         old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
 611         write_max_first = (old_min && (policy->max < old_min) ? 0 : 1);
 612 
 613         if (write_max_first) {
 614                 ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
 615                                                     max, strlen(max));
 616                 if (ret)
 617                         return ret;
 618         }
 619 
 620         ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min,
 621                                             strlen(min));
 622         if (ret)
 623                 return ret;
 624 
 625         if (!write_max_first) {
 626                 ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
 627                                                     max, strlen(max));
 628                 if (ret)
 629                         return ret;
 630         }
 631 
 632         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
 633                                              gov, strlen(gov));
 634 }
 635 
 636 
 637 int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq)
 638 {
 639         char value[SYSFS_PATH_MAX];
 640 
 641         snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq);
 642 
 643         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ,
 644                                              value, strlen(value));
 645 }
 646 
 647 
 648 int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq)
 649 {
 650         char value[SYSFS_PATH_MAX];
 651 
 652         snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq);
 653 
 654         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
 655                                              value, strlen(value));
 656 }
 657 
 658 int cpufreq_modify_policy_governor(unsigned int cpu, char *governor)
 659 {
 660         char new_gov[SYSFS_PATH_MAX];
 661 
 662         if ((!governor) || (strlen(governor) > 19))
 663                 return -EINVAL;
 664 
 665         if (verify_gov(new_gov, governor))
 666                 return -EINVAL;
 667 
 668         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
 669                                              new_gov, strlen(new_gov));
 670 }
 671 
 672 int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency)
 673 {
 674         struct cpufreq_policy *pol = cpufreq_get_policy(cpu);
 675         char userspace_gov[] = "userspace";
 676         char freq[SYSFS_PATH_MAX];
 677         int ret;
 678 
 679         if (!pol)
 680                 return -ENODEV;
 681 
 682         if (strncmp(pol->governor, userspace_gov, 9) != 0) {
 683                 ret = cpufreq_modify_policy_governor(cpu, userspace_gov);
 684                 if (ret) {
 685                         cpufreq_put_policy(pol);
 686                         return ret;
 687                 }
 688         }
 689 
 690         cpufreq_put_policy(pol);
 691 
 692         snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency);
 693 
 694         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED,
 695                                              freq, strlen(freq));
 696 }
 697 
 698 struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
 699                                         unsigned long long *total_time)
 700 {
 701         struct cpufreq_stats *first = NULL;
 702         struct cpufreq_stats *current = NULL;
 703         char one_value[SYSFS_PATH_MAX];
 704         char linebuf[MAX_LINE_LEN];
 705         unsigned int pos, i;
 706         unsigned int len;
 707 
 708         len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state",
 709                                 linebuf, sizeof(linebuf));
 710         if (len == 0)
 711                 return NULL;
 712 
 713         *total_time = 0;
 714         pos = 0;
 715         for (i = 0; i < len; i++) {
 716                 if (i == strlen(linebuf) || linebuf[i] == '\n') {
 717                         if (i - pos < 2)
 718                                 continue;
 719                         if ((i - pos) >= SYSFS_PATH_MAX)
 720                                 goto error_out;
 721                         if (current) {
 722                                 current->next = malloc(sizeof(*current));
 723                                 if (!current->next)
 724                                         goto error_out;
 725                                 current = current->next;
 726                         } else {
 727                                 first = malloc(sizeof(*first));
 728                                 if (!first)
 729                                         goto error_out;
 730                                 current = first;
 731                         }
 732                         current->first = first;
 733                         current->next = NULL;
 734 
 735                         memcpy(one_value, linebuf + pos, i - pos);
 736                         one_value[i - pos] = '\0';
 737                         if (sscanf(one_value, "%lu %llu",
 738                                         &current->frequency,
 739                                         &current->time_in_state) != 2)
 740                                 goto error_out;
 741 
 742                         *total_time = *total_time + current->time_in_state;
 743                         pos = i + 1;
 744                 }
 745         }
 746 
 747         return first;
 748 
 749  error_out:
 750         while (first) {
 751                 current = first->next;
 752                 free(first);
 753                 first = current;
 754         }
 755         return NULL;
 756 }
 757 
 758 void cpufreq_put_stats(struct cpufreq_stats *any)
 759 {
 760         struct cpufreq_stats *tmp, *next;
 761 
 762         if (!any)
 763                 return;
 764 
 765         tmp = any->first;
 766         while (tmp) {
 767                 next = tmp->next;
 768                 free(tmp);
 769                 tmp = next;
 770         }
 771 }
 772 
 773 unsigned long cpufreq_get_transitions(unsigned int cpu)
 774 {
 775         return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS);
 776 }

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