18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * processor_perflib.c - ACPI Processor P-States Library ($Revision: 71 $)
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) 2004       Dominik Brodowski <linux@brodo.de>
88c2ecf20Sopenharmony_ci *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
98c2ecf20Sopenharmony_ci *  			- Added processor hotplug support
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/cpufreq.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/acpi.h>
188c2ecf20Sopenharmony_ci#include <acpi/processor.h>
198c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
208c2ecf20Sopenharmony_ci#include <asm/cpufeature.h>
218c2ecf20Sopenharmony_ci#endif
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define PREFIX "ACPI: "
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define ACPI_PROCESSOR_CLASS		"processor"
268c2ecf20Sopenharmony_ci#define ACPI_PROCESSOR_FILE_PERFORMANCE	"performance"
278c2ecf20Sopenharmony_ci#define _COMPONENT		ACPI_PROCESSOR_COMPONENT
288c2ecf20Sopenharmony_ciACPI_MODULE_NAME("processor_perflib");
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(performance_mutex);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * _PPC support is implemented as a CPUfreq policy notifier:
348c2ecf20Sopenharmony_ci * This means each time a CPUfreq driver registered also with
358c2ecf20Sopenharmony_ci * the ACPI core is asked to change the speed policy, the maximum
368c2ecf20Sopenharmony_ci * value is adjusted so that it is within the platform limit.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * Also, when a new platform limit value is detected, the CPUfreq
398c2ecf20Sopenharmony_ci * policy is adjusted accordingly.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* ignore_ppc:
438c2ecf20Sopenharmony_ci * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet
448c2ecf20Sopenharmony_ci *       ignore _PPC
458c2ecf20Sopenharmony_ci *  0 -> cpufreq low level drivers initialized -> consider _PPC values
468c2ecf20Sopenharmony_ci *  1 -> ignore _PPC totally -> forced by user through boot param
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic int ignore_ppc = -1;
498c2ecf20Sopenharmony_cimodule_param(ignore_ppc, int, 0644);
508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
518c2ecf20Sopenharmony_ci		 "limited by BIOS, this should help");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic bool acpi_processor_ppc_in_use;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic int acpi_processor_get_platform_limit(struct acpi_processor *pr)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	acpi_status status = 0;
588c2ecf20Sopenharmony_ci	unsigned long long ppc = 0;
598c2ecf20Sopenharmony_ci	s32 qos_value;
608c2ecf20Sopenharmony_ci	int index;
618c2ecf20Sopenharmony_ci	int ret;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (!pr)
648c2ecf20Sopenharmony_ci		return -EINVAL;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * _PPC indicates the maximum state currently supported by the platform
688c2ecf20Sopenharmony_ci	 * (e.g. 0 = states 0..n; 1 = states 1..n; etc.
698c2ecf20Sopenharmony_ci	 */
708c2ecf20Sopenharmony_ci	status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (status != AE_NOT_FOUND)
738c2ecf20Sopenharmony_ci		acpi_processor_ppc_in_use = true;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
768c2ecf20Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
778c2ecf20Sopenharmony_ci		return -ENODEV;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	index = ppc;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (pr->performance_platform_limit == index ||
838c2ecf20Sopenharmony_ci	    ppc >= pr->performance->state_count)
848c2ecf20Sopenharmony_ci		return 0;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
878c2ecf20Sopenharmony_ci		 index, index ? "is" : "is not");
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	pr->performance_platform_limit = index;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (unlikely(!freq_qos_request_active(&pr->perflib_req)))
928c2ecf20Sopenharmony_ci		return 0;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/*
958c2ecf20Sopenharmony_ci	 * If _PPC returns 0, it means that all of the available states can be
968c2ecf20Sopenharmony_ci	 * used ("no limit").
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	if (index == 0)
998c2ecf20Sopenharmony_ci		qos_value = FREQ_QOS_MAX_DEFAULT_VALUE;
1008c2ecf20Sopenharmony_ci	else
1018c2ecf20Sopenharmony_ci		qos_value = pr->performance->states[index].core_frequency * 1000;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ret = freq_qos_update_request(&pr->perflib_req, qos_value);
1048c2ecf20Sopenharmony_ci	if (ret < 0) {
1058c2ecf20Sopenharmony_ci		pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n",
1068c2ecf20Sopenharmony_ci			pr->id, ret);
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE	0x80
1138c2ecf20Sopenharmony_ci/*
1148c2ecf20Sopenharmony_ci * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status
1158c2ecf20Sopenharmony_ci * @handle: ACPI processor handle
1168c2ecf20Sopenharmony_ci * @status: the status code of _PPC evaluation
1178c2ecf20Sopenharmony_ci *	0: success. OSPM is now using the performance state specificed.
1188c2ecf20Sopenharmony_ci *	1: failure. OSPM has not changed the number of P-states in use
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistatic void acpi_processor_ppc_ost(acpi_handle handle, int status)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	if (acpi_has_method(handle, "_OST"))
1238c2ecf20Sopenharmony_ci		acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE,
1248c2ecf20Sopenharmony_ci				  status, NULL);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_civoid acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	int ret;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (ignore_ppc || !pr->performance) {
1328c2ecf20Sopenharmony_ci		/*
1338c2ecf20Sopenharmony_ci		 * Only when it is notification event, the _OST object
1348c2ecf20Sopenharmony_ci		 * will be evaluated. Otherwise it is skipped.
1358c2ecf20Sopenharmony_ci		 */
1368c2ecf20Sopenharmony_ci		if (event_flag)
1378c2ecf20Sopenharmony_ci			acpi_processor_ppc_ost(pr->handle, 1);
1388c2ecf20Sopenharmony_ci		return;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	ret = acpi_processor_get_platform_limit(pr);
1428c2ecf20Sopenharmony_ci	/*
1438c2ecf20Sopenharmony_ci	 * Only when it is notification event, the _OST object
1448c2ecf20Sopenharmony_ci	 * will be evaluated. Otherwise it is skipped.
1458c2ecf20Sopenharmony_ci	 */
1468c2ecf20Sopenharmony_ci	if (event_flag) {
1478c2ecf20Sopenharmony_ci		if (ret < 0)
1488c2ecf20Sopenharmony_ci			acpi_processor_ppc_ost(pr->handle, 1);
1498c2ecf20Sopenharmony_ci		else
1508c2ecf20Sopenharmony_ci			acpi_processor_ppc_ost(pr->handle, 0);
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci	if (ret >= 0)
1538c2ecf20Sopenharmony_ci		cpufreq_update_limits(pr->id);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ciint acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct acpi_processor *pr;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	pr = per_cpu(processors, cpu);
1618c2ecf20Sopenharmony_ci	if (!pr || !pr->performance || !pr->performance->state_count)
1628c2ecf20Sopenharmony_ci		return -ENODEV;
1638c2ecf20Sopenharmony_ci	*limit = pr->performance->states[pr->performance_platform_limit].
1648c2ecf20Sopenharmony_ci		core_frequency * 1000;
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_processor_get_bios_limit);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_civoid acpi_processor_ignore_ppc_init(void)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	if (ignore_ppc < 0)
1728c2ecf20Sopenharmony_ci		ignore_ppc = 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_civoid acpi_processor_ppc_init(struct cpufreq_policy *policy)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	unsigned int cpu;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	for_each_cpu(cpu, policy->related_cpus) {
1808c2ecf20Sopenharmony_ci		struct acpi_processor *pr = per_cpu(processors, cpu);
1818c2ecf20Sopenharmony_ci		int ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		if (!pr)
1848c2ecf20Sopenharmony_ci			continue;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		/*
1878c2ecf20Sopenharmony_ci		 * Reset performance_platform_limit in case there is a stale
1888c2ecf20Sopenharmony_ci		 * value in it, so as to make it match the "no limit" QoS value
1898c2ecf20Sopenharmony_ci		 * below.
1908c2ecf20Sopenharmony_ci		 */
1918c2ecf20Sopenharmony_ci		pr->performance_platform_limit = 0;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		ret = freq_qos_add_request(&policy->constraints,
1948c2ecf20Sopenharmony_ci					   &pr->perflib_req, FREQ_QOS_MAX,
1958c2ecf20Sopenharmony_ci					   FREQ_QOS_MAX_DEFAULT_VALUE);
1968c2ecf20Sopenharmony_ci		if (ret < 0)
1978c2ecf20Sopenharmony_ci			pr_err("Failed to add freq constraint for CPU%d (%d)\n",
1988c2ecf20Sopenharmony_ci			       cpu, ret);
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_civoid acpi_processor_ppc_exit(struct cpufreq_policy *policy)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	unsigned int cpu;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	for_each_cpu(cpu, policy->related_cpus) {
2078c2ecf20Sopenharmony_ci		struct acpi_processor *pr = per_cpu(processors, cpu);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		if (pr)
2108c2ecf20Sopenharmony_ci			freq_qos_remove_request(&pr->perflib_req);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int acpi_processor_get_performance_control(struct acpi_processor *pr)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int result = 0;
2178c2ecf20Sopenharmony_ci	acpi_status status = 0;
2188c2ecf20Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
2198c2ecf20Sopenharmony_ci	union acpi_object *pct = NULL;
2208c2ecf20Sopenharmony_ci	union acpi_object obj = { 0 };
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
2248c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
2258c2ecf20Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT"));
2268c2ecf20Sopenharmony_ci		return -ENODEV;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	pct = (union acpi_object *)buffer.pointer;
2308c2ecf20Sopenharmony_ci	if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
2318c2ecf20Sopenharmony_ci	    || (pct->package.count != 2)) {
2328c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PCT data\n");
2338c2ecf20Sopenharmony_ci		result = -EFAULT;
2348c2ecf20Sopenharmony_ci		goto end;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/*
2388c2ecf20Sopenharmony_ci	 * control_register
2398c2ecf20Sopenharmony_ci	 */
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	obj = pct->package.elements[0];
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if ((obj.type != ACPI_TYPE_BUFFER)
2448c2ecf20Sopenharmony_ci	    || (obj.buffer.length < sizeof(struct acpi_pct_register))
2458c2ecf20Sopenharmony_ci	    || (obj.buffer.pointer == NULL)) {
2468c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PCT data (control_register)\n");
2478c2ecf20Sopenharmony_ci		result = -EFAULT;
2488c2ecf20Sopenharmony_ci		goto end;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	memcpy(&pr->performance->control_register, obj.buffer.pointer,
2518c2ecf20Sopenharmony_ci	       sizeof(struct acpi_pct_register));
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/*
2548c2ecf20Sopenharmony_ci	 * status_register
2558c2ecf20Sopenharmony_ci	 */
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	obj = pct->package.elements[1];
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if ((obj.type != ACPI_TYPE_BUFFER)
2608c2ecf20Sopenharmony_ci	    || (obj.buffer.length < sizeof(struct acpi_pct_register))
2618c2ecf20Sopenharmony_ci	    || (obj.buffer.pointer == NULL)) {
2628c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PCT data (status_register)\n");
2638c2ecf20Sopenharmony_ci		result = -EFAULT;
2648c2ecf20Sopenharmony_ci		goto end;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	memcpy(&pr->performance->status_register, obj.buffer.pointer,
2688c2ecf20Sopenharmony_ci	       sizeof(struct acpi_pct_register));
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci      end:
2718c2ecf20Sopenharmony_ci	kfree(buffer.pointer);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return result;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
2778c2ecf20Sopenharmony_ci/*
2788c2ecf20Sopenharmony_ci * Some AMDs have 50MHz frequency multiples, but only provide 100MHz rounding
2798c2ecf20Sopenharmony_ci * in their ACPI data. Calculate the real values and fix up the _PSS data.
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic void amd_fixup_frequency(struct acpi_processor_px *px, int i)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	u32 hi, lo, fid, did;
2848c2ecf20Sopenharmony_ci	int index = px->control & 0x00000007;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
2878c2ecf20Sopenharmony_ci		return;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
2908c2ecf20Sopenharmony_ci	    || boot_cpu_data.x86 == 0x11) {
2918c2ecf20Sopenharmony_ci		rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi);
2928c2ecf20Sopenharmony_ci		/*
2938c2ecf20Sopenharmony_ci		 * MSR C001_0064+:
2948c2ecf20Sopenharmony_ci		 * Bit 63: PstateEn. Read-write. If set, the P-state is valid.
2958c2ecf20Sopenharmony_ci		 */
2968c2ecf20Sopenharmony_ci		if (!(hi & BIT(31)))
2978c2ecf20Sopenharmony_ci			return;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		fid = lo & 0x3f;
3008c2ecf20Sopenharmony_ci		did = (lo >> 6) & 7;
3018c2ecf20Sopenharmony_ci		if (boot_cpu_data.x86 == 0x10)
3028c2ecf20Sopenharmony_ci			px->core_frequency = (100 * (fid + 0x10)) >> did;
3038c2ecf20Sopenharmony_ci		else
3048c2ecf20Sopenharmony_ci			px->core_frequency = (100 * (fid + 8)) >> did;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci#else
3088c2ecf20Sopenharmony_cistatic void amd_fixup_frequency(struct acpi_processor_px *px, int i) {};
3098c2ecf20Sopenharmony_ci#endif
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int acpi_processor_get_performance_states(struct acpi_processor *pr)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	int result = 0;
3148c2ecf20Sopenharmony_ci	acpi_status status = AE_OK;
3158c2ecf20Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
3168c2ecf20Sopenharmony_ci	struct acpi_buffer format = { sizeof("NNNNNN"), "NNNNNN" };
3178c2ecf20Sopenharmony_ci	struct acpi_buffer state = { 0, NULL };
3188c2ecf20Sopenharmony_ci	union acpi_object *pss = NULL;
3198c2ecf20Sopenharmony_ci	int i;
3208c2ecf20Sopenharmony_ci	int last_invalid = -1;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
3248c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
3258c2ecf20Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS"));
3268c2ecf20Sopenharmony_ci		return -ENODEV;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	pss = buffer.pointer;
3308c2ecf20Sopenharmony_ci	if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
3318c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PSS data\n");
3328c2ecf20Sopenharmony_ci		result = -EFAULT;
3338c2ecf20Sopenharmony_ci		goto end;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n",
3378c2ecf20Sopenharmony_ci			  pss->package.count));
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	pr->performance->state_count = pss->package.count;
3408c2ecf20Sopenharmony_ci	pr->performance->states =
3418c2ecf20Sopenharmony_ci	    kmalloc_array(pss->package.count,
3428c2ecf20Sopenharmony_ci			  sizeof(struct acpi_processor_px),
3438c2ecf20Sopenharmony_ci			  GFP_KERNEL);
3448c2ecf20Sopenharmony_ci	if (!pr->performance->states) {
3458c2ecf20Sopenharmony_ci		result = -ENOMEM;
3468c2ecf20Sopenharmony_ci		goto end;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	for (i = 0; i < pr->performance->state_count; i++) {
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		struct acpi_processor_px *px = &(pr->performance->states[i]);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci		state.length = sizeof(struct acpi_processor_px);
3548c2ecf20Sopenharmony_ci		state.pointer = px;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		status = acpi_extract_package(&(pss->package.elements[i]),
3598c2ecf20Sopenharmony_ci					      &format, &state);
3608c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(status)) {
3618c2ecf20Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data"));
3628c2ecf20Sopenharmony_ci			result = -EFAULT;
3638c2ecf20Sopenharmony_ci			kfree(pr->performance->states);
3648c2ecf20Sopenharmony_ci			goto end;
3658c2ecf20Sopenharmony_ci		}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		amd_fixup_frequency(px, i);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
3708c2ecf20Sopenharmony_ci				  "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n",
3718c2ecf20Sopenharmony_ci				  i,
3728c2ecf20Sopenharmony_ci				  (u32) px->core_frequency,
3738c2ecf20Sopenharmony_ci				  (u32) px->power,
3748c2ecf20Sopenharmony_ci				  (u32) px->transition_latency,
3758c2ecf20Sopenharmony_ci				  (u32) px->bus_master_latency,
3768c2ecf20Sopenharmony_ci				  (u32) px->control, (u32) px->status));
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci		/*
3798c2ecf20Sopenharmony_ci		 * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
3808c2ecf20Sopenharmony_ci		 */
3818c2ecf20Sopenharmony_ci		if (!px->core_frequency ||
3828c2ecf20Sopenharmony_ci		    ((u32)(px->core_frequency * 1000) !=
3838c2ecf20Sopenharmony_ci		     (px->core_frequency * 1000))) {
3848c2ecf20Sopenharmony_ci			printk(KERN_ERR FW_BUG PREFIX
3858c2ecf20Sopenharmony_ci			       "Invalid BIOS _PSS frequency found for processor %d: 0x%llx MHz\n",
3868c2ecf20Sopenharmony_ci			       pr->id, px->core_frequency);
3878c2ecf20Sopenharmony_ci			if (last_invalid == -1)
3888c2ecf20Sopenharmony_ci				last_invalid = i;
3898c2ecf20Sopenharmony_ci		} else {
3908c2ecf20Sopenharmony_ci			if (last_invalid != -1) {
3918c2ecf20Sopenharmony_ci				/*
3928c2ecf20Sopenharmony_ci				 * Copy this valid entry over last_invalid entry
3938c2ecf20Sopenharmony_ci				 */
3948c2ecf20Sopenharmony_ci				memcpy(&(pr->performance->states[last_invalid]),
3958c2ecf20Sopenharmony_ci				       px, sizeof(struct acpi_processor_px));
3968c2ecf20Sopenharmony_ci				++last_invalid;
3978c2ecf20Sopenharmony_ci			}
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (last_invalid == 0) {
4028c2ecf20Sopenharmony_ci		printk(KERN_ERR FW_BUG PREFIX
4038c2ecf20Sopenharmony_ci		       "No valid BIOS _PSS frequency found for processor %d\n", pr->id);
4048c2ecf20Sopenharmony_ci		result = -EFAULT;
4058c2ecf20Sopenharmony_ci		kfree(pr->performance->states);
4068c2ecf20Sopenharmony_ci		pr->performance->states = NULL;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	if (last_invalid > 0)
4108c2ecf20Sopenharmony_ci		pr->performance->state_count = last_invalid;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci      end:
4138c2ecf20Sopenharmony_ci	kfree(buffer.pointer);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return result;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ciint acpi_processor_get_performance_info(struct acpi_processor *pr)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	int result = 0;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (!pr || !pr->performance || !pr->handle)
4238c2ecf20Sopenharmony_ci		return -EINVAL;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (!acpi_has_method(pr->handle, "_PCT")) {
4268c2ecf20Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4278c2ecf20Sopenharmony_ci				  "ACPI-based processor performance control unavailable\n"));
4288c2ecf20Sopenharmony_ci		return -ENODEV;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	result = acpi_processor_get_performance_control(pr);
4328c2ecf20Sopenharmony_ci	if (result)
4338c2ecf20Sopenharmony_ci		goto update_bios;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	result = acpi_processor_get_performance_states(pr);
4368c2ecf20Sopenharmony_ci	if (result)
4378c2ecf20Sopenharmony_ci		goto update_bios;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* We need to call _PPC once when cpufreq starts */
4408c2ecf20Sopenharmony_ci	if (ignore_ppc != 1)
4418c2ecf20Sopenharmony_ci		result = acpi_processor_get_platform_limit(pr);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return result;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/*
4468c2ecf20Sopenharmony_ci	 * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
4478c2ecf20Sopenharmony_ci	 * the BIOS is older than the CPU and does not know its frequencies
4488c2ecf20Sopenharmony_ci	 */
4498c2ecf20Sopenharmony_ci update_bios:
4508c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
4518c2ecf20Sopenharmony_ci	if (acpi_has_method(pr->handle, "_PPC")) {
4528c2ecf20Sopenharmony_ci		if(boot_cpu_has(X86_FEATURE_EST))
4538c2ecf20Sopenharmony_ci			printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
4548c2ecf20Sopenharmony_ci			       "frequency support\n");
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci#endif
4578c2ecf20Sopenharmony_ci	return result;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_processor_get_performance_info);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ciint acpi_processor_pstate_control(void)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	acpi_status status;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control)
4668c2ecf20Sopenharmony_ci		return 0;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4698c2ecf20Sopenharmony_ci			  "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
4708c2ecf20Sopenharmony_ci			  acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
4738c2ecf20Sopenharmony_ci				    (u32)acpi_gbl_FADT.pstate_control, 8);
4748c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
4758c2ecf20Sopenharmony_ci		return 1;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ACPI_EXCEPTION((AE_INFO, status,
4788c2ecf20Sopenharmony_ci			"Failed to write pstate_control [0x%x] to smi_command [0x%x]",
4798c2ecf20Sopenharmony_ci			acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
4808c2ecf20Sopenharmony_ci	return -EIO;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ciint acpi_processor_notify_smm(struct module *calling_module)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	static int is_done = 0;
4868c2ecf20Sopenharmony_ci	int result;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (!acpi_processor_cpufreq_init)
4898c2ecf20Sopenharmony_ci		return -EBUSY;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (!try_module_get(calling_module))
4928c2ecf20Sopenharmony_ci		return -EINVAL;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* is_done is set to negative if an error occurred,
4958c2ecf20Sopenharmony_ci	 * and to postitive if _no_ error occurred, but SMM
4968c2ecf20Sopenharmony_ci	 * was already notified. This avoids double notification
4978c2ecf20Sopenharmony_ci	 * which might lead to unexpected results...
4988c2ecf20Sopenharmony_ci	 */
4998c2ecf20Sopenharmony_ci	if (is_done > 0) {
5008c2ecf20Sopenharmony_ci		module_put(calling_module);
5018c2ecf20Sopenharmony_ci		return 0;
5028c2ecf20Sopenharmony_ci	} else if (is_done < 0) {
5038c2ecf20Sopenharmony_ci		module_put(calling_module);
5048c2ecf20Sopenharmony_ci		return is_done;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	is_done = -EIO;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	result = acpi_processor_pstate_control();
5108c2ecf20Sopenharmony_ci	if (!result) {
5118c2ecf20Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
5128c2ecf20Sopenharmony_ci		module_put(calling_module);
5138c2ecf20Sopenharmony_ci		return 0;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci	if (result < 0) {
5168c2ecf20Sopenharmony_ci		module_put(calling_module);
5178c2ecf20Sopenharmony_ci		return result;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	/* Success. If there's no _PPC, we need to fear nothing, so
5218c2ecf20Sopenharmony_ci	 * we can allow the cpufreq driver to be rmmod'ed. */
5228c2ecf20Sopenharmony_ci	is_done = 1;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (!acpi_processor_ppc_in_use)
5258c2ecf20Sopenharmony_ci		module_put(calling_module);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return 0;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_processor_notify_smm);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ciint acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	int result = 0;
5358c2ecf20Sopenharmony_ci	acpi_status status = AE_OK;
5368c2ecf20Sopenharmony_ci	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
5378c2ecf20Sopenharmony_ci	struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
5388c2ecf20Sopenharmony_ci	struct acpi_buffer state = {0, NULL};
5398c2ecf20Sopenharmony_ci	union acpi_object  *psd = NULL;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(handle, "_PSD", NULL, &buffer);
5428c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5438c2ecf20Sopenharmony_ci		return -ENODEV;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	psd = buffer.pointer;
5478c2ecf20Sopenharmony_ci	if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
5488c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PSD data\n");
5498c2ecf20Sopenharmony_ci		result = -EFAULT;
5508c2ecf20Sopenharmony_ci		goto end;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (psd->package.count != 1) {
5548c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PSD data\n");
5558c2ecf20Sopenharmony_ci		result = -EFAULT;
5568c2ecf20Sopenharmony_ci		goto end;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	state.length = sizeof(struct acpi_psd_package);
5608c2ecf20Sopenharmony_ci	state.pointer = pdomain;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	status = acpi_extract_package(&(psd->package.elements[0]),
5638c2ecf20Sopenharmony_ci		&format, &state);
5648c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5658c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PSD data\n");
5668c2ecf20Sopenharmony_ci		result = -EFAULT;
5678c2ecf20Sopenharmony_ci		goto end;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
5718c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Unknown _PSD:num_entries\n");
5728c2ecf20Sopenharmony_ci		result = -EFAULT;
5738c2ecf20Sopenharmony_ci		goto end;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
5778c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Unknown _PSD:revision\n");
5788c2ecf20Sopenharmony_ci		result = -EFAULT;
5798c2ecf20Sopenharmony_ci		goto end;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
5838c2ecf20Sopenharmony_ci	    pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
5848c2ecf20Sopenharmony_ci	    pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
5858c2ecf20Sopenharmony_ci		printk(KERN_ERR PREFIX "Invalid _PSD:coord_type\n");
5868c2ecf20Sopenharmony_ci		result = -EFAULT;
5878c2ecf20Sopenharmony_ci		goto end;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ciend:
5908c2ecf20Sopenharmony_ci	kfree(buffer.pointer);
5918c2ecf20Sopenharmony_ci	return result;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_processor_get_psd);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ciint acpi_processor_preregister_performance(
5968c2ecf20Sopenharmony_ci		struct acpi_processor_performance __percpu *performance)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	int count_target;
5998c2ecf20Sopenharmony_ci	int retval = 0;
6008c2ecf20Sopenharmony_ci	unsigned int i, j;
6018c2ecf20Sopenharmony_ci	cpumask_var_t covered_cpus;
6028c2ecf20Sopenharmony_ci	struct acpi_processor *pr;
6038c2ecf20Sopenharmony_ci	struct acpi_psd_package *pdomain;
6048c2ecf20Sopenharmony_ci	struct acpi_processor *match_pr;
6058c2ecf20Sopenharmony_ci	struct acpi_psd_package *match_pdomain;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
6088c2ecf20Sopenharmony_ci		return -ENOMEM;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	mutex_lock(&performance_mutex);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/*
6138c2ecf20Sopenharmony_ci	 * Check if another driver has already registered, and abort before
6148c2ecf20Sopenharmony_ci	 * changing pr->performance if it has. Check input data as well.
6158c2ecf20Sopenharmony_ci	 */
6168c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
6178c2ecf20Sopenharmony_ci		pr = per_cpu(processors, i);
6188c2ecf20Sopenharmony_ci		if (!pr) {
6198c2ecf20Sopenharmony_ci			/* Look only at processors in ACPI namespace */
6208c2ecf20Sopenharmony_ci			continue;
6218c2ecf20Sopenharmony_ci		}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		if (pr->performance) {
6248c2ecf20Sopenharmony_ci			retval = -EBUSY;
6258c2ecf20Sopenharmony_ci			goto err_out;
6268c2ecf20Sopenharmony_ci		}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci		if (!performance || !per_cpu_ptr(performance, i)) {
6298c2ecf20Sopenharmony_ci			retval = -EINVAL;
6308c2ecf20Sopenharmony_ci			goto err_out;
6318c2ecf20Sopenharmony_ci		}
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* Call _PSD for all CPUs */
6358c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
6368c2ecf20Sopenharmony_ci		pr = per_cpu(processors, i);
6378c2ecf20Sopenharmony_ci		if (!pr)
6388c2ecf20Sopenharmony_ci			continue;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		pr->performance = per_cpu_ptr(performance, i);
6418c2ecf20Sopenharmony_ci		cpumask_set_cpu(i, pr->performance->shared_cpu_map);
6428c2ecf20Sopenharmony_ci		pdomain = &(pr->performance->domain_info);
6438c2ecf20Sopenharmony_ci		if (acpi_processor_get_psd(pr->handle, pdomain)) {
6448c2ecf20Sopenharmony_ci			retval = -EINVAL;
6458c2ecf20Sopenharmony_ci			continue;
6468c2ecf20Sopenharmony_ci		}
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci	if (retval)
6498c2ecf20Sopenharmony_ci		goto err_ret;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/*
6528c2ecf20Sopenharmony_ci	 * Now that we have _PSD data from all CPUs, lets setup P-state
6538c2ecf20Sopenharmony_ci	 * domain info.
6548c2ecf20Sopenharmony_ci	 */
6558c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
6568c2ecf20Sopenharmony_ci		pr = per_cpu(processors, i);
6578c2ecf20Sopenharmony_ci		if (!pr)
6588c2ecf20Sopenharmony_ci			continue;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		if (cpumask_test_cpu(i, covered_cpus))
6618c2ecf20Sopenharmony_ci			continue;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		pdomain = &(pr->performance->domain_info);
6648c2ecf20Sopenharmony_ci		cpumask_set_cpu(i, pr->performance->shared_cpu_map);
6658c2ecf20Sopenharmony_ci		cpumask_set_cpu(i, covered_cpus);
6668c2ecf20Sopenharmony_ci		if (pdomain->num_processors <= 1)
6678c2ecf20Sopenharmony_ci			continue;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		/* Validate the Domain info */
6708c2ecf20Sopenharmony_ci		count_target = pdomain->num_processors;
6718c2ecf20Sopenharmony_ci		if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
6728c2ecf20Sopenharmony_ci			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
6738c2ecf20Sopenharmony_ci		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
6748c2ecf20Sopenharmony_ci			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW;
6758c2ecf20Sopenharmony_ci		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
6768c2ecf20Sopenharmony_ci			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci		for_each_possible_cpu(j) {
6798c2ecf20Sopenharmony_ci			if (i == j)
6808c2ecf20Sopenharmony_ci				continue;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci			match_pr = per_cpu(processors, j);
6838c2ecf20Sopenharmony_ci			if (!match_pr)
6848c2ecf20Sopenharmony_ci				continue;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci			match_pdomain = &(match_pr->performance->domain_info);
6878c2ecf20Sopenharmony_ci			if (match_pdomain->domain != pdomain->domain)
6888c2ecf20Sopenharmony_ci				continue;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci			/* Here i and j are in the same domain */
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci			if (match_pdomain->num_processors != count_target) {
6938c2ecf20Sopenharmony_ci				retval = -EINVAL;
6948c2ecf20Sopenharmony_ci				goto err_ret;
6958c2ecf20Sopenharmony_ci			}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci			if (pdomain->coord_type != match_pdomain->coord_type) {
6988c2ecf20Sopenharmony_ci				retval = -EINVAL;
6998c2ecf20Sopenharmony_ci				goto err_ret;
7008c2ecf20Sopenharmony_ci			}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci			cpumask_set_cpu(j, covered_cpus);
7038c2ecf20Sopenharmony_ci			cpumask_set_cpu(j, pr->performance->shared_cpu_map);
7048c2ecf20Sopenharmony_ci		}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci		for_each_possible_cpu(j) {
7078c2ecf20Sopenharmony_ci			if (i == j)
7088c2ecf20Sopenharmony_ci				continue;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci			match_pr = per_cpu(processors, j);
7118c2ecf20Sopenharmony_ci			if (!match_pr)
7128c2ecf20Sopenharmony_ci				continue;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci			match_pdomain = &(match_pr->performance->domain_info);
7158c2ecf20Sopenharmony_ci			if (match_pdomain->domain != pdomain->domain)
7168c2ecf20Sopenharmony_ci				continue;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci			match_pr->performance->shared_type =
7198c2ecf20Sopenharmony_ci					pr->performance->shared_type;
7208c2ecf20Sopenharmony_ci			cpumask_copy(match_pr->performance->shared_cpu_map,
7218c2ecf20Sopenharmony_ci				     pr->performance->shared_cpu_map);
7228c2ecf20Sopenharmony_ci		}
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_cierr_ret:
7268c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
7278c2ecf20Sopenharmony_ci		pr = per_cpu(processors, i);
7288c2ecf20Sopenharmony_ci		if (!pr || !pr->performance)
7298c2ecf20Sopenharmony_ci			continue;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		/* Assume no coordination on any error parsing domain info */
7328c2ecf20Sopenharmony_ci		if (retval) {
7338c2ecf20Sopenharmony_ci			cpumask_clear(pr->performance->shared_cpu_map);
7348c2ecf20Sopenharmony_ci			cpumask_set_cpu(i, pr->performance->shared_cpu_map);
7358c2ecf20Sopenharmony_ci			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
7368c2ecf20Sopenharmony_ci		}
7378c2ecf20Sopenharmony_ci		pr->performance = NULL; /* Will be set for real in register */
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_cierr_out:
7418c2ecf20Sopenharmony_ci	mutex_unlock(&performance_mutex);
7428c2ecf20Sopenharmony_ci	free_cpumask_var(covered_cpus);
7438c2ecf20Sopenharmony_ci	return retval;
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_processor_preregister_performance);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ciint
7488c2ecf20Sopenharmony_ciacpi_processor_register_performance(struct acpi_processor_performance
7498c2ecf20Sopenharmony_ci				    *performance, unsigned int cpu)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct acpi_processor *pr;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (!acpi_processor_cpufreq_init)
7548c2ecf20Sopenharmony_ci		return -EINVAL;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	mutex_lock(&performance_mutex);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	pr = per_cpu(processors, cpu);
7598c2ecf20Sopenharmony_ci	if (!pr) {
7608c2ecf20Sopenharmony_ci		mutex_unlock(&performance_mutex);
7618c2ecf20Sopenharmony_ci		return -ENODEV;
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (pr->performance) {
7658c2ecf20Sopenharmony_ci		mutex_unlock(&performance_mutex);
7668c2ecf20Sopenharmony_ci		return -EBUSY;
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	WARN_ON(!performance);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	pr->performance = performance;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (acpi_processor_get_performance_info(pr)) {
7748c2ecf20Sopenharmony_ci		pr->performance = NULL;
7758c2ecf20Sopenharmony_ci		mutex_unlock(&performance_mutex);
7768c2ecf20Sopenharmony_ci		return -EIO;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	mutex_unlock(&performance_mutex);
7808c2ecf20Sopenharmony_ci	return 0;
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_processor_register_performance);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_civoid acpi_processor_unregister_performance(unsigned int cpu)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	struct acpi_processor *pr;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	mutex_lock(&performance_mutex);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	pr = per_cpu(processors, cpu);
7928c2ecf20Sopenharmony_ci	if (!pr) {
7938c2ecf20Sopenharmony_ci		mutex_unlock(&performance_mutex);
7948c2ecf20Sopenharmony_ci		return;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	if (pr->performance)
7988c2ecf20Sopenharmony_ci		kfree(pr->performance->states);
7998c2ecf20Sopenharmony_ci	pr->performance = NULL;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	mutex_unlock(&performance_mutex);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_processor_unregister_performance);
807