From 7470a272084dbd9d95e60770cc10ede42ebdcb7b Mon Sep 17 00:00:00 2001
From: Xiongfeng Wang <wangxiongfeng2@huawei.com>
Date: Mon, 10 Jan 2022 17:33:40 +0800
Subject: [PATCH] ACPI: CPPC: Fix cppc_cpufreq_init failed in CPU Hotplug
 situation

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I4HYY4
CVE: NA

-------------------------------------------------

Per-CPU variables cpc_desc_ptr are initialized in
acpi_cppc_processor_probe() when the processor devices are present and
added into the system. But when cpu_possible_mask and cpu_present_mask
is not equal, only cpc_desc_ptr in cpu_present_mask are initialized,
this will cause acpi_get_psd_map() failed in cppc_cpufreq_init().

To fix this issue, we parse the _PSD method for all possible CPUs to get
the P-State topology and modify acpi_get_psd_map() to rely on this
information.

Signed-off-by: Xiongfeng Wang <wangxiongfeng@huawei.com>
Reviewed-by: Keqian Zhu <zhukeqian1@huawei.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Cheng Jian <cj.chengjian@huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>

 Conflicts:
	drivers/acpi/cppc_acpi.c
Signed-off-by: Xiongfeng Wang <wangxiongfeng@huawei.com>
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
---
 drivers/acpi/cppc_acpi.c | 91 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 0a2da06e9d8b..dc8ac435dea1 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -411,7 +411,7 @@ static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle)
  *
  *	Return: 0 for success or negative value for err.
  */
-int acpi_get_psd_map(struct cppc_cpudata **all_cpu_data)
+static int __acpi_get_psd_map(struct cppc_cpudata **all_cpu_data, struct cpc_desc **cpc_pptr)
 {
 	int count_target;
 	int retval = 0;
@@ -434,7 +434,7 @@ int acpi_get_psd_map(struct cppc_cpudata **all_cpu_data)
 			continue;
 
 		pr = all_cpu_data[i];
-		cpc_ptr = per_cpu(cpc_desc_ptr, i);
+		cpc_ptr = cpc_pptr[i];
 		if (!cpc_ptr) {
 			retval = -EFAULT;
 			goto err_ret;
@@ -459,7 +459,7 @@ int acpi_get_psd_map(struct cppc_cpudata **all_cpu_data)
 			if (i == j)
 				continue;
 
-			match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
+			match_cpc_ptr = cpc_pptr[j];
 			if (!match_cpc_ptr) {
 				retval = -EFAULT;
 				goto err_ret;
@@ -509,6 +509,91 @@ int acpi_get_psd_map(struct cppc_cpudata **all_cpu_data)
 	free_cpumask_var(covered_cpus);
 	return retval;
 }
+
+static acpi_status acpi_parse_cpc(acpi_handle handle, u32 lvl, void *data,
+				  void **ret_p)
+{
+	struct acpi_device *adev = NULL;
+	struct cpc_desc *cpc_ptr, **cpc_pptr;
+	acpi_status status = AE_OK;
+	const int device_declaration = 1;
+	unsigned long long uid;
+	phys_cpuid_t phys_id;
+	int logical_id, ret;
+	int *parsed_core_num = (int *)ret_p;
+
+	if (acpi_bus_get_device(handle, &adev))
+		return AE_OK;
+
+	if (strcmp(acpi_device_hid(adev), ACPI_PROCESSOR_DEVICE_HID))
+		return AE_OK;
+
+	status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid);
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+	phys_id = acpi_get_phys_id(handle, device_declaration, uid);
+	if (invalid_phys_cpuid(phys_id))
+		return AE_OK;
+	logical_id = acpi_map_cpuid(phys_id, uid);
+	if (logical_id < 0)
+		return AE_OK;
+
+	cpc_pptr = (struct cpc_desc **)data;
+	cpc_ptr = cpc_pptr[logical_id];
+	cpc_ptr->cpu_id = logical_id;
+
+	ret = acpi_get_psd(cpc_ptr, handle);
+	if (ret)
+		return ret;
+
+	(*parsed_core_num)++;
+
+	return AE_OK;
+}
+
+int acpi_get_psd_map(struct cppc_cpudata **all_cpu_data)
+{
+	struct cpc_desc **cpc_pptr, *cpc_ptr;
+	int parsed_core_num = 0;
+	int i, ret;
+
+	cpc_pptr = kcalloc(num_possible_cpus(), sizeof(void *), GFP_KERNEL);
+	if (!cpc_pptr)
+		return -ENOMEM;
+	for_each_possible_cpu(i) {
+		cpc_pptr[i] = kzalloc(sizeof(struct cpc_desc), GFP_KERNEL);
+		if (!cpc_pptr[i]) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
+	/*
+	 * We can not use acpi_get_devices() to walk the processor devices
+	 * because some processor device is not present.
+	 */
+	ret = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_parse_cpc, NULL,
+				  cpc_pptr, (void **)&parsed_core_num);
+	if (ret)
+		goto out;
+	if (parsed_core_num != num_possible_cpus()) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = __acpi_get_psd_map(all_cpu_data, cpc_pptr);
+
+out:
+	for_each_possible_cpu(i) {
+		cpc_ptr = cpc_pptr[i];
+		if (cpc_ptr)
+			kfree(cpc_ptr);
+	}
+	kfree(cpc_pptr);
+
+	return ret;
+}
 EXPORT_SYMBOL_GPL(acpi_get_psd_map);
 
 static int register_pcc_channel(int pcc_ss_idx)
-- 
GitLab