| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * acpi-cpufreq.c - ACPI Processor P-States Driver |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
|---|
| 6 | 7 | * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> |
|---|
| 7 | 8 | * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com> |
|---|
| 8 | | - * |
|---|
| 9 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 12 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 13 | | - * the Free Software Foundation; either version 2 of the License, or (at |
|---|
| 14 | | - * your option) any later version. |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 17 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 19 | | - * General Public License for more details. |
|---|
| 20 | | - * |
|---|
| 21 | | - * You should have received a copy of the GNU General Public License along |
|---|
| 22 | | - * with this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 23 | | - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|---|
| 24 | | - * |
|---|
| 25 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 26 | 9 | */ |
|---|
| 27 | 10 | |
|---|
| 28 | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 43 | 26 | #include <linux/uaccess.h> |
|---|
| 44 | 27 | |
|---|
| 45 | 28 | #include <acpi/processor.h> |
|---|
| 29 | +#include <acpi/cppc_acpi.h> |
|---|
| 46 | 30 | |
|---|
| 47 | 31 | #include <asm/msr.h> |
|---|
| 48 | 32 | #include <asm/processor.h> |
|---|
| 49 | 33 | #include <asm/cpufeature.h> |
|---|
| 34 | +#include <asm/cpu_device_id.h> |
|---|
| 50 | 35 | |
|---|
| 51 | 36 | MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); |
|---|
| 52 | 37 | MODULE_DESCRIPTION("ACPI Processor P-States Driver"); |
|---|
| .. | .. |
|---|
| 61 | 46 | |
|---|
| 62 | 47 | #define INTEL_MSR_RANGE (0xffff) |
|---|
| 63 | 48 | #define AMD_MSR_RANGE (0x7) |
|---|
| 49 | +#define HYGON_MSR_RANGE (0x7) |
|---|
| 64 | 50 | |
|---|
| 65 | 51 | #define MSR_K7_HWCR_CPB_DIS (1ULL << 25) |
|---|
| 66 | 52 | |
|---|
| .. | .. |
|---|
| 95 | 81 | rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi); |
|---|
| 96 | 82 | msr = lo | ((u64)hi << 32); |
|---|
| 97 | 83 | return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); |
|---|
| 84 | + case X86_VENDOR_HYGON: |
|---|
| 98 | 85 | case X86_VENDOR_AMD: |
|---|
| 99 | 86 | rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); |
|---|
| 100 | 87 | msr = lo | ((u64)hi << 32); |
|---|
| .. | .. |
|---|
| 113 | 100 | msr_addr = MSR_IA32_MISC_ENABLE; |
|---|
| 114 | 101 | msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE; |
|---|
| 115 | 102 | break; |
|---|
| 103 | + case X86_VENDOR_HYGON: |
|---|
| 116 | 104 | case X86_VENDOR_AMD: |
|---|
| 117 | 105 | msr_addr = MSR_K7_HWCR; |
|---|
| 118 | 106 | msr_mask = MSR_K7_HWCR_CPB_DIS; |
|---|
| .. | .. |
|---|
| 139 | 127 | boost_set_msr(enable); |
|---|
| 140 | 128 | } |
|---|
| 141 | 129 | |
|---|
| 142 | | -static int set_boost(int val) |
|---|
| 130 | +static int set_boost(struct cpufreq_policy *policy, int val) |
|---|
| 143 | 131 | { |
|---|
| 144 | | - get_online_cpus(); |
|---|
| 145 | | - on_each_cpu(boost_set_msr_each, (void *)(long)val, 1); |
|---|
| 146 | | - put_online_cpus(); |
|---|
| 147 | | - pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis"); |
|---|
| 132 | + on_each_cpu_mask(policy->cpus, boost_set_msr_each, |
|---|
| 133 | + (void *)(long)val, 1); |
|---|
| 134 | + pr_debug("CPU %*pbl: Core Boosting %sabled.\n", |
|---|
| 135 | + cpumask_pr_args(policy->cpus), val ? "en" : "dis"); |
|---|
| 148 | 136 | |
|---|
| 149 | 137 | return 0; |
|---|
| 150 | 138 | } |
|---|
| .. | .. |
|---|
| 175 | 163 | if (ret || val > 1) |
|---|
| 176 | 164 | return -EINVAL; |
|---|
| 177 | 165 | |
|---|
| 178 | | - set_boost(val); |
|---|
| 166 | + get_online_cpus(); |
|---|
| 167 | + set_boost(policy, val); |
|---|
| 168 | + put_online_cpus(); |
|---|
| 179 | 169 | |
|---|
| 180 | 170 | return count; |
|---|
| 181 | 171 | } |
|---|
| .. | .. |
|---|
| 225 | 215 | |
|---|
| 226 | 216 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) |
|---|
| 227 | 217 | msr &= AMD_MSR_RANGE; |
|---|
| 218 | + else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) |
|---|
| 219 | + msr &= HYGON_MSR_RANGE; |
|---|
| 228 | 220 | else |
|---|
| 229 | 221 | msr &= INTEL_MSR_RANGE; |
|---|
| 230 | 222 | |
|---|
| .. | .. |
|---|
| 253 | 245 | |
|---|
| 254 | 246 | static u32 cpu_freq_read_intel(struct acpi_pct_register *not_used) |
|---|
| 255 | 247 | { |
|---|
| 256 | | - u32 val, dummy; |
|---|
| 248 | + u32 val, dummy __always_unused; |
|---|
| 257 | 249 | |
|---|
| 258 | 250 | rdmsr(MSR_IA32_PERF_CTL, val, dummy); |
|---|
| 259 | 251 | return val; |
|---|
| .. | .. |
|---|
| 270 | 262 | |
|---|
| 271 | 263 | static u32 cpu_freq_read_amd(struct acpi_pct_register *not_used) |
|---|
| 272 | 264 | { |
|---|
| 273 | | - u32 val, dummy; |
|---|
| 265 | + u32 val, dummy __always_unused; |
|---|
| 274 | 266 | |
|---|
| 275 | 267 | rdmsr(MSR_AMD_PERF_CTL, val, dummy); |
|---|
| 276 | 268 | return val; |
|---|
| .. | .. |
|---|
| 361 | 353 | |
|---|
| 362 | 354 | val = drv_read(data, mask); |
|---|
| 363 | 355 | |
|---|
| 364 | | - pr_debug("get_cur_val = %u\n", val); |
|---|
| 356 | + pr_debug("%s = %u\n", __func__, val); |
|---|
| 365 | 357 | |
|---|
| 366 | 358 | return val; |
|---|
| 367 | 359 | } |
|---|
| .. | .. |
|---|
| 373 | 365 | unsigned int freq; |
|---|
| 374 | 366 | unsigned int cached_freq; |
|---|
| 375 | 367 | |
|---|
| 376 | | - pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); |
|---|
| 368 | + pr_debug("%s (%d)\n", __func__, cpu); |
|---|
| 377 | 369 | |
|---|
| 378 | 370 | policy = cpufreq_cpu_get_raw(cpu); |
|---|
| 379 | 371 | if (unlikely(!policy)) |
|---|
| .. | .. |
|---|
| 453 | 445 | if (acpi_pstate_strict) { |
|---|
| 454 | 446 | if (!check_freqs(policy, mask, |
|---|
| 455 | 447 | policy->freq_table[index].frequency)) { |
|---|
| 456 | | - pr_debug("acpi_cpufreq_target failed (%d)\n", |
|---|
| 457 | | - policy->cpu); |
|---|
| 448 | + pr_debug("%s (%d)\n", __func__, policy->cpu); |
|---|
| 458 | 449 | result = -EAGAIN; |
|---|
| 459 | 450 | } |
|---|
| 460 | 451 | } |
|---|
| .. | .. |
|---|
| 568 | 559 | static int __init acpi_cpufreq_early_init(void) |
|---|
| 569 | 560 | { |
|---|
| 570 | 561 | unsigned int i; |
|---|
| 571 | | - pr_debug("acpi_cpufreq_early_init\n"); |
|---|
| 562 | + pr_debug("%s\n", __func__); |
|---|
| 572 | 563 | |
|---|
| 573 | 564 | acpi_perf_data = alloc_percpu(struct acpi_processor_performance); |
|---|
| 574 | 565 | if (!acpi_perf_data) { |
|---|
| .. | .. |
|---|
| 622 | 613 | static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) |
|---|
| 623 | 614 | { |
|---|
| 624 | 615 | /* Intel Xeon Processor 7100 Series Specification Update |
|---|
| 625 | | - * http://www.intel.com/Assets/PDF/specupdate/314554.pdf |
|---|
| 616 | + * https://www.intel.com/Assets/PDF/specupdate/314554.pdf |
|---|
| 626 | 617 | * AL30: A Machine Check Exception (MCE) Occurring during an |
|---|
| 627 | 618 | * Enhanced Intel SpeedStep Technology Ratio Change May Cause |
|---|
| 628 | 619 | * Both Processor Cores to Lock Up. */ |
|---|
| .. | .. |
|---|
| 638 | 629 | } |
|---|
| 639 | 630 | #endif |
|---|
| 640 | 631 | |
|---|
| 632 | +#ifdef CONFIG_ACPI_CPPC_LIB |
|---|
| 633 | +static u64 get_max_boost_ratio(unsigned int cpu) |
|---|
| 634 | +{ |
|---|
| 635 | + struct cppc_perf_caps perf_caps; |
|---|
| 636 | + u64 highest_perf, nominal_perf; |
|---|
| 637 | + int ret; |
|---|
| 638 | + |
|---|
| 639 | + if (acpi_pstate_strict) |
|---|
| 640 | + return 0; |
|---|
| 641 | + |
|---|
| 642 | + ret = cppc_get_perf_caps(cpu, &perf_caps); |
|---|
| 643 | + if (ret) { |
|---|
| 644 | + pr_debug("CPU%d: Unable to get performance capabilities (%d)\n", |
|---|
| 645 | + cpu, ret); |
|---|
| 646 | + return 0; |
|---|
| 647 | + } |
|---|
| 648 | + |
|---|
| 649 | + highest_perf = perf_caps.highest_perf; |
|---|
| 650 | + nominal_perf = perf_caps.nominal_perf; |
|---|
| 651 | + |
|---|
| 652 | + if (!highest_perf || !nominal_perf) { |
|---|
| 653 | + pr_debug("CPU%d: highest or nominal performance missing\n", cpu); |
|---|
| 654 | + return 0; |
|---|
| 655 | + } |
|---|
| 656 | + |
|---|
| 657 | + if (highest_perf < nominal_perf) { |
|---|
| 658 | + pr_debug("CPU%d: nominal performance above highest\n", cpu); |
|---|
| 659 | + return 0; |
|---|
| 660 | + } |
|---|
| 661 | + |
|---|
| 662 | + return div_u64(highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf); |
|---|
| 663 | +} |
|---|
| 664 | +#else |
|---|
| 665 | +static inline u64 get_max_boost_ratio(unsigned int cpu) { return 0; } |
|---|
| 666 | +#endif |
|---|
| 667 | + |
|---|
| 641 | 668 | static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) |
|---|
| 642 | 669 | { |
|---|
| 643 | | - unsigned int i; |
|---|
| 644 | | - unsigned int valid_states = 0; |
|---|
| 645 | | - unsigned int cpu = policy->cpu; |
|---|
| 646 | | - struct acpi_cpufreq_data *data; |
|---|
| 647 | | - unsigned int result = 0; |
|---|
| 648 | | - struct cpuinfo_x86 *c = &cpu_data(policy->cpu); |
|---|
| 649 | | - struct acpi_processor_performance *perf; |
|---|
| 650 | 670 | struct cpufreq_frequency_table *freq_table; |
|---|
| 671 | + struct acpi_processor_performance *perf; |
|---|
| 672 | + struct acpi_cpufreq_data *data; |
|---|
| 673 | + unsigned int cpu = policy->cpu; |
|---|
| 674 | + struct cpuinfo_x86 *c = &cpu_data(cpu); |
|---|
| 675 | + unsigned int valid_states = 0; |
|---|
| 676 | + unsigned int result = 0; |
|---|
| 677 | + u64 max_boost_ratio; |
|---|
| 678 | + unsigned int i; |
|---|
| 651 | 679 | #ifdef CONFIG_SMP |
|---|
| 652 | 680 | static int blacklisted; |
|---|
| 653 | 681 | #endif |
|---|
| 654 | 682 | |
|---|
| 655 | | - pr_debug("acpi_cpufreq_cpu_init\n"); |
|---|
| 683 | + pr_debug("%s\n", __func__); |
|---|
| 656 | 684 | |
|---|
| 657 | 685 | #ifdef CONFIG_SMP |
|---|
| 658 | 686 | if (blacklisted) |
|---|
| .. | .. |
|---|
| 795 | 823 | valid_states++; |
|---|
| 796 | 824 | } |
|---|
| 797 | 825 | freq_table[valid_states].frequency = CPUFREQ_TABLE_END; |
|---|
| 826 | + |
|---|
| 827 | + max_boost_ratio = get_max_boost_ratio(cpu); |
|---|
| 828 | + if (max_boost_ratio) { |
|---|
| 829 | + unsigned int freq = freq_table[0].frequency; |
|---|
| 830 | + |
|---|
| 831 | + /* |
|---|
| 832 | + * Because the loop above sorts the freq_table entries in the |
|---|
| 833 | + * descending order, freq is the maximum frequency in the table. |
|---|
| 834 | + * Assume that it corresponds to the CPPC nominal frequency and |
|---|
| 835 | + * use it to set cpuinfo.max_freq. |
|---|
| 836 | + */ |
|---|
| 837 | + policy->cpuinfo.max_freq = freq * max_boost_ratio >> SCHED_CAPACITY_SHIFT; |
|---|
| 838 | + } else { |
|---|
| 839 | + /* |
|---|
| 840 | + * If the maximum "boost" frequency is unknown, ask the arch |
|---|
| 841 | + * scale-invariance code to use the "nominal" performance for |
|---|
| 842 | + * CPU utilization scaling so as to prevent the schedutil |
|---|
| 843 | + * governor from selecting inadequate CPU frequencies. |
|---|
| 844 | + */ |
|---|
| 845 | + arch_set_max_freq_ratio(true); |
|---|
| 846 | + } |
|---|
| 847 | + |
|---|
| 798 | 848 | policy->freq_table = freq_table; |
|---|
| 799 | 849 | perf->state = 0; |
|---|
| 800 | 850 | |
|---|
| .. | .. |
|---|
| 852 | 902 | { |
|---|
| 853 | 903 | struct acpi_cpufreq_data *data = policy->driver_data; |
|---|
| 854 | 904 | |
|---|
| 855 | | - pr_debug("acpi_cpufreq_cpu_exit\n"); |
|---|
| 905 | + pr_debug("%s\n", __func__); |
|---|
| 856 | 906 | |
|---|
| 857 | 907 | policy->fast_switch_possible = false; |
|---|
| 858 | 908 | policy->driver_data = NULL; |
|---|
| .. | .. |
|---|
| 868 | 918 | { |
|---|
| 869 | 919 | struct acpi_processor_performance *perf = per_cpu_ptr(acpi_perf_data, |
|---|
| 870 | 920 | policy->cpu); |
|---|
| 921 | + unsigned int freq = policy->freq_table[0].frequency; |
|---|
| 871 | 922 | |
|---|
| 872 | | - if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq) |
|---|
| 923 | + if (perf->states[0].core_frequency * 1000 != freq) |
|---|
| 873 | 924 | pr_warn(FW_WARN "P-state 0 is not max freq\n"); |
|---|
| 874 | 925 | } |
|---|
| 875 | 926 | |
|---|
| .. | .. |
|---|
| 877 | 928 | { |
|---|
| 878 | 929 | struct acpi_cpufreq_data *data = policy->driver_data; |
|---|
| 879 | 930 | |
|---|
| 880 | | - pr_debug("acpi_cpufreq_resume\n"); |
|---|
| 931 | + pr_debug("%s\n", __func__); |
|---|
| 881 | 932 | |
|---|
| 882 | 933 | data->resume = 1; |
|---|
| 883 | 934 | |
|---|
| .. | .. |
|---|
| 950 | 1001 | if (cpufreq_get_current_driver()) |
|---|
| 951 | 1002 | return -EEXIST; |
|---|
| 952 | 1003 | |
|---|
| 953 | | - pr_debug("acpi_cpufreq_init\n"); |
|---|
| 1004 | + pr_debug("%s\n", __func__); |
|---|
| 954 | 1005 | |
|---|
| 955 | 1006 | ret = acpi_cpufreq_early_init(); |
|---|
| 956 | 1007 | if (ret) |
|---|
| .. | .. |
|---|
| 987 | 1038 | |
|---|
| 988 | 1039 | static void __exit acpi_cpufreq_exit(void) |
|---|
| 989 | 1040 | { |
|---|
| 990 | | - pr_debug("acpi_cpufreq_exit\n"); |
|---|
| 1041 | + pr_debug("%s\n", __func__); |
|---|
| 991 | 1042 | |
|---|
| 992 | 1043 | acpi_cpufreq_boost_exit(); |
|---|
| 993 | 1044 | |
|---|
| .. | .. |
|---|
| 1004 | 1055 | late_initcall(acpi_cpufreq_init); |
|---|
| 1005 | 1056 | module_exit(acpi_cpufreq_exit); |
|---|
| 1006 | 1057 | |
|---|
| 1007 | | -static const struct x86_cpu_id acpi_cpufreq_ids[] = { |
|---|
| 1008 | | - X86_FEATURE_MATCH(X86_FEATURE_ACPI), |
|---|
| 1009 | | - X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE), |
|---|
| 1058 | +static const struct x86_cpu_id __maybe_unused acpi_cpufreq_ids[] = { |
|---|
| 1059 | + X86_MATCH_FEATURE(X86_FEATURE_ACPI, NULL), |
|---|
| 1060 | + X86_MATCH_FEATURE(X86_FEATURE_HW_PSTATE, NULL), |
|---|
| 1010 | 1061 | {} |
|---|
| 1011 | 1062 | }; |
|---|
| 1012 | 1063 | MODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids); |
|---|
| 1013 | 1064 | |
|---|
| 1014 | | -static const struct acpi_device_id processor_device_ids[] = { |
|---|
| 1065 | +static const struct acpi_device_id __maybe_unused processor_device_ids[] = { |
|---|
| 1015 | 1066 | {ACPI_PROCESSOR_OBJECT_HID, }, |
|---|
| 1016 | 1067 | {ACPI_PROCESSOR_DEVICE_HID, }, |
|---|
| 1017 | 1068 | {}, |
|---|