| .. | .. |
|---|
| 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 | + int ret; |
|---|
| 117 | 60 | |
|---|
| 118 | 61 | if (!pr) |
|---|
| 119 | 62 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 125 | 68 | status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc); |
|---|
| 126 | 69 | |
|---|
| 127 | 70 | if (status != AE_NOT_FOUND) |
|---|
| 128 | | - acpi_processor_ppc_status |= PPC_IN_USE; |
|---|
| 71 | + acpi_processor_ppc_in_use = true; |
|---|
| 129 | 72 | |
|---|
| 130 | 73 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
|---|
| 131 | 74 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC")); |
|---|
| .. | .. |
|---|
| 136 | 79 | (int)ppc, ppc ? "" : "not"); |
|---|
| 137 | 80 | |
|---|
| 138 | 81 | pr->performance_platform_limit = (int)ppc; |
|---|
| 82 | + |
|---|
| 83 | + if (ppc >= pr->performance->state_count || |
|---|
| 84 | + unlikely(!freq_qos_request_active(&pr->perflib_req))) |
|---|
| 85 | + return 0; |
|---|
| 86 | + |
|---|
| 87 | + ret = freq_qos_update_request(&pr->perflib_req, |
|---|
| 88 | + pr->performance->states[ppc].core_frequency * 1000); |
|---|
| 89 | + if (ret < 0) { |
|---|
| 90 | + pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n", |
|---|
| 91 | + pr->id, ret); |
|---|
| 92 | + } |
|---|
| 139 | 93 | |
|---|
| 140 | 94 | return 0; |
|---|
| 141 | 95 | } |
|---|
| .. | .. |
|---|
| 181 | 135 | acpi_processor_ppc_ost(pr->handle, 0); |
|---|
| 182 | 136 | } |
|---|
| 183 | 137 | if (ret >= 0) |
|---|
| 184 | | - cpufreq_update_policy(pr->id); |
|---|
| 138 | + cpufreq_update_limits(pr->id); |
|---|
| 185 | 139 | } |
|---|
| 186 | 140 | |
|---|
| 187 | 141 | int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) |
|---|
| .. | .. |
|---|
| 197 | 151 | } |
|---|
| 198 | 152 | EXPORT_SYMBOL(acpi_processor_get_bios_limit); |
|---|
| 199 | 153 | |
|---|
| 200 | | -void acpi_processor_ppc_init(void) |
|---|
| 154 | +void acpi_processor_ignore_ppc_init(void) |
|---|
| 201 | 155 | { |
|---|
| 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"); |
|---|
| 156 | + if (ignore_ppc < 0) |
|---|
| 157 | + ignore_ppc = 0; |
|---|
| 208 | 158 | } |
|---|
| 209 | 159 | |
|---|
| 210 | | -void acpi_processor_ppc_exit(void) |
|---|
| 160 | +void acpi_processor_ppc_init(struct cpufreq_policy *policy) |
|---|
| 211 | 161 | { |
|---|
| 212 | | - if (acpi_processor_ppc_status & PPC_REGISTERED) |
|---|
| 213 | | - cpufreq_unregister_notifier(&acpi_ppc_notifier_block, |
|---|
| 214 | | - CPUFREQ_POLICY_NOTIFIER); |
|---|
| 162 | + unsigned int cpu; |
|---|
| 215 | 163 | |
|---|
| 216 | | - acpi_processor_ppc_status &= ~PPC_REGISTERED; |
|---|
| 164 | + for_each_cpu(cpu, policy->related_cpus) { |
|---|
| 165 | + struct acpi_processor *pr = per_cpu(processors, cpu); |
|---|
| 166 | + int ret; |
|---|
| 167 | + |
|---|
| 168 | + if (!pr) |
|---|
| 169 | + continue; |
|---|
| 170 | + |
|---|
| 171 | + ret = freq_qos_add_request(&policy->constraints, |
|---|
| 172 | + &pr->perflib_req, |
|---|
| 173 | + FREQ_QOS_MAX, INT_MAX); |
|---|
| 174 | + if (ret < 0) |
|---|
| 175 | + pr_err("Failed to add freq constraint for CPU%d (%d)\n", |
|---|
| 176 | + cpu, ret); |
|---|
| 177 | + } |
|---|
| 178 | +} |
|---|
| 179 | + |
|---|
| 180 | +void acpi_processor_ppc_exit(struct cpufreq_policy *policy) |
|---|
| 181 | +{ |
|---|
| 182 | + unsigned int cpu; |
|---|
| 183 | + |
|---|
| 184 | + for_each_cpu(cpu, policy->related_cpus) { |
|---|
| 185 | + struct acpi_processor *pr = per_cpu(processors, cpu); |
|---|
| 186 | + |
|---|
| 187 | + if (pr) |
|---|
| 188 | + freq_qos_remove_request(&pr->perflib_req); |
|---|
| 189 | + } |
|---|
| 217 | 190 | } |
|---|
| 218 | 191 | |
|---|
| 219 | 192 | static int acpi_processor_get_performance_control(struct acpi_processor *pr) |
|---|
| .. | .. |
|---|
| 381 | 354 | (u32) px->control, (u32) px->status)); |
|---|
| 382 | 355 | |
|---|
| 383 | 356 | /* |
|---|
| 384 | | - * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq |
|---|
| 357 | + * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq |
|---|
| 385 | 358 | */ |
|---|
| 386 | 359 | if (!px->core_frequency || |
|---|
| 387 | 360 | ((u32)(px->core_frequency * 1000) != |
|---|
| .. | .. |
|---|
| 490 | 463 | static int is_done = 0; |
|---|
| 491 | 464 | int result; |
|---|
| 492 | 465 | |
|---|
| 493 | | - if (!(acpi_processor_ppc_status & PPC_REGISTERED)) |
|---|
| 466 | + if (!acpi_processor_cpufreq_init) |
|---|
| 494 | 467 | return -EBUSY; |
|---|
| 495 | 468 | |
|---|
| 496 | 469 | if (!try_module_get(calling_module)) |
|---|
| .. | .. |
|---|
| 526 | 499 | * we can allow the cpufreq driver to be rmmod'ed. */ |
|---|
| 527 | 500 | is_done = 1; |
|---|
| 528 | 501 | |
|---|
| 529 | | - if (!(acpi_processor_ppc_status & PPC_IN_USE)) |
|---|
| 502 | + if (!acpi_processor_ppc_in_use) |
|---|
| 530 | 503 | module_put(calling_module); |
|---|
| 531 | 504 | |
|---|
| 532 | 505 | return 0; |
|---|
| .. | .. |
|---|
| 654 | 627 | goto err_ret; |
|---|
| 655 | 628 | |
|---|
| 656 | 629 | /* |
|---|
| 657 | | - * Now that we have _PSD data from all CPUs, lets setup P-state |
|---|
| 630 | + * Now that we have _PSD data from all CPUs, lets setup P-state |
|---|
| 658 | 631 | * domain info. |
|---|
| 659 | 632 | */ |
|---|
| 660 | 633 | for_each_possible_cpu(i) { |
|---|
| .. | .. |
|---|
| 720 | 693 | if (match_pdomain->domain != pdomain->domain) |
|---|
| 721 | 694 | continue; |
|---|
| 722 | 695 | |
|---|
| 723 | | - match_pr->performance->shared_type = |
|---|
| 696 | + match_pr->performance->shared_type = |
|---|
| 724 | 697 | pr->performance->shared_type; |
|---|
| 725 | 698 | cpumask_copy(match_pr->performance->shared_cpu_map, |
|---|
| 726 | 699 | pr->performance->shared_cpu_map); |
|---|
| .. | .. |
|---|
| 755 | 728 | { |
|---|
| 756 | 729 | struct acpi_processor *pr; |
|---|
| 757 | 730 | |
|---|
| 758 | | - if (!(acpi_processor_ppc_status & PPC_REGISTERED)) |
|---|
| 731 | + if (!acpi_processor_cpufreq_init) |
|---|
| 759 | 732 | return -EINVAL; |
|---|
| 760 | 733 | |
|---|
| 761 | 734 | mutex_lock(&performance_mutex); |
|---|