.. | .. |
---|
| 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 | {}, |
---|