| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * processor_perflib.c - ACPI Processor P-States Library ($Revision: 71 $) |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> |
|---|
| 7 | 8 | * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> |
|---|
| 8 | 9 | * - Added processor hotplug support |
|---|
| 9 | | - * |
|---|
| 10 | | - * |
|---|
| 11 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 14 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 15 | | - * the Free Software Foundation; either version 2 of the License, or (at |
|---|
| 16 | | - * your option) any later version. |
|---|
| 17 | | - * |
|---|
| 18 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 19 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 20 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 21 | | - * General Public License for more details. |
|---|
| 22 | | - * |
|---|
| 23 | 10 | */ |
|---|
| 24 | 11 | |
|---|
| 25 | 12 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 63 | 50 | MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ |
|---|
| 64 | 51 | "limited by BIOS, this should help"); |
|---|
| 65 | 52 | |
|---|
| 66 | | -#define PPC_REGISTERED 1 |
|---|
| 67 | | -#define PPC_IN_USE 2 |
|---|
| 68 | | - |
|---|
| 69 | | -static int acpi_processor_ppc_status; |
|---|
| 70 | | - |
|---|
| 71 | | -static int acpi_processor_ppc_notifier(struct notifier_block *nb, |
|---|
| 72 | | - unsigned long event, void *data) |
|---|
| 73 | | -{ |
|---|
| 74 | | - struct cpufreq_policy *policy = data; |
|---|
| 75 | | - struct acpi_processor *pr; |
|---|
| 76 | | - unsigned int ppc = 0; |
|---|
| 77 | | - |
|---|
| 78 | | - if (ignore_ppc < 0) |
|---|
| 79 | | - ignore_ppc = 0; |
|---|
| 80 | | - |
|---|
| 81 | | - if (ignore_ppc) |
|---|
| 82 | | - return 0; |
|---|
| 83 | | - |
|---|
| 84 | | - if (event != CPUFREQ_ADJUST) |
|---|
| 85 | | - return 0; |
|---|
| 86 | | - |
|---|
| 87 | | - mutex_lock(&performance_mutex); |
|---|
| 88 | | - |
|---|
| 89 | | - pr = per_cpu(processors, policy->cpu); |
|---|
| 90 | | - if (!pr || !pr->performance) |
|---|
| 91 | | - goto out; |
|---|
| 92 | | - |
|---|
| 93 | | - ppc = (unsigned int)pr->performance_platform_limit; |
|---|
| 94 | | - |
|---|
| 95 | | - if (ppc >= pr->performance->state_count) |
|---|
| 96 | | - goto out; |
|---|
| 97 | | - |
|---|
| 98 | | - cpufreq_verify_within_limits(policy, 0, |
|---|
| 99 | | - pr->performance->states[ppc]. |
|---|
| 100 | | - core_frequency * 1000); |
|---|
| 101 | | - |
|---|
| 102 | | - out: |
|---|
| 103 | | - mutex_unlock(&performance_mutex); |
|---|
| 104 | | - |
|---|
| 105 | | - return 0; |
|---|
| 106 | | -} |
|---|
| 107 | | - |
|---|
| 108 | | -static struct notifier_block acpi_ppc_notifier_block = { |
|---|
| 109 | | - .notifier_call = acpi_processor_ppc_notifier, |
|---|
| 110 | | -}; |
|---|
| 53 | +static bool acpi_processor_ppc_in_use; |
|---|
| 111 | 54 | |
|---|
| 112 | 55 | static int acpi_processor_get_platform_limit(struct acpi_processor *pr) |
|---|
| 113 | 56 | { |
|---|
| 114 | 57 | acpi_status status = 0; |
|---|
| 115 | 58 | unsigned long long ppc = 0; |
|---|
| 116 | | - |
|---|
| 59 | + s32 qos_value; |
|---|
| 60 | + int index; |
|---|
| 61 | + int ret; |
|---|
| 117 | 62 | |
|---|
| 118 | 63 | if (!pr) |
|---|
| 119 | 64 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 125 | 70 | status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc); |
|---|
| 126 | 71 | |
|---|
| 127 | 72 | if (status != AE_NOT_FOUND) |
|---|
| 128 | | - acpi_processor_ppc_status |= PPC_IN_USE; |
|---|
| 73 | + acpi_processor_ppc_in_use = true; |
|---|
| 129 | 74 | |
|---|
| 130 | 75 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
|---|
| 131 | 76 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC")); |
|---|
| 132 | 77 | return -ENODEV; |
|---|
| 133 | 78 | } |
|---|
| 134 | 79 | |
|---|
| 135 | | - pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, |
|---|
| 136 | | - (int)ppc, ppc ? "" : "not"); |
|---|
| 80 | + index = ppc; |
|---|
| 137 | 81 | |
|---|
| 138 | | - pr->performance_platform_limit = (int)ppc; |
|---|
| 82 | + if (pr->performance_platform_limit == index || |
|---|
| 83 | + ppc >= pr->performance->state_count) |
|---|
| 84 | + return 0; |
|---|
| 85 | + |
|---|
| 86 | + pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, |
|---|
| 87 | + index, index ? "is" : "is not"); |
|---|
| 88 | + |
|---|
| 89 | + pr->performance_platform_limit = index; |
|---|
| 90 | + |
|---|
| 91 | + if (unlikely(!freq_qos_request_active(&pr->perflib_req))) |
|---|
| 92 | + return 0; |
|---|
| 93 | + |
|---|
| 94 | + /* |
|---|
| 95 | + * If _PPC returns 0, it means that all of the available states can be |
|---|
| 96 | + * used ("no limit"). |
|---|
| 97 | + */ |
|---|
| 98 | + if (index == 0) |
|---|
| 99 | + qos_value = FREQ_QOS_MAX_DEFAULT_VALUE; |
|---|
| 100 | + else |
|---|
| 101 | + qos_value = pr->performance->states[index].core_frequency * 1000; |
|---|
| 102 | + |
|---|
| 103 | + ret = freq_qos_update_request(&pr->perflib_req, qos_value); |
|---|
| 104 | + if (ret < 0) { |
|---|
| 105 | + pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n", |
|---|
| 106 | + pr->id, ret); |
|---|
| 107 | + } |
|---|
| 139 | 108 | |
|---|
| 140 | 109 | return 0; |
|---|
| 141 | 110 | } |
|---|
| .. | .. |
|---|
| 181 | 150 | acpi_processor_ppc_ost(pr->handle, 0); |
|---|
| 182 | 151 | } |
|---|
| 183 | 152 | if (ret >= 0) |
|---|
| 184 | | - cpufreq_update_policy(pr->id); |
|---|
| 153 | + cpufreq_update_limits(pr->id); |
|---|
| 185 | 154 | } |
|---|
| 186 | 155 | |
|---|
| 187 | 156 | int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) |
|---|
| .. | .. |
|---|
| 197 | 166 | } |
|---|
| 198 | 167 | EXPORT_SYMBOL(acpi_processor_get_bios_limit); |
|---|
| 199 | 168 | |
|---|
| 200 | | -void acpi_processor_ppc_init(void) |
|---|
| 169 | +void acpi_processor_ignore_ppc_init(void) |
|---|
| 201 | 170 | { |
|---|
| 202 | | - if (!cpufreq_register_notifier |
|---|
| 203 | | - (&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER)) |
|---|
| 204 | | - acpi_processor_ppc_status |= PPC_REGISTERED; |
|---|
| 205 | | - else |
|---|
| 206 | | - printk(KERN_DEBUG |
|---|
| 207 | | - "Warning: Processor Platform Limit not supported.\n"); |
|---|
| 171 | + if (ignore_ppc < 0) |
|---|
| 172 | + ignore_ppc = 0; |
|---|
| 208 | 173 | } |
|---|
| 209 | 174 | |
|---|
| 210 | | -void acpi_processor_ppc_exit(void) |
|---|
| 175 | +void acpi_processor_ppc_init(struct cpufreq_policy *policy) |
|---|
| 211 | 176 | { |
|---|
| 212 | | - if (acpi_processor_ppc_status & PPC_REGISTERED) |
|---|
| 213 | | - cpufreq_unregister_notifier(&acpi_ppc_notifier_block, |
|---|
| 214 | | - CPUFREQ_POLICY_NOTIFIER); |
|---|
| 177 | + unsigned int cpu; |
|---|
| 215 | 178 | |
|---|
| 216 | | - acpi_processor_ppc_status &= ~PPC_REGISTERED; |
|---|
| 179 | + for_each_cpu(cpu, policy->related_cpus) { |
|---|
| 180 | + struct acpi_processor *pr = per_cpu(processors, cpu); |
|---|
| 181 | + int ret; |
|---|
| 182 | + |
|---|
| 183 | + if (!pr) |
|---|
| 184 | + continue; |
|---|
| 185 | + |
|---|
| 186 | + /* |
|---|
| 187 | + * Reset performance_platform_limit in case there is a stale |
|---|
| 188 | + * value in it, so as to make it match the "no limit" QoS value |
|---|
| 189 | + * below. |
|---|
| 190 | + */ |
|---|
| 191 | + pr->performance_platform_limit = 0; |
|---|
| 192 | + |
|---|
| 193 | + ret = freq_qos_add_request(&policy->constraints, |
|---|
| 194 | + &pr->perflib_req, FREQ_QOS_MAX, |
|---|
| 195 | + FREQ_QOS_MAX_DEFAULT_VALUE); |
|---|
| 196 | + if (ret < 0) |
|---|
| 197 | + pr_err("Failed to add freq constraint for CPU%d (%d)\n", |
|---|
| 198 | + cpu, ret); |
|---|
| 199 | + } |
|---|
| 200 | +} |
|---|
| 201 | + |
|---|
| 202 | +void acpi_processor_ppc_exit(struct cpufreq_policy *policy) |
|---|
| 203 | +{ |
|---|
| 204 | + unsigned int cpu; |
|---|
| 205 | + |
|---|
| 206 | + for_each_cpu(cpu, policy->related_cpus) { |
|---|
| 207 | + struct acpi_processor *pr = per_cpu(processors, cpu); |
|---|
| 208 | + |
|---|
| 209 | + if (pr) |
|---|
| 210 | + freq_qos_remove_request(&pr->perflib_req); |
|---|
| 211 | + } |
|---|
| 217 | 212 | } |
|---|
| 218 | 213 | |
|---|
| 219 | 214 | static int acpi_processor_get_performance_control(struct acpi_processor *pr) |
|---|
| .. | .. |
|---|
| 381 | 376 | (u32) px->control, (u32) px->status)); |
|---|
| 382 | 377 | |
|---|
| 383 | 378 | /* |
|---|
| 384 | | - * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq |
|---|
| 379 | + * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq |
|---|
| 385 | 380 | */ |
|---|
| 386 | 381 | if (!px->core_frequency || |
|---|
| 387 | 382 | ((u32)(px->core_frequency * 1000) != |
|---|
| .. | .. |
|---|
| 490 | 485 | static int is_done = 0; |
|---|
| 491 | 486 | int result; |
|---|
| 492 | 487 | |
|---|
| 493 | | - if (!(acpi_processor_ppc_status & PPC_REGISTERED)) |
|---|
| 488 | + if (!acpi_processor_cpufreq_init) |
|---|
| 494 | 489 | return -EBUSY; |
|---|
| 495 | 490 | |
|---|
| 496 | 491 | if (!try_module_get(calling_module)) |
|---|
| .. | .. |
|---|
| 526 | 521 | * we can allow the cpufreq driver to be rmmod'ed. */ |
|---|
| 527 | 522 | is_done = 1; |
|---|
| 528 | 523 | |
|---|
| 529 | | - if (!(acpi_processor_ppc_status & PPC_IN_USE)) |
|---|
| 524 | + if (!acpi_processor_ppc_in_use) |
|---|
| 530 | 525 | module_put(calling_module); |
|---|
| 531 | 526 | |
|---|
| 532 | 527 | return 0; |
|---|
| .. | .. |
|---|
| 654 | 649 | goto err_ret; |
|---|
| 655 | 650 | |
|---|
| 656 | 651 | /* |
|---|
| 657 | | - * Now that we have _PSD data from all CPUs, lets setup P-state |
|---|
| 652 | + * Now that we have _PSD data from all CPUs, lets setup P-state |
|---|
| 658 | 653 | * domain info. |
|---|
| 659 | 654 | */ |
|---|
| 660 | 655 | for_each_possible_cpu(i) { |
|---|
| .. | .. |
|---|
| 720 | 715 | if (match_pdomain->domain != pdomain->domain) |
|---|
| 721 | 716 | continue; |
|---|
| 722 | 717 | |
|---|
| 723 | | - match_pr->performance->shared_type = |
|---|
| 718 | + match_pr->performance->shared_type = |
|---|
| 724 | 719 | pr->performance->shared_type; |
|---|
| 725 | 720 | cpumask_copy(match_pr->performance->shared_cpu_map, |
|---|
| 726 | 721 | pr->performance->shared_cpu_map); |
|---|
| .. | .. |
|---|
| 755 | 750 | { |
|---|
| 756 | 751 | struct acpi_processor *pr; |
|---|
| 757 | 752 | |
|---|
| 758 | | - if (!(acpi_processor_ppc_status & PPC_REGISTERED)) |
|---|
| 753 | + if (!acpi_processor_cpufreq_init) |
|---|
| 759 | 754 | return -EINVAL; |
|---|
| 760 | 755 | |
|---|
| 761 | 756 | mutex_lock(&performance_mutex); |
|---|