18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> 48c2ecf20Sopenharmony_ci * (C) 2010 Thomas Renninger <trenn@suse.de> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <unistd.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <stdlib.h> 128c2ecf20Sopenharmony_ci#include <string.h> 138c2ecf20Sopenharmony_ci#include <getopt.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <cpuidle.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "helpers/sysfs.h" 188c2ecf20Sopenharmony_ci#include "helpers/helpers.h" 198c2ecf20Sopenharmony_ci#include "helpers/bitmask.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define LINE_LEN 10 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void cpuidle_cpu_output(unsigned int cpu, int verbose) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci unsigned int idlestates, idlestate; 268c2ecf20Sopenharmony_ci char *tmp; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci idlestates = cpuidle_state_count(cpu); 298c2ecf20Sopenharmony_ci if (idlestates == 0) { 308c2ecf20Sopenharmony_ci printf(_("CPU %u: No idle states\n"), cpu); 318c2ecf20Sopenharmony_ci return; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci printf(_("Number of idle states: %d\n"), idlestates); 358c2ecf20Sopenharmony_ci printf(_("Available idle states:")); 368c2ecf20Sopenharmony_ci for (idlestate = 0; idlestate < idlestates; idlestate++) { 378c2ecf20Sopenharmony_ci tmp = cpuidle_state_name(cpu, idlestate); 388c2ecf20Sopenharmony_ci if (!tmp) 398c2ecf20Sopenharmony_ci continue; 408c2ecf20Sopenharmony_ci printf(" %s", tmp); 418c2ecf20Sopenharmony_ci free(tmp); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci printf("\n"); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!verbose) 468c2ecf20Sopenharmony_ci return; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci for (idlestate = 0; idlestate < idlestates; idlestate++) { 498c2ecf20Sopenharmony_ci int disabled = cpuidle_is_state_disabled(cpu, idlestate); 508c2ecf20Sopenharmony_ci /* Disabled interface not supported on older kernels */ 518c2ecf20Sopenharmony_ci if (disabled < 0) 528c2ecf20Sopenharmony_ci disabled = 0; 538c2ecf20Sopenharmony_ci tmp = cpuidle_state_name(cpu, idlestate); 548c2ecf20Sopenharmony_ci if (!tmp) 558c2ecf20Sopenharmony_ci continue; 568c2ecf20Sopenharmony_ci printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); 578c2ecf20Sopenharmony_ci free(tmp); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci tmp = cpuidle_state_desc(cpu, idlestate); 608c2ecf20Sopenharmony_ci if (!tmp) 618c2ecf20Sopenharmony_ci continue; 628c2ecf20Sopenharmony_ci printf(_("Flags/Description: %s\n"), tmp); 638c2ecf20Sopenharmony_ci free(tmp); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci printf(_("Latency: %lu\n"), 668c2ecf20Sopenharmony_ci cpuidle_state_latency(cpu, idlestate)); 678c2ecf20Sopenharmony_ci printf(_("Usage: %lu\n"), 688c2ecf20Sopenharmony_ci cpuidle_state_usage(cpu, idlestate)); 698c2ecf20Sopenharmony_ci printf(_("Duration: %llu\n"), 708c2ecf20Sopenharmony_ci cpuidle_state_time(cpu, idlestate)); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void cpuidle_general_output(void) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci char *tmp; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci tmp = cpuidle_get_driver(); 798c2ecf20Sopenharmony_ci if (!tmp) { 808c2ecf20Sopenharmony_ci printf(_("Could not determine cpuidle driver\n")); 818c2ecf20Sopenharmony_ci return; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci printf(_("CPUidle driver: %s\n"), tmp); 858c2ecf20Sopenharmony_ci free(tmp); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci tmp = cpuidle_get_governor(); 888c2ecf20Sopenharmony_ci if (!tmp) { 898c2ecf20Sopenharmony_ci printf(_("Could not determine cpuidle governor\n")); 908c2ecf20Sopenharmony_ci return; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci printf(_("CPUidle governor: %s\n"), tmp); 948c2ecf20Sopenharmony_ci free(tmp); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void proc_cpuidle_cpu_output(unsigned int cpu) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci long max_allowed_cstate = 2000000000; 1008c2ecf20Sopenharmony_ci unsigned int cstate, cstates; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci cstates = cpuidle_state_count(cpu); 1038c2ecf20Sopenharmony_ci if (cstates == 0) { 1048c2ecf20Sopenharmony_ci printf(_("CPU %u: No C-states info\n"), cpu); 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci printf(_("active state: C0\n")); 1098c2ecf20Sopenharmony_ci printf(_("max_cstate: C%u\n"), cstates-1); 1108c2ecf20Sopenharmony_ci printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); 1118c2ecf20Sopenharmony_ci printf(_("states:\t\n")); 1128c2ecf20Sopenharmony_ci for (cstate = 1; cstate < cstates; cstate++) { 1138c2ecf20Sopenharmony_ci printf(_(" C%d: " 1148c2ecf20Sopenharmony_ci "type[C%d] "), cstate, cstate); 1158c2ecf20Sopenharmony_ci printf(_("promotion[--] demotion[--] ")); 1168c2ecf20Sopenharmony_ci printf(_("latency[%03lu] "), 1178c2ecf20Sopenharmony_ci cpuidle_state_latency(cpu, cstate)); 1188c2ecf20Sopenharmony_ci printf(_("usage[%08lu] "), 1198c2ecf20Sopenharmony_ci cpuidle_state_usage(cpu, cstate)); 1208c2ecf20Sopenharmony_ci printf(_("duration[%020Lu] \n"), 1218c2ecf20Sopenharmony_ci cpuidle_state_time(cpu, cstate)); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct option info_opts[] = { 1268c2ecf20Sopenharmony_ci {"silent", no_argument, NULL, 's'}, 1278c2ecf20Sopenharmony_ci {"proc", no_argument, NULL, 'o'}, 1288c2ecf20Sopenharmony_ci { }, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline void cpuidle_exit(int fail) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint cmd_idle_info(int argc, char **argv) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci extern char *optarg; 1398c2ecf20Sopenharmony_ci extern int optind, opterr, optopt; 1408c2ecf20Sopenharmony_ci int ret = 0, cont = 1, output_param = 0, verbose = 1; 1418c2ecf20Sopenharmony_ci unsigned int cpu = 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci do { 1448c2ecf20Sopenharmony_ci ret = getopt_long(argc, argv, "os", info_opts, NULL); 1458c2ecf20Sopenharmony_ci if (ret == -1) 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci switch (ret) { 1488c2ecf20Sopenharmony_ci case '?': 1498c2ecf20Sopenharmony_ci output_param = '?'; 1508c2ecf20Sopenharmony_ci cont = 0; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case 's': 1538c2ecf20Sopenharmony_ci verbose = 0; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case -1: 1568c2ecf20Sopenharmony_ci cont = 0; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case 'o': 1598c2ecf20Sopenharmony_ci if (output_param) { 1608c2ecf20Sopenharmony_ci output_param = -1; 1618c2ecf20Sopenharmony_ci cont = 0; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci output_param = ret; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } while (cont); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci switch (output_param) { 1708c2ecf20Sopenharmony_ci case -1: 1718c2ecf20Sopenharmony_ci printf(_("You can't specify more than one " 1728c2ecf20Sopenharmony_ci "output-specific argument\n")); 1738c2ecf20Sopenharmony_ci cpuidle_exit(EXIT_FAILURE); 1748c2ecf20Sopenharmony_ci case '?': 1758c2ecf20Sopenharmony_ci printf(_("invalid or unknown argument\n")); 1768c2ecf20Sopenharmony_ci cpuidle_exit(EXIT_FAILURE); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Default is: show output of CPU 0 only */ 1808c2ecf20Sopenharmony_ci if (bitmask_isallclear(cpus_chosen)) 1818c2ecf20Sopenharmony_ci bitmask_setbit(cpus_chosen, 0); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (output_param == 0) 1848c2ecf20Sopenharmony_ci cpuidle_general_output(); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci for (cpu = bitmask_first(cpus_chosen); 1878c2ecf20Sopenharmony_ci cpu <= bitmask_last(cpus_chosen); cpu++) { 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!bitmask_isbitset(cpus_chosen, cpu)) 1908c2ecf20Sopenharmony_ci continue; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci printf(_("analyzing CPU %d:\n"), cpu); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (sysfs_is_cpu_online(cpu) != 1) { 1958c2ecf20Sopenharmony_ci printf(_(" *is offline\n")); 1968c2ecf20Sopenharmony_ci printf("\n"); 1978c2ecf20Sopenharmony_ci continue; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch (output_param) { 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci case 'o': 2038c2ecf20Sopenharmony_ci proc_cpuidle_cpu_output(cpu); 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case 0: 2068c2ecf20Sopenharmony_ci printf("\n"); 2078c2ecf20Sopenharmony_ci cpuidle_cpu_output(cpu, verbose); 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci printf("\n"); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci return EXIT_SUCCESS; 2138c2ecf20Sopenharmony_ci} 214