18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * acpi-cpufreq.c - ACPI Processor P-States Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
68c2ecf20Sopenharmony_ci *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
78c2ecf20Sopenharmony_ci *  Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
88c2ecf20Sopenharmony_ci *  Copyright (C) 2006       Denis Sadykov <denis.m.sadykov@intel.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/smp.h>
178c2ecf20Sopenharmony_ci#include <linux/sched.h>
188c2ecf20Sopenharmony_ci#include <linux/cpufreq.h>
198c2ecf20Sopenharmony_ci#include <linux/compiler.h>
208c2ecf20Sopenharmony_ci#include <linux/dmi.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <linux/acpi.h>
248c2ecf20Sopenharmony_ci#include <linux/io.h>
258c2ecf20Sopenharmony_ci#include <linux/delay.h>
268c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <acpi/processor.h>
298c2ecf20Sopenharmony_ci#include <acpi/cppc_acpi.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <asm/msr.h>
328c2ecf20Sopenharmony_ci#include <asm/processor.h>
338c2ecf20Sopenharmony_ci#include <asm/cpufeature.h>
348c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ACPI Processor P-States Driver");
388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cienum {
418c2ecf20Sopenharmony_ci	UNDEFINED_CAPABLE = 0,
428c2ecf20Sopenharmony_ci	SYSTEM_INTEL_MSR_CAPABLE,
438c2ecf20Sopenharmony_ci	SYSTEM_AMD_MSR_CAPABLE,
448c2ecf20Sopenharmony_ci	SYSTEM_IO_CAPABLE,
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define INTEL_MSR_RANGE		(0xffff)
488c2ecf20Sopenharmony_ci#define AMD_MSR_RANGE		(0x7)
498c2ecf20Sopenharmony_ci#define HYGON_MSR_RANGE		(0x7)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define MSR_K7_HWCR_CPB_DIS	(1ULL << 25)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistruct acpi_cpufreq_data {
548c2ecf20Sopenharmony_ci	unsigned int resume;
558c2ecf20Sopenharmony_ci	unsigned int cpu_feature;
568c2ecf20Sopenharmony_ci	unsigned int acpi_perf_cpu;
578c2ecf20Sopenharmony_ci	cpumask_var_t freqdomain_cpus;
588c2ecf20Sopenharmony_ci	void (*cpu_freq_write)(struct acpi_pct_register *reg, u32 val);
598c2ecf20Sopenharmony_ci	u32 (*cpu_freq_read)(struct acpi_pct_register *reg);
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* acpi_perf_data is a pointer to percpu data. */
638c2ecf20Sopenharmony_cistatic struct acpi_processor_performance __percpu *acpi_perf_data;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic inline struct acpi_processor_performance *to_perf_data(struct acpi_cpufreq_data *data)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	return per_cpu_ptr(acpi_perf_data, data->acpi_perf_cpu);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic struct cpufreq_driver acpi_cpufreq_driver;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic unsigned int acpi_pstate_strict;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic bool boost_state(unsigned int cpu)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	u32 lo, hi;
778c2ecf20Sopenharmony_ci	u64 msr;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	switch (boot_cpu_data.x86_vendor) {
808c2ecf20Sopenharmony_ci	case X86_VENDOR_INTEL:
818c2ecf20Sopenharmony_ci		rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi);
828c2ecf20Sopenharmony_ci		msr = lo | ((u64)hi << 32);
838c2ecf20Sopenharmony_ci		return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
848c2ecf20Sopenharmony_ci	case X86_VENDOR_HYGON:
858c2ecf20Sopenharmony_ci	case X86_VENDOR_AMD:
868c2ecf20Sopenharmony_ci		rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
878c2ecf20Sopenharmony_ci		msr = lo | ((u64)hi << 32);
888c2ecf20Sopenharmony_ci		return !(msr & MSR_K7_HWCR_CPB_DIS);
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	return false;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int boost_set_msr(bool enable)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	u32 msr_addr;
968c2ecf20Sopenharmony_ci	u64 msr_mask, val;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	switch (boot_cpu_data.x86_vendor) {
998c2ecf20Sopenharmony_ci	case X86_VENDOR_INTEL:
1008c2ecf20Sopenharmony_ci		msr_addr = MSR_IA32_MISC_ENABLE;
1018c2ecf20Sopenharmony_ci		msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
1028c2ecf20Sopenharmony_ci		break;
1038c2ecf20Sopenharmony_ci	case X86_VENDOR_HYGON:
1048c2ecf20Sopenharmony_ci	case X86_VENDOR_AMD:
1058c2ecf20Sopenharmony_ci		msr_addr = MSR_K7_HWCR;
1068c2ecf20Sopenharmony_ci		msr_mask = MSR_K7_HWCR_CPB_DIS;
1078c2ecf20Sopenharmony_ci		break;
1088c2ecf20Sopenharmony_ci	default:
1098c2ecf20Sopenharmony_ci		return -EINVAL;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	rdmsrl(msr_addr, val);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (enable)
1158c2ecf20Sopenharmony_ci		val &= ~msr_mask;
1168c2ecf20Sopenharmony_ci	else
1178c2ecf20Sopenharmony_ci		val |= msr_mask;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	wrmsrl(msr_addr, val);
1208c2ecf20Sopenharmony_ci	return 0;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic void boost_set_msr_each(void *p_en)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	bool enable = (bool) p_en;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	boost_set_msr(enable);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int set_boost(struct cpufreq_policy *policy, int val)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	on_each_cpu_mask(policy->cpus, boost_set_msr_each,
1338c2ecf20Sopenharmony_ci			 (void *)(long)val, 1);
1348c2ecf20Sopenharmony_ci	pr_debug("CPU %*pbl: Core Boosting %sabled.\n",
1358c2ecf20Sopenharmony_ci		 cpumask_pr_args(policy->cpus), val ? "en" : "dis");
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return 0;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (unlikely(!data))
1458c2ecf20Sopenharmony_ci		return -ENODEV;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return cpufreq_show_cpus(data->freqdomain_cpus, buf);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cicpufreq_freq_attr_ro(freqdomain_cpus);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
1538c2ecf20Sopenharmony_cistatic ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
1548c2ecf20Sopenharmony_ci			 size_t count)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	int ret;
1578c2ecf20Sopenharmony_ci	unsigned int val = 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (!acpi_cpufreq_driver.set_boost)
1608c2ecf20Sopenharmony_ci		return -EINVAL;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	ret = kstrtouint(buf, 10, &val);
1638c2ecf20Sopenharmony_ci	if (ret || val > 1)
1648c2ecf20Sopenharmony_ci		return -EINVAL;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	get_online_cpus();
1678c2ecf20Sopenharmony_ci	set_boost(policy, val);
1688c2ecf20Sopenharmony_ci	put_online_cpus();
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return count;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cicpufreq_freq_attr_rw(cpb);
1798c2ecf20Sopenharmony_ci#endif
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int check_est_cpu(unsigned int cpuid)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct cpuinfo_x86 *cpu = &cpu_data(cpuid);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return cpu_has(cpu, X86_FEATURE_EST);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int check_amd_hwpstate_cpu(unsigned int cpuid)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct cpuinfo_x86 *cpu = &cpu_data(cpuid);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return cpu_has(cpu, X86_FEATURE_HW_PSTATE);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic unsigned extract_io(struct cpufreq_policy *policy, u32 value)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
1988c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf;
1998c2ecf20Sopenharmony_ci	int i;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	perf = to_perf_data(data);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	for (i = 0; i < perf->state_count; i++) {
2048c2ecf20Sopenharmony_ci		if (value == perf->states[i].status)
2058c2ecf20Sopenharmony_ci			return policy->freq_table[i].frequency;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci	return 0;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic unsigned extract_msr(struct cpufreq_policy *policy, u32 msr)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
2138c2ecf20Sopenharmony_ci	struct cpufreq_frequency_table *pos;
2148c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
2178c2ecf20Sopenharmony_ci		msr &= AMD_MSR_RANGE;
2188c2ecf20Sopenharmony_ci	else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
2198c2ecf20Sopenharmony_ci		msr &= HYGON_MSR_RANGE;
2208c2ecf20Sopenharmony_ci	else
2218c2ecf20Sopenharmony_ci		msr &= INTEL_MSR_RANGE;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	perf = to_perf_data(data);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	cpufreq_for_each_entry(pos, policy->freq_table)
2268c2ecf20Sopenharmony_ci		if (msr == perf->states[pos->driver_data].status)
2278c2ecf20Sopenharmony_ci			return pos->frequency;
2288c2ecf20Sopenharmony_ci	return policy->freq_table[0].frequency;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic unsigned extract_freq(struct cpufreq_policy *policy, u32 val)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	switch (data->cpu_feature) {
2368c2ecf20Sopenharmony_ci	case SYSTEM_INTEL_MSR_CAPABLE:
2378c2ecf20Sopenharmony_ci	case SYSTEM_AMD_MSR_CAPABLE:
2388c2ecf20Sopenharmony_ci		return extract_msr(policy, val);
2398c2ecf20Sopenharmony_ci	case SYSTEM_IO_CAPABLE:
2408c2ecf20Sopenharmony_ci		return extract_io(policy, val);
2418c2ecf20Sopenharmony_ci	default:
2428c2ecf20Sopenharmony_ci		return 0;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic u32 cpu_freq_read_intel(struct acpi_pct_register *not_used)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u32 val, dummy __always_unused;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	rdmsr(MSR_IA32_PERF_CTL, val, dummy);
2518c2ecf20Sopenharmony_ci	return val;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void cpu_freq_write_intel(struct acpi_pct_register *not_used, u32 val)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	u32 lo, hi;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	rdmsr(MSR_IA32_PERF_CTL, lo, hi);
2598c2ecf20Sopenharmony_ci	lo = (lo & ~INTEL_MSR_RANGE) | (val & INTEL_MSR_RANGE);
2608c2ecf20Sopenharmony_ci	wrmsr(MSR_IA32_PERF_CTL, lo, hi);
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic u32 cpu_freq_read_amd(struct acpi_pct_register *not_used)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	u32 val, dummy __always_unused;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	rdmsr(MSR_AMD_PERF_CTL, val, dummy);
2688c2ecf20Sopenharmony_ci	return val;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic void cpu_freq_write_amd(struct acpi_pct_register *not_used, u32 val)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	wrmsr(MSR_AMD_PERF_CTL, val, 0);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic u32 cpu_freq_read_io(struct acpi_pct_register *reg)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	u32 val;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	acpi_os_read_port(reg->address, &val, reg->bit_width);
2818c2ecf20Sopenharmony_ci	return val;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic void cpu_freq_write_io(struct acpi_pct_register *reg, u32 val)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	acpi_os_write_port(reg->address, val, reg->bit_width);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistruct drv_cmd {
2908c2ecf20Sopenharmony_ci	struct acpi_pct_register *reg;
2918c2ecf20Sopenharmony_ci	u32 val;
2928c2ecf20Sopenharmony_ci	union {
2938c2ecf20Sopenharmony_ci		void (*write)(struct acpi_pct_register *reg, u32 val);
2948c2ecf20Sopenharmony_ci		u32 (*read)(struct acpi_pct_register *reg);
2958c2ecf20Sopenharmony_ci	} func;
2968c2ecf20Sopenharmony_ci};
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/* Called via smp_call_function_single(), on the target CPU */
2998c2ecf20Sopenharmony_cistatic void do_drv_read(void *_cmd)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct drv_cmd *cmd = _cmd;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	cmd->val = cmd->func.read(cmd->reg);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic u32 drv_read(struct acpi_cpufreq_data *data, const struct cpumask *mask)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf = to_perf_data(data);
3098c2ecf20Sopenharmony_ci	struct drv_cmd cmd = {
3108c2ecf20Sopenharmony_ci		.reg = &perf->control_register,
3118c2ecf20Sopenharmony_ci		.func.read = data->cpu_freq_read,
3128c2ecf20Sopenharmony_ci	};
3138c2ecf20Sopenharmony_ci	int err;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	err = smp_call_function_any(mask, do_drv_read, &cmd, 1);
3168c2ecf20Sopenharmony_ci	WARN_ON_ONCE(err);	/* smp_call_function_any() was buggy? */
3178c2ecf20Sopenharmony_ci	return cmd.val;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci/* Called via smp_call_function_many(), on the target CPUs */
3218c2ecf20Sopenharmony_cistatic void do_drv_write(void *_cmd)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct drv_cmd *cmd = _cmd;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	cmd->func.write(cmd->reg, cmd->val);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic void drv_write(struct acpi_cpufreq_data *data,
3298c2ecf20Sopenharmony_ci		      const struct cpumask *mask, u32 val)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf = to_perf_data(data);
3328c2ecf20Sopenharmony_ci	struct drv_cmd cmd = {
3338c2ecf20Sopenharmony_ci		.reg = &perf->control_register,
3348c2ecf20Sopenharmony_ci		.val = val,
3358c2ecf20Sopenharmony_ci		.func.write = data->cpu_freq_write,
3368c2ecf20Sopenharmony_ci	};
3378c2ecf20Sopenharmony_ci	int this_cpu;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	this_cpu = get_cpu();
3408c2ecf20Sopenharmony_ci	if (cpumask_test_cpu(this_cpu, mask))
3418c2ecf20Sopenharmony_ci		do_drv_write(&cmd);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	smp_call_function_many(mask, do_drv_write, &cmd, 1);
3448c2ecf20Sopenharmony_ci	put_cpu();
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic u32 get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	u32 val;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (unlikely(cpumask_empty(mask)))
3528c2ecf20Sopenharmony_ci		return 0;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	val = drv_read(data, mask);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	pr_debug("%s = %u\n", __func__, val);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	return val;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic unsigned int get_cur_freq_on_cpu(unsigned int cpu)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data;
3648c2ecf20Sopenharmony_ci	struct cpufreq_policy *policy;
3658c2ecf20Sopenharmony_ci	unsigned int freq;
3668c2ecf20Sopenharmony_ci	unsigned int cached_freq;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	pr_debug("%s (%d)\n", __func__, cpu);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	policy = cpufreq_cpu_get_raw(cpu);
3718c2ecf20Sopenharmony_ci	if (unlikely(!policy))
3728c2ecf20Sopenharmony_ci		return 0;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	data = policy->driver_data;
3758c2ecf20Sopenharmony_ci	if (unlikely(!data || !policy->freq_table))
3768c2ecf20Sopenharmony_ci		return 0;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	cached_freq = policy->freq_table[to_perf_data(data)->state].frequency;
3798c2ecf20Sopenharmony_ci	freq = extract_freq(policy, get_cur_val(cpumask_of(cpu), data));
3808c2ecf20Sopenharmony_ci	if (freq != cached_freq) {
3818c2ecf20Sopenharmony_ci		/*
3828c2ecf20Sopenharmony_ci		 * The dreaded BIOS frequency change behind our back.
3838c2ecf20Sopenharmony_ci		 * Force set the frequency on next target call.
3848c2ecf20Sopenharmony_ci		 */
3858c2ecf20Sopenharmony_ci		data->resume = 1;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	pr_debug("cur freq = %u\n", freq);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return freq;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic unsigned int check_freqs(struct cpufreq_policy *policy,
3948c2ecf20Sopenharmony_ci				const struct cpumask *mask, unsigned int freq)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
3978c2ecf20Sopenharmony_ci	unsigned int cur_freq;
3988c2ecf20Sopenharmony_ci	unsigned int i;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	for (i = 0; i < 100; i++) {
4018c2ecf20Sopenharmony_ci		cur_freq = extract_freq(policy, get_cur_val(mask, data));
4028c2ecf20Sopenharmony_ci		if (cur_freq == freq)
4038c2ecf20Sopenharmony_ci			return 1;
4048c2ecf20Sopenharmony_ci		udelay(10);
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci	return 0;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int acpi_cpufreq_target(struct cpufreq_policy *policy,
4108c2ecf20Sopenharmony_ci			       unsigned int index)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
4138c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf;
4148c2ecf20Sopenharmony_ci	const struct cpumask *mask;
4158c2ecf20Sopenharmony_ci	unsigned int next_perf_state = 0; /* Index into perf table */
4168c2ecf20Sopenharmony_ci	int result = 0;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (unlikely(!data)) {
4198c2ecf20Sopenharmony_ci		return -ENODEV;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	perf = to_perf_data(data);
4238c2ecf20Sopenharmony_ci	next_perf_state = policy->freq_table[index].driver_data;
4248c2ecf20Sopenharmony_ci	if (perf->state == next_perf_state) {
4258c2ecf20Sopenharmony_ci		if (unlikely(data->resume)) {
4268c2ecf20Sopenharmony_ci			pr_debug("Called after resume, resetting to P%d\n",
4278c2ecf20Sopenharmony_ci				next_perf_state);
4288c2ecf20Sopenharmony_ci			data->resume = 0;
4298c2ecf20Sopenharmony_ci		} else {
4308c2ecf20Sopenharmony_ci			pr_debug("Already at target state (P%d)\n",
4318c2ecf20Sopenharmony_ci				next_perf_state);
4328c2ecf20Sopenharmony_ci			return 0;
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/*
4378c2ecf20Sopenharmony_ci	 * The core won't allow CPUs to go away until the governor has been
4388c2ecf20Sopenharmony_ci	 * stopped, so we can rely on the stability of policy->cpus.
4398c2ecf20Sopenharmony_ci	 */
4408c2ecf20Sopenharmony_ci	mask = policy->shared_type == CPUFREQ_SHARED_TYPE_ANY ?
4418c2ecf20Sopenharmony_ci		cpumask_of(policy->cpu) : policy->cpus;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	drv_write(data, mask, perf->states[next_perf_state].control);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (acpi_pstate_strict) {
4468c2ecf20Sopenharmony_ci		if (!check_freqs(policy, mask,
4478c2ecf20Sopenharmony_ci				 policy->freq_table[index].frequency)) {
4488c2ecf20Sopenharmony_ci			pr_debug("%s (%d)\n", __func__, policy->cpu);
4498c2ecf20Sopenharmony_ci			result = -EAGAIN;
4508c2ecf20Sopenharmony_ci		}
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (!result)
4548c2ecf20Sopenharmony_ci		perf->state = next_perf_state;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	return result;
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy,
4608c2ecf20Sopenharmony_ci					     unsigned int target_freq)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
4638c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf;
4648c2ecf20Sopenharmony_ci	struct cpufreq_frequency_table *entry;
4658c2ecf20Sopenharmony_ci	unsigned int next_perf_state, next_freq, index;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/*
4688c2ecf20Sopenharmony_ci	 * Find the closest frequency above target_freq.
4698c2ecf20Sopenharmony_ci	 */
4708c2ecf20Sopenharmony_ci	if (policy->cached_target_freq == target_freq)
4718c2ecf20Sopenharmony_ci		index = policy->cached_resolved_idx;
4728c2ecf20Sopenharmony_ci	else
4738c2ecf20Sopenharmony_ci		index = cpufreq_table_find_index_dl(policy, target_freq);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	entry = &policy->freq_table[index];
4768c2ecf20Sopenharmony_ci	next_freq = entry->frequency;
4778c2ecf20Sopenharmony_ci	next_perf_state = entry->driver_data;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	perf = to_perf_data(data);
4808c2ecf20Sopenharmony_ci	if (perf->state == next_perf_state) {
4818c2ecf20Sopenharmony_ci		if (unlikely(data->resume))
4828c2ecf20Sopenharmony_ci			data->resume = 0;
4838c2ecf20Sopenharmony_ci		else
4848c2ecf20Sopenharmony_ci			return next_freq;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	data->cpu_freq_write(&perf->control_register,
4888c2ecf20Sopenharmony_ci			     perf->states[next_perf_state].control);
4898c2ecf20Sopenharmony_ci	perf->state = next_perf_state;
4908c2ecf20Sopenharmony_ci	return next_freq;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic unsigned long
4948c2ecf20Sopenharmony_ciacpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	perf = to_perf_data(data);
4998c2ecf20Sopenharmony_ci	if (cpu_khz) {
5008c2ecf20Sopenharmony_ci		/* search the closest match to cpu_khz */
5018c2ecf20Sopenharmony_ci		unsigned int i;
5028c2ecf20Sopenharmony_ci		unsigned long freq;
5038c2ecf20Sopenharmony_ci		unsigned long freqn = perf->states[0].core_frequency * 1000;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		for (i = 0; i < (perf->state_count-1); i++) {
5068c2ecf20Sopenharmony_ci			freq = freqn;
5078c2ecf20Sopenharmony_ci			freqn = perf->states[i+1].core_frequency * 1000;
5088c2ecf20Sopenharmony_ci			if ((2 * cpu_khz) > (freqn + freq)) {
5098c2ecf20Sopenharmony_ci				perf->state = i;
5108c2ecf20Sopenharmony_ci				return freq;
5118c2ecf20Sopenharmony_ci			}
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci		perf->state = perf->state_count-1;
5148c2ecf20Sopenharmony_ci		return freqn;
5158c2ecf20Sopenharmony_ci	} else {
5168c2ecf20Sopenharmony_ci		/* assume CPU is at P0... */
5178c2ecf20Sopenharmony_ci		perf->state = 0;
5188c2ecf20Sopenharmony_ci		return perf->states[0].core_frequency * 1000;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic void free_acpi_perf_data(void)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	unsigned int i;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */
5278c2ecf20Sopenharmony_ci	for_each_possible_cpu(i)
5288c2ecf20Sopenharmony_ci		free_cpumask_var(per_cpu_ptr(acpi_perf_data, i)
5298c2ecf20Sopenharmony_ci				 ->shared_cpu_map);
5308c2ecf20Sopenharmony_ci	free_percpu(acpi_perf_data);
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic int cpufreq_boost_online(unsigned int cpu)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	/*
5368c2ecf20Sopenharmony_ci	 * On the CPU_UP path we simply keep the boost-disable flag
5378c2ecf20Sopenharmony_ci	 * in sync with the current global state.
5388c2ecf20Sopenharmony_ci	 */
5398c2ecf20Sopenharmony_ci	return boost_set_msr(acpi_cpufreq_driver.boost_enabled);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic int cpufreq_boost_down_prep(unsigned int cpu)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	/*
5458c2ecf20Sopenharmony_ci	 * Clear the boost-disable bit on the CPU_DOWN path so that
5468c2ecf20Sopenharmony_ci	 * this cpu cannot block the remaining ones from boosting.
5478c2ecf20Sopenharmony_ci	 */
5488c2ecf20Sopenharmony_ci	return boost_set_msr(1);
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci/*
5528c2ecf20Sopenharmony_ci * acpi_cpufreq_early_init - initialize ACPI P-States library
5538c2ecf20Sopenharmony_ci *
5548c2ecf20Sopenharmony_ci * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c)
5558c2ecf20Sopenharmony_ci * in order to determine correct frequency and voltage pairings. We can
5568c2ecf20Sopenharmony_ci * do _PDC and _PSD and find out the processor dependency for the
5578c2ecf20Sopenharmony_ci * actual init that will happen later...
5588c2ecf20Sopenharmony_ci */
5598c2ecf20Sopenharmony_cistatic int __init acpi_cpufreq_early_init(void)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	unsigned int i;
5628c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	acpi_perf_data = alloc_percpu(struct acpi_processor_performance);
5658c2ecf20Sopenharmony_ci	if (!acpi_perf_data) {
5668c2ecf20Sopenharmony_ci		pr_debug("Memory allocation error for acpi_perf_data.\n");
5678c2ecf20Sopenharmony_ci		return -ENOMEM;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
5708c2ecf20Sopenharmony_ci		if (!zalloc_cpumask_var_node(
5718c2ecf20Sopenharmony_ci			&per_cpu_ptr(acpi_perf_data, i)->shared_cpu_map,
5728c2ecf20Sopenharmony_ci			GFP_KERNEL, cpu_to_node(i))) {
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci			/* Freeing a NULL pointer is OK: alloc_percpu zeroes. */
5758c2ecf20Sopenharmony_ci			free_acpi_perf_data();
5768c2ecf20Sopenharmony_ci			return -ENOMEM;
5778c2ecf20Sopenharmony_ci		}
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/* Do initialization in ACPI core */
5818c2ecf20Sopenharmony_ci	acpi_processor_preregister_performance(acpi_perf_data);
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
5868c2ecf20Sopenharmony_ci/*
5878c2ecf20Sopenharmony_ci * Some BIOSes do SW_ANY coordination internally, either set it up in hw
5888c2ecf20Sopenharmony_ci * or do it in BIOS firmware and won't inform about it to OS. If not
5898c2ecf20Sopenharmony_ci * detected, this has a side effect of making CPU run at a different speed
5908c2ecf20Sopenharmony_ci * than OS intended it to run at. Detect it and handle it cleanly.
5918c2ecf20Sopenharmony_ci */
5928c2ecf20Sopenharmony_cistatic int bios_with_sw_any_bug;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cistatic int sw_any_bug_found(const struct dmi_system_id *d)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	bios_with_sw_any_bug = 1;
5978c2ecf20Sopenharmony_ci	return 0;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic const struct dmi_system_id sw_any_bug_dmi_table[] = {
6018c2ecf20Sopenharmony_ci	{
6028c2ecf20Sopenharmony_ci		.callback = sw_any_bug_found,
6038c2ecf20Sopenharmony_ci		.ident = "Supermicro Server X6DLP",
6048c2ecf20Sopenharmony_ci		.matches = {
6058c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
6068c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "080010"),
6078c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
6088c2ecf20Sopenharmony_ci		},
6098c2ecf20Sopenharmony_ci	},
6108c2ecf20Sopenharmony_ci	{ }
6118c2ecf20Sopenharmony_ci};
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	/* Intel Xeon Processor 7100 Series Specification Update
6168c2ecf20Sopenharmony_ci	 * https://www.intel.com/Assets/PDF/specupdate/314554.pdf
6178c2ecf20Sopenharmony_ci	 * AL30: A Machine Check Exception (MCE) Occurring during an
6188c2ecf20Sopenharmony_ci	 * Enhanced Intel SpeedStep Technology Ratio Change May Cause
6198c2ecf20Sopenharmony_ci	 * Both Processor Cores to Lock Up. */
6208c2ecf20Sopenharmony_ci	if (c->x86_vendor == X86_VENDOR_INTEL) {
6218c2ecf20Sopenharmony_ci		if ((c->x86 == 15) &&
6228c2ecf20Sopenharmony_ci		    (c->x86_model == 6) &&
6238c2ecf20Sopenharmony_ci		    (c->x86_stepping == 8)) {
6248c2ecf20Sopenharmony_ci			pr_info("Intel(R) Xeon(R) 7100 Errata AL30, processors may lock up on frequency changes: disabling acpi-cpufreq\n");
6258c2ecf20Sopenharmony_ci			return -ENODEV;
6268c2ecf20Sopenharmony_ci		    }
6278c2ecf20Sopenharmony_ci		}
6288c2ecf20Sopenharmony_ci	return 0;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci#endif
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_CPPC_LIB
6338c2ecf20Sopenharmony_cistatic u64 get_max_boost_ratio(unsigned int cpu)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct cppc_perf_caps perf_caps;
6368c2ecf20Sopenharmony_ci	u64 highest_perf, nominal_perf;
6378c2ecf20Sopenharmony_ci	int ret;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (acpi_pstate_strict)
6408c2ecf20Sopenharmony_ci		return 0;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	ret = cppc_get_perf_caps(cpu, &perf_caps);
6438c2ecf20Sopenharmony_ci	if (ret) {
6448c2ecf20Sopenharmony_ci		pr_debug("CPU%d: Unable to get performance capabilities (%d)\n",
6458c2ecf20Sopenharmony_ci			 cpu, ret);
6468c2ecf20Sopenharmony_ci		return 0;
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	highest_perf = perf_caps.highest_perf;
6508c2ecf20Sopenharmony_ci	nominal_perf = perf_caps.nominal_perf;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (!highest_perf || !nominal_perf) {
6538c2ecf20Sopenharmony_ci		pr_debug("CPU%d: highest or nominal performance missing\n", cpu);
6548c2ecf20Sopenharmony_ci		return 0;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (highest_perf < nominal_perf) {
6588c2ecf20Sopenharmony_ci		pr_debug("CPU%d: nominal performance above highest\n", cpu);
6598c2ecf20Sopenharmony_ci		return 0;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	return div_u64(highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf);
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci#else
6658c2ecf20Sopenharmony_cistatic inline u64 get_max_boost_ratio(unsigned int cpu) { return 0; }
6668c2ecf20Sopenharmony_ci#endif
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct cpufreq_frequency_table *freq_table;
6718c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf;
6728c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data;
6738c2ecf20Sopenharmony_ci	unsigned int cpu = policy->cpu;
6748c2ecf20Sopenharmony_ci	struct cpuinfo_x86 *c = &cpu_data(cpu);
6758c2ecf20Sopenharmony_ci	unsigned int valid_states = 0;
6768c2ecf20Sopenharmony_ci	unsigned int result = 0;
6778c2ecf20Sopenharmony_ci	u64 max_boost_ratio;
6788c2ecf20Sopenharmony_ci	unsigned int i;
6798c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
6808c2ecf20Sopenharmony_ci	static int blacklisted;
6818c2ecf20Sopenharmony_ci#endif
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
6868c2ecf20Sopenharmony_ci	if (blacklisted)
6878c2ecf20Sopenharmony_ci		return blacklisted;
6888c2ecf20Sopenharmony_ci	blacklisted = acpi_cpufreq_blacklist(c);
6898c2ecf20Sopenharmony_ci	if (blacklisted)
6908c2ecf20Sopenharmony_ci		return blacklisted;
6918c2ecf20Sopenharmony_ci#endif
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
6948c2ecf20Sopenharmony_ci	if (!data)
6958c2ecf20Sopenharmony_ci		return -ENOMEM;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	if (!zalloc_cpumask_var(&data->freqdomain_cpus, GFP_KERNEL)) {
6988c2ecf20Sopenharmony_ci		result = -ENOMEM;
6998c2ecf20Sopenharmony_ci		goto err_free;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	perf = per_cpu_ptr(acpi_perf_data, cpu);
7038c2ecf20Sopenharmony_ci	data->acpi_perf_cpu = cpu;
7048c2ecf20Sopenharmony_ci	policy->driver_data = data;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	if (cpu_has(c, X86_FEATURE_CONSTANT_TSC))
7078c2ecf20Sopenharmony_ci		acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	result = acpi_processor_register_performance(perf, cpu);
7108c2ecf20Sopenharmony_ci	if (result)
7118c2ecf20Sopenharmony_ci		goto err_free_mask;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	policy->shared_type = perf->shared_type;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/*
7168c2ecf20Sopenharmony_ci	 * Will let policy->cpus know about dependency only when software
7178c2ecf20Sopenharmony_ci	 * coordination is required.
7188c2ecf20Sopenharmony_ci	 */
7198c2ecf20Sopenharmony_ci	if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
7208c2ecf20Sopenharmony_ci	    policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
7218c2ecf20Sopenharmony_ci		cpumask_copy(policy->cpus, perf->shared_cpu_map);
7228c2ecf20Sopenharmony_ci	}
7238c2ecf20Sopenharmony_ci	cpumask_copy(data->freqdomain_cpus, perf->shared_cpu_map);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
7268c2ecf20Sopenharmony_ci	dmi_check_system(sw_any_bug_dmi_table);
7278c2ecf20Sopenharmony_ci	if (bios_with_sw_any_bug && !policy_is_shared(policy)) {
7288c2ecf20Sopenharmony_ci		policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
7298c2ecf20Sopenharmony_ci		cpumask_copy(policy->cpus, topology_core_cpumask(cpu));
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	if (check_amd_hwpstate_cpu(cpu) && boot_cpu_data.x86 < 0x19 &&
7338c2ecf20Sopenharmony_ci	    !acpi_pstate_strict) {
7348c2ecf20Sopenharmony_ci		cpumask_clear(policy->cpus);
7358c2ecf20Sopenharmony_ci		cpumask_set_cpu(cpu, policy->cpus);
7368c2ecf20Sopenharmony_ci		cpumask_copy(data->freqdomain_cpus,
7378c2ecf20Sopenharmony_ci			     topology_sibling_cpumask(cpu));
7388c2ecf20Sopenharmony_ci		policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
7398c2ecf20Sopenharmony_ci		pr_info_once("overriding BIOS provided _PSD data\n");
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci#endif
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	/* capability check */
7448c2ecf20Sopenharmony_ci	if (perf->state_count <= 1) {
7458c2ecf20Sopenharmony_ci		pr_debug("No P-States\n");
7468c2ecf20Sopenharmony_ci		result = -ENODEV;
7478c2ecf20Sopenharmony_ci		goto err_unreg;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	if (perf->control_register.space_id != perf->status_register.space_id) {
7518c2ecf20Sopenharmony_ci		result = -ENODEV;
7528c2ecf20Sopenharmony_ci		goto err_unreg;
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	switch (perf->control_register.space_id) {
7568c2ecf20Sopenharmony_ci	case ACPI_ADR_SPACE_SYSTEM_IO:
7578c2ecf20Sopenharmony_ci		if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
7588c2ecf20Sopenharmony_ci		    boot_cpu_data.x86 == 0xf) {
7598c2ecf20Sopenharmony_ci			pr_debug("AMD K8 systems must use native drivers.\n");
7608c2ecf20Sopenharmony_ci			result = -ENODEV;
7618c2ecf20Sopenharmony_ci			goto err_unreg;
7628c2ecf20Sopenharmony_ci		}
7638c2ecf20Sopenharmony_ci		pr_debug("SYSTEM IO addr space\n");
7648c2ecf20Sopenharmony_ci		data->cpu_feature = SYSTEM_IO_CAPABLE;
7658c2ecf20Sopenharmony_ci		data->cpu_freq_read = cpu_freq_read_io;
7668c2ecf20Sopenharmony_ci		data->cpu_freq_write = cpu_freq_write_io;
7678c2ecf20Sopenharmony_ci		break;
7688c2ecf20Sopenharmony_ci	case ACPI_ADR_SPACE_FIXED_HARDWARE:
7698c2ecf20Sopenharmony_ci		pr_debug("HARDWARE addr space\n");
7708c2ecf20Sopenharmony_ci		if (check_est_cpu(cpu)) {
7718c2ecf20Sopenharmony_ci			data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
7728c2ecf20Sopenharmony_ci			data->cpu_freq_read = cpu_freq_read_intel;
7738c2ecf20Sopenharmony_ci			data->cpu_freq_write = cpu_freq_write_intel;
7748c2ecf20Sopenharmony_ci			break;
7758c2ecf20Sopenharmony_ci		}
7768c2ecf20Sopenharmony_ci		if (check_amd_hwpstate_cpu(cpu)) {
7778c2ecf20Sopenharmony_ci			data->cpu_feature = SYSTEM_AMD_MSR_CAPABLE;
7788c2ecf20Sopenharmony_ci			data->cpu_freq_read = cpu_freq_read_amd;
7798c2ecf20Sopenharmony_ci			data->cpu_freq_write = cpu_freq_write_amd;
7808c2ecf20Sopenharmony_ci			break;
7818c2ecf20Sopenharmony_ci		}
7828c2ecf20Sopenharmony_ci		result = -ENODEV;
7838c2ecf20Sopenharmony_ci		goto err_unreg;
7848c2ecf20Sopenharmony_ci	default:
7858c2ecf20Sopenharmony_ci		pr_debug("Unknown addr space %d\n",
7868c2ecf20Sopenharmony_ci			(u32) (perf->control_register.space_id));
7878c2ecf20Sopenharmony_ci		result = -ENODEV;
7888c2ecf20Sopenharmony_ci		goto err_unreg;
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	freq_table = kcalloc(perf->state_count + 1, sizeof(*freq_table),
7928c2ecf20Sopenharmony_ci			     GFP_KERNEL);
7938c2ecf20Sopenharmony_ci	if (!freq_table) {
7948c2ecf20Sopenharmony_ci		result = -ENOMEM;
7958c2ecf20Sopenharmony_ci		goto err_unreg;
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* detect transition latency */
7998c2ecf20Sopenharmony_ci	policy->cpuinfo.transition_latency = 0;
8008c2ecf20Sopenharmony_ci	for (i = 0; i < perf->state_count; i++) {
8018c2ecf20Sopenharmony_ci		if ((perf->states[i].transition_latency * 1000) >
8028c2ecf20Sopenharmony_ci		    policy->cpuinfo.transition_latency)
8038c2ecf20Sopenharmony_ci			policy->cpuinfo.transition_latency =
8048c2ecf20Sopenharmony_ci			    perf->states[i].transition_latency * 1000;
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* Check for high latency (>20uS) from buggy BIOSes, like on T42 */
8088c2ecf20Sopenharmony_ci	if (perf->control_register.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE &&
8098c2ecf20Sopenharmony_ci	    policy->cpuinfo.transition_latency > 20 * 1000) {
8108c2ecf20Sopenharmony_ci		policy->cpuinfo.transition_latency = 20 * 1000;
8118c2ecf20Sopenharmony_ci		pr_info_once("P-state transition latency capped at 20 uS\n");
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/* table init */
8158c2ecf20Sopenharmony_ci	for (i = 0; i < perf->state_count; i++) {
8168c2ecf20Sopenharmony_ci		if (i > 0 && perf->states[i].core_frequency >=
8178c2ecf20Sopenharmony_ci		    freq_table[valid_states-1].frequency / 1000)
8188c2ecf20Sopenharmony_ci			continue;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci		freq_table[valid_states].driver_data = i;
8218c2ecf20Sopenharmony_ci		freq_table[valid_states].frequency =
8228c2ecf20Sopenharmony_ci		    perf->states[i].core_frequency * 1000;
8238c2ecf20Sopenharmony_ci		valid_states++;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci	freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	max_boost_ratio = get_max_boost_ratio(cpu);
8288c2ecf20Sopenharmony_ci	if (max_boost_ratio) {
8298c2ecf20Sopenharmony_ci		unsigned int freq = freq_table[0].frequency;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci		/*
8328c2ecf20Sopenharmony_ci		 * Because the loop above sorts the freq_table entries in the
8338c2ecf20Sopenharmony_ci		 * descending order, freq is the maximum frequency in the table.
8348c2ecf20Sopenharmony_ci		 * Assume that it corresponds to the CPPC nominal frequency and
8358c2ecf20Sopenharmony_ci		 * use it to set cpuinfo.max_freq.
8368c2ecf20Sopenharmony_ci		 */
8378c2ecf20Sopenharmony_ci		policy->cpuinfo.max_freq = freq * max_boost_ratio >> SCHED_CAPACITY_SHIFT;
8388c2ecf20Sopenharmony_ci	} else {
8398c2ecf20Sopenharmony_ci		/*
8408c2ecf20Sopenharmony_ci		 * If the maximum "boost" frequency is unknown, ask the arch
8418c2ecf20Sopenharmony_ci		 * scale-invariance code to use the "nominal" performance for
8428c2ecf20Sopenharmony_ci		 * CPU utilization scaling so as to prevent the schedutil
8438c2ecf20Sopenharmony_ci		 * governor from selecting inadequate CPU frequencies.
8448c2ecf20Sopenharmony_ci		 */
8458c2ecf20Sopenharmony_ci		arch_set_max_freq_ratio(true);
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	policy->freq_table = freq_table;
8498c2ecf20Sopenharmony_ci	perf->state = 0;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	switch (perf->control_register.space_id) {
8528c2ecf20Sopenharmony_ci	case ACPI_ADR_SPACE_SYSTEM_IO:
8538c2ecf20Sopenharmony_ci		/*
8548c2ecf20Sopenharmony_ci		 * The core will not set policy->cur, because
8558c2ecf20Sopenharmony_ci		 * cpufreq_driver->get is NULL, so we need to set it here.
8568c2ecf20Sopenharmony_ci		 * However, we have to guess it, because the current speed is
8578c2ecf20Sopenharmony_ci		 * unknown and not detectable via IO ports.
8588c2ecf20Sopenharmony_ci		 */
8598c2ecf20Sopenharmony_ci		policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
8608c2ecf20Sopenharmony_ci		break;
8618c2ecf20Sopenharmony_ci	case ACPI_ADR_SPACE_FIXED_HARDWARE:
8628c2ecf20Sopenharmony_ci		acpi_cpufreq_driver.get = get_cur_freq_on_cpu;
8638c2ecf20Sopenharmony_ci		break;
8648c2ecf20Sopenharmony_ci	default:
8658c2ecf20Sopenharmony_ci		break;
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	/* notify BIOS that we exist */
8698c2ecf20Sopenharmony_ci	acpi_processor_notify_smm(THIS_MODULE);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
8728c2ecf20Sopenharmony_ci	for (i = 0; i < perf->state_count; i++)
8738c2ecf20Sopenharmony_ci		pr_debug("     %cP%d: %d MHz, %d mW, %d uS\n",
8748c2ecf20Sopenharmony_ci			(i == perf->state ? '*' : ' '), i,
8758c2ecf20Sopenharmony_ci			(u32) perf->states[i].core_frequency,
8768c2ecf20Sopenharmony_ci			(u32) perf->states[i].power,
8778c2ecf20Sopenharmony_ci			(u32) perf->states[i].transition_latency);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/*
8808c2ecf20Sopenharmony_ci	 * the first call to ->target() should result in us actually
8818c2ecf20Sopenharmony_ci	 * writing something to the appropriate registers.
8828c2ecf20Sopenharmony_ci	 */
8838c2ecf20Sopenharmony_ci	data->resume = 1;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	policy->fast_switch_possible = !acpi_pstate_strict &&
8868c2ecf20Sopenharmony_ci		!(policy_is_shared(policy) && policy->shared_type != CPUFREQ_SHARED_TYPE_ANY);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return result;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cierr_unreg:
8918c2ecf20Sopenharmony_ci	acpi_processor_unregister_performance(cpu);
8928c2ecf20Sopenharmony_cierr_free_mask:
8938c2ecf20Sopenharmony_ci	free_cpumask_var(data->freqdomain_cpus);
8948c2ecf20Sopenharmony_cierr_free:
8958c2ecf20Sopenharmony_ci	kfree(data);
8968c2ecf20Sopenharmony_ci	policy->driver_data = NULL;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	return result;
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_cistatic int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
9028c2ecf20Sopenharmony_ci{
9038c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	policy->fast_switch_possible = false;
9088c2ecf20Sopenharmony_ci	policy->driver_data = NULL;
9098c2ecf20Sopenharmony_ci	acpi_processor_unregister_performance(data->acpi_perf_cpu);
9108c2ecf20Sopenharmony_ci	free_cpumask_var(data->freqdomain_cpus);
9118c2ecf20Sopenharmony_ci	kfree(policy->freq_table);
9128c2ecf20Sopenharmony_ci	kfree(data);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return 0;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic void acpi_cpufreq_cpu_ready(struct cpufreq_policy *policy)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	struct acpi_processor_performance *perf = per_cpu_ptr(acpi_perf_data,
9208c2ecf20Sopenharmony_ci							      policy->cpu);
9218c2ecf20Sopenharmony_ci	unsigned int freq = policy->freq_table[0].frequency;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (perf->states[0].core_frequency * 1000 != freq)
9248c2ecf20Sopenharmony_ci		pr_warn(FW_WARN "P-state 0 is not max freq\n");
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_cistatic int acpi_cpufreq_resume(struct cpufreq_policy *policy)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct acpi_cpufreq_data *data = policy->driver_data;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	data->resume = 1;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	return 0;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic struct freq_attr *acpi_cpufreq_attr[] = {
9398c2ecf20Sopenharmony_ci	&cpufreq_freq_attr_scaling_available_freqs,
9408c2ecf20Sopenharmony_ci	&freqdomain_cpus,
9418c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
9428c2ecf20Sopenharmony_ci	&cpb,
9438c2ecf20Sopenharmony_ci#endif
9448c2ecf20Sopenharmony_ci	NULL,
9458c2ecf20Sopenharmony_ci};
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_cistatic struct cpufreq_driver acpi_cpufreq_driver = {
9488c2ecf20Sopenharmony_ci	.verify		= cpufreq_generic_frequency_table_verify,
9498c2ecf20Sopenharmony_ci	.target_index	= acpi_cpufreq_target,
9508c2ecf20Sopenharmony_ci	.fast_switch	= acpi_cpufreq_fast_switch,
9518c2ecf20Sopenharmony_ci	.bios_limit	= acpi_processor_get_bios_limit,
9528c2ecf20Sopenharmony_ci	.init		= acpi_cpufreq_cpu_init,
9538c2ecf20Sopenharmony_ci	.exit		= acpi_cpufreq_cpu_exit,
9548c2ecf20Sopenharmony_ci	.ready		= acpi_cpufreq_cpu_ready,
9558c2ecf20Sopenharmony_ci	.resume		= acpi_cpufreq_resume,
9568c2ecf20Sopenharmony_ci	.name		= "acpi-cpufreq",
9578c2ecf20Sopenharmony_ci	.attr		= acpi_cpufreq_attr,
9588c2ecf20Sopenharmony_ci};
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic enum cpuhp_state acpi_cpufreq_online;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_cistatic void __init acpi_cpufreq_boost_init(void)
9638c2ecf20Sopenharmony_ci{
9648c2ecf20Sopenharmony_ci	int ret;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA))) {
9678c2ecf20Sopenharmony_ci		pr_debug("Boost capabilities not present in the processor\n");
9688c2ecf20Sopenharmony_ci		return;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	acpi_cpufreq_driver.set_boost = set_boost;
9728c2ecf20Sopenharmony_ci	acpi_cpufreq_driver.boost_enabled = boost_state(0);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	/*
9758c2ecf20Sopenharmony_ci	 * This calls the online callback on all online cpu and forces all
9768c2ecf20Sopenharmony_ci	 * MSRs to the same value.
9778c2ecf20Sopenharmony_ci	 */
9788c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpufreq/acpi:online",
9798c2ecf20Sopenharmony_ci				cpufreq_boost_online, cpufreq_boost_down_prep);
9808c2ecf20Sopenharmony_ci	if (ret < 0) {
9818c2ecf20Sopenharmony_ci		pr_err("acpi_cpufreq: failed to register hotplug callbacks\n");
9828c2ecf20Sopenharmony_ci		return;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci	acpi_cpufreq_online = ret;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic void acpi_cpufreq_boost_exit(void)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	if (acpi_cpufreq_online > 0)
9908c2ecf20Sopenharmony_ci		cpuhp_remove_state_nocalls(acpi_cpufreq_online);
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic int __init acpi_cpufreq_init(void)
9948c2ecf20Sopenharmony_ci{
9958c2ecf20Sopenharmony_ci	int ret;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	if (acpi_disabled)
9988c2ecf20Sopenharmony_ci		return -ENODEV;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	/* don't keep reloading if cpufreq_driver exists */
10018c2ecf20Sopenharmony_ci	if (cpufreq_get_current_driver())
10028c2ecf20Sopenharmony_ci		return -EEXIST;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	ret = acpi_cpufreq_early_init();
10078c2ecf20Sopenharmony_ci	if (ret)
10088c2ecf20Sopenharmony_ci		return ret;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
10118c2ecf20Sopenharmony_ci	/* this is a sysfs file with a strange name and an even stranger
10128c2ecf20Sopenharmony_ci	 * semantic - per CPU instantiation, but system global effect.
10138c2ecf20Sopenharmony_ci	 * Lets enable it only on AMD CPUs for compatibility reasons and
10148c2ecf20Sopenharmony_ci	 * only if configured. This is considered legacy code, which
10158c2ecf20Sopenharmony_ci	 * will probably be removed at some point in the future.
10168c2ecf20Sopenharmony_ci	 */
10178c2ecf20Sopenharmony_ci	if (!check_amd_hwpstate_cpu(0)) {
10188c2ecf20Sopenharmony_ci		struct freq_attr **attr;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci		pr_debug("CPB unsupported, do not expose it\n");
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci		for (attr = acpi_cpufreq_attr; *attr; attr++)
10238c2ecf20Sopenharmony_ci			if (*attr == &cpb) {
10248c2ecf20Sopenharmony_ci				*attr = NULL;
10258c2ecf20Sopenharmony_ci				break;
10268c2ecf20Sopenharmony_ci			}
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci#endif
10298c2ecf20Sopenharmony_ci	acpi_cpufreq_boost_init();
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	ret = cpufreq_register_driver(&acpi_cpufreq_driver);
10328c2ecf20Sopenharmony_ci	if (ret) {
10338c2ecf20Sopenharmony_ci		free_acpi_perf_data();
10348c2ecf20Sopenharmony_ci		acpi_cpufreq_boost_exit();
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci	return ret;
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_cistatic void __exit acpi_cpufreq_exit(void)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	acpi_cpufreq_boost_exit();
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	cpufreq_unregister_driver(&acpi_cpufreq_driver);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	free_acpi_perf_data();
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cimodule_param(acpi_pstate_strict, uint, 0644);
10518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(acpi_pstate_strict,
10528c2ecf20Sopenharmony_ci	"value 0 or non-zero. non-zero -> strict ACPI checks are "
10538c2ecf20Sopenharmony_ci	"performed during frequency changes.");
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cilate_initcall(acpi_cpufreq_init);
10568c2ecf20Sopenharmony_cimodule_exit(acpi_cpufreq_exit);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_cistatic const struct x86_cpu_id __maybe_unused acpi_cpufreq_ids[] = {
10598c2ecf20Sopenharmony_ci	X86_MATCH_FEATURE(X86_FEATURE_ACPI, NULL),
10608c2ecf20Sopenharmony_ci	X86_MATCH_FEATURE(X86_FEATURE_HW_PSTATE, NULL),
10618c2ecf20Sopenharmony_ci	{}
10628c2ecf20Sopenharmony_ci};
10638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic const struct acpi_device_id __maybe_unused processor_device_ids[] = {
10668c2ecf20Sopenharmony_ci	{ACPI_PROCESSOR_OBJECT_HID, },
10678c2ecf20Sopenharmony_ci	{ACPI_PROCESSOR_DEVICE_HID, },
10688c2ecf20Sopenharmony_ci	{},
10698c2ecf20Sopenharmony_ci};
10708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, processor_device_ids);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ciMODULE_ALIAS("acpi");
1073