18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <stdio.h> 98c2ecf20Sopenharmony_ci#include <errno.h> 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#include <limits.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <getopt.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "cpufreq.h" 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 unsigned int count_cpus(void) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci FILE *fp; 268c2ecf20Sopenharmony_ci char value[LINE_LEN]; 278c2ecf20Sopenharmony_ci unsigned int ret = 0; 288c2ecf20Sopenharmony_ci unsigned int cpunr = 0; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci fp = fopen("/proc/stat", "r"); 318c2ecf20Sopenharmony_ci if (!fp) { 328c2ecf20Sopenharmony_ci printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno)); 338c2ecf20Sopenharmony_ci return 1; 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci while (!feof(fp)) { 378c2ecf20Sopenharmony_ci if (!fgets(value, LINE_LEN, fp)) 388c2ecf20Sopenharmony_ci continue; 398c2ecf20Sopenharmony_ci value[LINE_LEN - 1] = '\0'; 408c2ecf20Sopenharmony_ci if (strlen(value) < (LINE_LEN - 2)) 418c2ecf20Sopenharmony_ci continue; 428c2ecf20Sopenharmony_ci if (strstr(value, "cpu ")) 438c2ecf20Sopenharmony_ci continue; 448c2ecf20Sopenharmony_ci if (sscanf(value, "cpu%d ", &cpunr) != 1) 458c2ecf20Sopenharmony_ci continue; 468c2ecf20Sopenharmony_ci if (cpunr > ret) 478c2ecf20Sopenharmony_ci ret = cpunr; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci fclose(fp); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* cpu count starts from 0, on error return 1 (UP) */ 528c2ecf20Sopenharmony_ci return ret + 1; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void proc_cpufreq_output(void) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci unsigned int cpu, nr_cpus; 598c2ecf20Sopenharmony_ci struct cpufreq_policy *policy; 608c2ecf20Sopenharmony_ci unsigned int min_pctg = 0; 618c2ecf20Sopenharmony_ci unsigned int max_pctg = 0; 628c2ecf20Sopenharmony_ci unsigned long min, max; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n")); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci nr_cpus = count_cpus(); 678c2ecf20Sopenharmony_ci for (cpu = 0; cpu < nr_cpus; cpu++) { 688c2ecf20Sopenharmony_ci policy = cpufreq_get_policy(cpu); 698c2ecf20Sopenharmony_ci if (!policy) 708c2ecf20Sopenharmony_ci continue; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (cpufreq_get_hardware_limits(cpu, &min, &max)) { 738c2ecf20Sopenharmony_ci max = 0; 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci min_pctg = (policy->min * 100) / max; 768c2ecf20Sopenharmony_ci max_pctg = (policy->max * 100) / max; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n", 798c2ecf20Sopenharmony_ci cpu , policy->min, max ? min_pctg : 0, policy->max, 808c2ecf20Sopenharmony_ci max ? max_pctg : 0, policy->governor); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci cpufreq_put_policy(policy); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int no_rounding; 878c2ecf20Sopenharmony_cistatic void print_speed(unsigned long speed) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned long tmp; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (no_rounding) { 928c2ecf20Sopenharmony_ci if (speed > 1000000) 938c2ecf20Sopenharmony_ci printf("%u.%06u GHz", ((unsigned int) speed/1000000), 948c2ecf20Sopenharmony_ci ((unsigned int) speed%1000000)); 958c2ecf20Sopenharmony_ci else if (speed > 1000) 968c2ecf20Sopenharmony_ci printf("%u.%03u MHz", ((unsigned int) speed/1000), 978c2ecf20Sopenharmony_ci (unsigned int) (speed%1000)); 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci printf("%lu kHz", speed); 1008c2ecf20Sopenharmony_ci } else { 1018c2ecf20Sopenharmony_ci if (speed > 1000000) { 1028c2ecf20Sopenharmony_ci tmp = speed%10000; 1038c2ecf20Sopenharmony_ci if (tmp >= 5000) 1048c2ecf20Sopenharmony_ci speed += 10000; 1058c2ecf20Sopenharmony_ci printf("%u.%02u GHz", ((unsigned int) speed/1000000), 1068c2ecf20Sopenharmony_ci ((unsigned int) (speed%1000000)/10000)); 1078c2ecf20Sopenharmony_ci } else if (speed > 100000) { 1088c2ecf20Sopenharmony_ci tmp = speed%1000; 1098c2ecf20Sopenharmony_ci if (tmp >= 500) 1108c2ecf20Sopenharmony_ci speed += 1000; 1118c2ecf20Sopenharmony_ci printf("%u MHz", ((unsigned int) speed/1000)); 1128c2ecf20Sopenharmony_ci } else if (speed > 1000) { 1138c2ecf20Sopenharmony_ci tmp = speed%100; 1148c2ecf20Sopenharmony_ci if (tmp >= 50) 1158c2ecf20Sopenharmony_ci speed += 100; 1168c2ecf20Sopenharmony_ci printf("%u.%01u MHz", ((unsigned int) speed/1000), 1178c2ecf20Sopenharmony_ci ((unsigned int) (speed%1000)/100)); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void print_duration(unsigned long duration) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci unsigned long tmp; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (no_rounding) { 1298c2ecf20Sopenharmony_ci if (duration > 1000000) 1308c2ecf20Sopenharmony_ci printf("%u.%06u ms", ((unsigned int) duration/1000000), 1318c2ecf20Sopenharmony_ci ((unsigned int) duration%1000000)); 1328c2ecf20Sopenharmony_ci else if (duration > 100000) 1338c2ecf20Sopenharmony_ci printf("%u us", ((unsigned int) duration/1000)); 1348c2ecf20Sopenharmony_ci else if (duration > 1000) 1358c2ecf20Sopenharmony_ci printf("%u.%03u us", ((unsigned int) duration/1000), 1368c2ecf20Sopenharmony_ci ((unsigned int) duration%1000)); 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci printf("%lu ns", duration); 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci if (duration > 1000000) { 1418c2ecf20Sopenharmony_ci tmp = duration%10000; 1428c2ecf20Sopenharmony_ci if (tmp >= 5000) 1438c2ecf20Sopenharmony_ci duration += 10000; 1448c2ecf20Sopenharmony_ci printf("%u.%02u ms", ((unsigned int) duration/1000000), 1458c2ecf20Sopenharmony_ci ((unsigned int) (duration%1000000)/10000)); 1468c2ecf20Sopenharmony_ci } else if (duration > 100000) { 1478c2ecf20Sopenharmony_ci tmp = duration%1000; 1488c2ecf20Sopenharmony_ci if (tmp >= 500) 1498c2ecf20Sopenharmony_ci duration += 1000; 1508c2ecf20Sopenharmony_ci printf("%u us", ((unsigned int) duration / 1000)); 1518c2ecf20Sopenharmony_ci } else if (duration > 1000) { 1528c2ecf20Sopenharmony_ci tmp = duration%100; 1538c2ecf20Sopenharmony_ci if (tmp >= 50) 1548c2ecf20Sopenharmony_ci duration += 100; 1558c2ecf20Sopenharmony_ci printf("%u.%01u us", ((unsigned int) duration/1000), 1568c2ecf20Sopenharmony_ci ((unsigned int) (duration%1000)/100)); 1578c2ecf20Sopenharmony_ci } else 1588c2ecf20Sopenharmony_ci printf("%lu ns", duration); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci return; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int get_boost_mode_x86(unsigned int cpu) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int support, active, b_states = 0, ret, pstate_no, i; 1668c2ecf20Sopenharmony_ci /* ToDo: Make this more global */ 1678c2ecf20Sopenharmony_ci unsigned long pstates[MAX_HW_PSTATES] = {0,}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states); 1708c2ecf20Sopenharmony_ci if (ret) { 1718c2ecf20Sopenharmony_ci printf(_("Error while evaluating Boost Capabilities" 1728c2ecf20Sopenharmony_ci " on CPU %d -- are you root?\n"), cpu); 1738c2ecf20Sopenharmony_ci return ret; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci /* P state changes via MSR are identified via cpuid 80000007 1768c2ecf20Sopenharmony_ci on Intel and AMD, but we assume boost capable machines can do that 1778c2ecf20Sopenharmony_ci if (cpuid_eax(0x80000000) >= 0x80000007 1788c2ecf20Sopenharmony_ci && (cpuid_edx(0x80000007) & (1 << 7))) 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci printf(_(" boost state support:\n")); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci printf(_(" Supported: %s\n"), support ? _("yes") : _("no")); 1848c2ecf20Sopenharmony_ci printf(_(" Active: %s\n"), active ? _("yes") : _("no")); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD && 1878c2ecf20Sopenharmony_ci cpupower_cpu_info.family >= 0x10) || 1888c2ecf20Sopenharmony_ci cpupower_cpu_info.vendor == X86_VENDOR_HYGON) { 1898c2ecf20Sopenharmony_ci ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states, 1908c2ecf20Sopenharmony_ci pstates, &pstate_no); 1918c2ecf20Sopenharmony_ci if (ret) 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci printf(_(" Boost States: %d\n"), b_states); 1958c2ecf20Sopenharmony_ci printf(_(" Total States: %d\n"), pstate_no); 1968c2ecf20Sopenharmony_ci for (i = 0; i < pstate_no; i++) { 1978c2ecf20Sopenharmony_ci if (!pstates[i]) 1988c2ecf20Sopenharmony_ci continue; 1998c2ecf20Sopenharmony_ci if (i < b_states) 2008c2ecf20Sopenharmony_ci printf(_(" Pstate-Pb%d: %luMHz (boost state)" 2018c2ecf20Sopenharmony_ci "\n"), i, pstates[i]); 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci printf(_(" Pstate-P%d: %luMHz\n"), 2048c2ecf20Sopenharmony_ci i - b_states, pstates[i]); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) { 2078c2ecf20Sopenharmony_ci double bclk; 2088c2ecf20Sopenharmony_ci unsigned long long intel_turbo_ratio = 0; 2098c2ecf20Sopenharmony_ci unsigned int ratio; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Any way to autodetect this ? */ 2128c2ecf20Sopenharmony_ci if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB) 2138c2ecf20Sopenharmony_ci bclk = 100.00; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci bclk = 133.33; 2168c2ecf20Sopenharmony_ci intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu); 2178c2ecf20Sopenharmony_ci dprint (" Ratio: 0x%llx - bclk: %f\n", 2188c2ecf20Sopenharmony_ci intel_turbo_ratio, bclk); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ratio = (intel_turbo_ratio >> 24) & 0xFF; 2218c2ecf20Sopenharmony_ci if (ratio) 2228c2ecf20Sopenharmony_ci printf(_(" %.0f MHz max turbo 4 active cores\n"), 2238c2ecf20Sopenharmony_ci ratio * bclk); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ratio = (intel_turbo_ratio >> 16) & 0xFF; 2268c2ecf20Sopenharmony_ci if (ratio) 2278c2ecf20Sopenharmony_ci printf(_(" %.0f MHz max turbo 3 active cores\n"), 2288c2ecf20Sopenharmony_ci ratio * bclk); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ratio = (intel_turbo_ratio >> 8) & 0xFF; 2318c2ecf20Sopenharmony_ci if (ratio) 2328c2ecf20Sopenharmony_ci printf(_(" %.0f MHz max turbo 2 active cores\n"), 2338c2ecf20Sopenharmony_ci ratio * bclk); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ratio = (intel_turbo_ratio >> 0) & 0xFF; 2368c2ecf20Sopenharmony_ci if (ratio) 2378c2ecf20Sopenharmony_ci printf(_(" %.0f MHz max turbo 1 active cores\n"), 2388c2ecf20Sopenharmony_ci ratio * bclk); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci return 0; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci/* --boost / -b */ 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int get_boost_mode(unsigned int cpu) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *freqs; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (cpupower_cpu_info.vendor == X86_VENDOR_AMD || 2508c2ecf20Sopenharmony_ci cpupower_cpu_info.vendor == X86_VENDOR_HYGON || 2518c2ecf20Sopenharmony_ci cpupower_cpu_info.vendor == X86_VENDOR_INTEL) 2528c2ecf20Sopenharmony_ci return get_boost_mode_x86(cpu); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci freqs = cpufreq_get_boost_frequencies(cpu); 2558c2ecf20Sopenharmony_ci if (freqs) { 2568c2ecf20Sopenharmony_ci printf(_(" boost frequency steps: ")); 2578c2ecf20Sopenharmony_ci while (freqs->next) { 2588c2ecf20Sopenharmony_ci print_speed(freqs->frequency); 2598c2ecf20Sopenharmony_ci printf(", "); 2608c2ecf20Sopenharmony_ci freqs = freqs->next; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci print_speed(freqs->frequency); 2638c2ecf20Sopenharmony_ci printf("\n"); 2648c2ecf20Sopenharmony_ci cpufreq_put_available_frequencies(freqs); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* --freq / -f */ 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int get_freq_kernel(unsigned int cpu, unsigned int human) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci unsigned long freq = cpufreq_get_freq_kernel(cpu); 2758c2ecf20Sopenharmony_ci printf(_(" current CPU frequency: ")); 2768c2ecf20Sopenharmony_ci if (!freq) { 2778c2ecf20Sopenharmony_ci printf(_(" Unable to call to kernel\n")); 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (human) { 2818c2ecf20Sopenharmony_ci print_speed(freq); 2828c2ecf20Sopenharmony_ci } else 2838c2ecf20Sopenharmony_ci printf("%lu", freq); 2848c2ecf20Sopenharmony_ci printf(_(" (asserted by call to kernel)\n")); 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* --hwfreq / -w */ 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int get_freq_hardware(unsigned int cpu, unsigned int human) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci unsigned long freq = cpufreq_get_freq_hardware(cpu); 2948c2ecf20Sopenharmony_ci printf(_(" current CPU frequency: ")); 2958c2ecf20Sopenharmony_ci if (!freq) { 2968c2ecf20Sopenharmony_ci printf("Unable to call hardware\n"); 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci if (human) { 3008c2ecf20Sopenharmony_ci print_speed(freq); 3018c2ecf20Sopenharmony_ci } else 3028c2ecf20Sopenharmony_ci printf("%lu", freq); 3038c2ecf20Sopenharmony_ci printf(_(" (asserted by call to hardware)\n")); 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* --hwlimits / -l */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int get_hardware_limits(unsigned int cpu, unsigned int human) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci unsigned long min, max; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (cpufreq_get_hardware_limits(cpu, &min, &max)) { 3148c2ecf20Sopenharmony_ci printf(_("Not Available\n")); 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (human) { 3198c2ecf20Sopenharmony_ci printf(_(" hardware limits: ")); 3208c2ecf20Sopenharmony_ci print_speed(min); 3218c2ecf20Sopenharmony_ci printf(" - "); 3228c2ecf20Sopenharmony_ci print_speed(max); 3238c2ecf20Sopenharmony_ci printf("\n"); 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci printf("%lu %lu\n", min, max); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/* --driver / -d */ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int get_driver(unsigned int cpu) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci char *driver = cpufreq_get_driver(cpu); 3358c2ecf20Sopenharmony_ci if (!driver) { 3368c2ecf20Sopenharmony_ci printf(_(" no or unknown cpufreq driver is active on this CPU\n")); 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci printf(" driver: %s\n", driver); 3408c2ecf20Sopenharmony_ci cpufreq_put_driver(driver); 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* --policy / -p */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int get_policy(unsigned int cpu) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct cpufreq_policy *policy = cpufreq_get_policy(cpu); 3498c2ecf20Sopenharmony_ci if (!policy) { 3508c2ecf20Sopenharmony_ci printf(_(" Unable to determine current policy\n")); 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci printf(_(" current policy: frequency should be within ")); 3548c2ecf20Sopenharmony_ci print_speed(policy->min); 3558c2ecf20Sopenharmony_ci printf(_(" and ")); 3568c2ecf20Sopenharmony_ci print_speed(policy->max); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci printf(".\n "); 3598c2ecf20Sopenharmony_ci printf(_("The governor \"%s\" may decide which speed to use\n" 3608c2ecf20Sopenharmony_ci " within this range.\n"), 3618c2ecf20Sopenharmony_ci policy->governor); 3628c2ecf20Sopenharmony_ci cpufreq_put_policy(policy); 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* --governors / -g */ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int get_available_governors(unsigned int cpu) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct cpufreq_available_governors *governors = 3718c2ecf20Sopenharmony_ci cpufreq_get_available_governors(cpu); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci printf(_(" available cpufreq governors: ")); 3748c2ecf20Sopenharmony_ci if (!governors) { 3758c2ecf20Sopenharmony_ci printf(_("Not Available\n")); 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci while (governors->next) { 3808c2ecf20Sopenharmony_ci printf("%s ", governors->governor); 3818c2ecf20Sopenharmony_ci governors = governors->next; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci printf("%s\n", governors->governor); 3848c2ecf20Sopenharmony_ci cpufreq_put_available_governors(governors); 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* --affected-cpus / -a */ 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int get_affected_cpus(unsigned int cpu) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci printf(_(" CPUs which need to have their frequency coordinated by software: ")); 3968c2ecf20Sopenharmony_ci if (!cpus) { 3978c2ecf20Sopenharmony_ci printf(_("Not Available\n")); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci while (cpus->next) { 4028c2ecf20Sopenharmony_ci printf("%d ", cpus->cpu); 4038c2ecf20Sopenharmony_ci cpus = cpus->next; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci printf("%d\n", cpus->cpu); 4068c2ecf20Sopenharmony_ci cpufreq_put_affected_cpus(cpus); 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/* --related-cpus / -r */ 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int get_related_cpus(unsigned int cpu) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci printf(_(" CPUs which run at the same hardware frequency: ")); 4178c2ecf20Sopenharmony_ci if (!cpus) { 4188c2ecf20Sopenharmony_ci printf(_("Not Available\n")); 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci while (cpus->next) { 4238c2ecf20Sopenharmony_ci printf("%d ", cpus->cpu); 4248c2ecf20Sopenharmony_ci cpus = cpus->next; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci printf("%d\n", cpus->cpu); 4278c2ecf20Sopenharmony_ci cpufreq_put_related_cpus(cpus); 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* --stats / -s */ 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int get_freq_stats(unsigned int cpu, unsigned int human) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci unsigned long total_trans = cpufreq_get_transitions(cpu); 4368c2ecf20Sopenharmony_ci unsigned long long total_time; 4378c2ecf20Sopenharmony_ci struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); 4388c2ecf20Sopenharmony_ci while (stats) { 4398c2ecf20Sopenharmony_ci if (human) { 4408c2ecf20Sopenharmony_ci print_speed(stats->frequency); 4418c2ecf20Sopenharmony_ci printf(":%.2f%%", 4428c2ecf20Sopenharmony_ci (100.0 * stats->time_in_state) / total_time); 4438c2ecf20Sopenharmony_ci } else 4448c2ecf20Sopenharmony_ci printf("%lu:%llu", 4458c2ecf20Sopenharmony_ci stats->frequency, stats->time_in_state); 4468c2ecf20Sopenharmony_ci stats = stats->next; 4478c2ecf20Sopenharmony_ci if (stats) 4488c2ecf20Sopenharmony_ci printf(", "); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci cpufreq_put_stats(stats); 4518c2ecf20Sopenharmony_ci if (total_trans) 4528c2ecf20Sopenharmony_ci printf(" (%lu)\n", total_trans); 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/* --latency / -y */ 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int get_latency(unsigned int cpu, unsigned int human) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci unsigned long latency = cpufreq_get_transition_latency(cpu); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci printf(_(" maximum transition latency: ")); 4638c2ecf20Sopenharmony_ci if (!latency || latency == UINT_MAX) { 4648c2ecf20Sopenharmony_ci printf(_(" Cannot determine or is not supported.\n")); 4658c2ecf20Sopenharmony_ci return -EINVAL; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (human) { 4698c2ecf20Sopenharmony_ci print_duration(latency); 4708c2ecf20Sopenharmony_ci printf("\n"); 4718c2ecf20Sopenharmony_ci } else 4728c2ecf20Sopenharmony_ci printf("%lu\n", latency); 4738c2ecf20Sopenharmony_ci return 0; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void debug_output_one(unsigned int cpu) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *freqs; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci get_driver(cpu); 4818c2ecf20Sopenharmony_ci get_related_cpus(cpu); 4828c2ecf20Sopenharmony_ci get_affected_cpus(cpu); 4838c2ecf20Sopenharmony_ci get_latency(cpu, 1); 4848c2ecf20Sopenharmony_ci get_hardware_limits(cpu, 1); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci freqs = cpufreq_get_available_frequencies(cpu); 4878c2ecf20Sopenharmony_ci if (freqs) { 4888c2ecf20Sopenharmony_ci printf(_(" available frequency steps: ")); 4898c2ecf20Sopenharmony_ci while (freqs->next) { 4908c2ecf20Sopenharmony_ci print_speed(freqs->frequency); 4918c2ecf20Sopenharmony_ci printf(", "); 4928c2ecf20Sopenharmony_ci freqs = freqs->next; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci print_speed(freqs->frequency); 4958c2ecf20Sopenharmony_ci printf("\n"); 4968c2ecf20Sopenharmony_ci cpufreq_put_available_frequencies(freqs); 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci get_available_governors(cpu); 5008c2ecf20Sopenharmony_ci get_policy(cpu); 5018c2ecf20Sopenharmony_ci if (get_freq_hardware(cpu, 1) < 0) 5028c2ecf20Sopenharmony_ci get_freq_kernel(cpu, 1); 5038c2ecf20Sopenharmony_ci get_boost_mode(cpu); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic struct option info_opts[] = { 5078c2ecf20Sopenharmony_ci {"debug", no_argument, NULL, 'e'}, 5088c2ecf20Sopenharmony_ci {"boost", no_argument, NULL, 'b'}, 5098c2ecf20Sopenharmony_ci {"freq", no_argument, NULL, 'f'}, 5108c2ecf20Sopenharmony_ci {"hwfreq", no_argument, NULL, 'w'}, 5118c2ecf20Sopenharmony_ci {"hwlimits", no_argument, NULL, 'l'}, 5128c2ecf20Sopenharmony_ci {"driver", no_argument, NULL, 'd'}, 5138c2ecf20Sopenharmony_ci {"policy", no_argument, NULL, 'p'}, 5148c2ecf20Sopenharmony_ci {"governors", no_argument, NULL, 'g'}, 5158c2ecf20Sopenharmony_ci {"related-cpus", no_argument, NULL, 'r'}, 5168c2ecf20Sopenharmony_ci {"affected-cpus", no_argument, NULL, 'a'}, 5178c2ecf20Sopenharmony_ci {"stats", no_argument, NULL, 's'}, 5188c2ecf20Sopenharmony_ci {"latency", no_argument, NULL, 'y'}, 5198c2ecf20Sopenharmony_ci {"proc", no_argument, NULL, 'o'}, 5208c2ecf20Sopenharmony_ci {"human", no_argument, NULL, 'm'}, 5218c2ecf20Sopenharmony_ci {"no-rounding", no_argument, NULL, 'n'}, 5228c2ecf20Sopenharmony_ci { }, 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ciint cmd_freq_info(int argc, char **argv) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci extern char *optarg; 5288c2ecf20Sopenharmony_ci extern int optind, opterr, optopt; 5298c2ecf20Sopenharmony_ci int ret = 0, cont = 1; 5308c2ecf20Sopenharmony_ci unsigned int cpu = 0; 5318c2ecf20Sopenharmony_ci unsigned int human = 0; 5328c2ecf20Sopenharmony_ci int output_param = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci do { 5358c2ecf20Sopenharmony_ci ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts, 5368c2ecf20Sopenharmony_ci NULL); 5378c2ecf20Sopenharmony_ci switch (ret) { 5388c2ecf20Sopenharmony_ci case '?': 5398c2ecf20Sopenharmony_ci output_param = '?'; 5408c2ecf20Sopenharmony_ci cont = 0; 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci case -1: 5438c2ecf20Sopenharmony_ci cont = 0; 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci case 'b': 5468c2ecf20Sopenharmony_ci case 'o': 5478c2ecf20Sopenharmony_ci case 'a': 5488c2ecf20Sopenharmony_ci case 'r': 5498c2ecf20Sopenharmony_ci case 'g': 5508c2ecf20Sopenharmony_ci case 'p': 5518c2ecf20Sopenharmony_ci case 'd': 5528c2ecf20Sopenharmony_ci case 'l': 5538c2ecf20Sopenharmony_ci case 'w': 5548c2ecf20Sopenharmony_ci case 'f': 5558c2ecf20Sopenharmony_ci case 'e': 5568c2ecf20Sopenharmony_ci case 's': 5578c2ecf20Sopenharmony_ci case 'y': 5588c2ecf20Sopenharmony_ci if (output_param) { 5598c2ecf20Sopenharmony_ci output_param = -1; 5608c2ecf20Sopenharmony_ci cont = 0; 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci output_param = ret; 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci case 'm': 5668c2ecf20Sopenharmony_ci if (human) { 5678c2ecf20Sopenharmony_ci output_param = -1; 5688c2ecf20Sopenharmony_ci cont = 0; 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci human = 1; 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci case 'n': 5748c2ecf20Sopenharmony_ci no_rounding = 1; 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci default: 5778c2ecf20Sopenharmony_ci fprintf(stderr, "invalid or unknown argument\n"); 5788c2ecf20Sopenharmony_ci return EXIT_FAILURE; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci } while (cont); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci switch (output_param) { 5838c2ecf20Sopenharmony_ci case 'o': 5848c2ecf20Sopenharmony_ci if (!bitmask_isallclear(cpus_chosen)) { 5858c2ecf20Sopenharmony_ci printf(_("The argument passed to this tool can't be " 5868c2ecf20Sopenharmony_ci "combined with passing a --cpu argument\n")); 5878c2ecf20Sopenharmony_ci return -EINVAL; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci case 0: 5918c2ecf20Sopenharmony_ci output_param = 'e'; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci ret = 0; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Default is: show output of CPU 0 only */ 5978c2ecf20Sopenharmony_ci if (bitmask_isallclear(cpus_chosen)) 5988c2ecf20Sopenharmony_ci bitmask_setbit(cpus_chosen, 0); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci switch (output_param) { 6018c2ecf20Sopenharmony_ci case -1: 6028c2ecf20Sopenharmony_ci printf(_("You can't specify more than one --cpu parameter and/or\n" 6038c2ecf20Sopenharmony_ci "more than one output-specific argument\n")); 6048c2ecf20Sopenharmony_ci return -EINVAL; 6058c2ecf20Sopenharmony_ci case '?': 6068c2ecf20Sopenharmony_ci printf(_("invalid or unknown argument\n")); 6078c2ecf20Sopenharmony_ci return -EINVAL; 6088c2ecf20Sopenharmony_ci case 'o': 6098c2ecf20Sopenharmony_ci proc_cpufreq_output(); 6108c2ecf20Sopenharmony_ci return EXIT_SUCCESS; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci for (cpu = bitmask_first(cpus_chosen); 6148c2ecf20Sopenharmony_ci cpu <= bitmask_last(cpus_chosen); cpu++) { 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (!bitmask_isbitset(cpus_chosen, cpu)) 6178c2ecf20Sopenharmony_ci continue; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci printf(_("analyzing CPU %d:\n"), cpu); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (sysfs_is_cpu_online(cpu) != 1) { 6228c2ecf20Sopenharmony_ci printf(_(" *is offline\n")); 6238c2ecf20Sopenharmony_ci printf("\n"); 6248c2ecf20Sopenharmony_ci continue; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci switch (output_param) { 6288c2ecf20Sopenharmony_ci case 'b': 6298c2ecf20Sopenharmony_ci get_boost_mode(cpu); 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci case 'e': 6328c2ecf20Sopenharmony_ci debug_output_one(cpu); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci case 'a': 6358c2ecf20Sopenharmony_ci ret = get_affected_cpus(cpu); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case 'r': 6388c2ecf20Sopenharmony_ci ret = get_related_cpus(cpu); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case 'g': 6418c2ecf20Sopenharmony_ci ret = get_available_governors(cpu); 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case 'p': 6448c2ecf20Sopenharmony_ci ret = get_policy(cpu); 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci case 'd': 6478c2ecf20Sopenharmony_ci ret = get_driver(cpu); 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci case 'l': 6508c2ecf20Sopenharmony_ci ret = get_hardware_limits(cpu, human); 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case 'w': 6538c2ecf20Sopenharmony_ci ret = get_freq_hardware(cpu, human); 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci case 'f': 6568c2ecf20Sopenharmony_ci ret = get_freq_kernel(cpu, human); 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci case 's': 6598c2ecf20Sopenharmony_ci ret = get_freq_stats(cpu, human); 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case 'y': 6628c2ecf20Sopenharmony_ci ret = get_latency(cpu, human); 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci if (ret) 6668c2ecf20Sopenharmony_ci return ret; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci} 670