18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005 Intel Corporation 48c2ecf20Sopenharmony_ci * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 78c2ecf20Sopenharmony_ci * - Added _PDC for platforms with Intel CPUs 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "ACPI: " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/dmi.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/acpi.h> 158c2ecf20Sopenharmony_ci#include <acpi/processor.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <xen/xen.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "internal.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define _COMPONENT ACPI_PROCESSOR_COMPONENT 228c2ecf20Sopenharmony_ciACPI_MODULE_NAME("processor_pdc"); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic bool __init processor_physically_present(acpi_handle handle) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci int cpuid, type; 278c2ecf20Sopenharmony_ci u32 acpi_id; 288c2ecf20Sopenharmony_ci acpi_status status; 298c2ecf20Sopenharmony_ci acpi_object_type acpi_type; 308c2ecf20Sopenharmony_ci unsigned long long tmp; 318c2ecf20Sopenharmony_ci union acpi_object object = { 0 }; 328c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci status = acpi_get_type(handle, &acpi_type); 358c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 368c2ecf20Sopenharmony_ci return false; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci switch (acpi_type) { 398c2ecf20Sopenharmony_ci case ACPI_TYPE_PROCESSOR: 408c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, NULL, NULL, &buffer); 418c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 428c2ecf20Sopenharmony_ci return false; 438c2ecf20Sopenharmony_ci acpi_id = object.processor.proc_id; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case ACPI_TYPE_DEVICE: 468c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); 478c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 488c2ecf20Sopenharmony_ci return false; 498c2ecf20Sopenharmony_ci acpi_id = tmp; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci default: 528c2ecf20Sopenharmony_ci return false; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (xen_initial_domain()) 568c2ecf20Sopenharmony_ci /* 578c2ecf20Sopenharmony_ci * When running as a Xen dom0 the number of processors Linux 588c2ecf20Sopenharmony_ci * sees can be different from the real number of processors on 598c2ecf20Sopenharmony_ci * the system, and we still need to execute _PDC for all of 608c2ecf20Sopenharmony_ci * them. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci return xen_processor_present(acpi_id); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; 658c2ecf20Sopenharmony_ci cpuid = acpi_get_cpuid(handle, type, acpi_id); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return !invalid_logical_cpuid(cpuid); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void acpi_set_pdc_bits(u32 *buf) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci buf[0] = ACPI_PDC_REVISION_ID; 738c2ecf20Sopenharmony_ci buf[1] = 1; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Enable coordination with firmware's _TSD info */ 768c2ecf20Sopenharmony_ci buf[2] = ACPI_PDC_SMP_T_SWCOORD; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Twiddle arch-specific bits needed for _PDC */ 798c2ecf20Sopenharmony_ci arch_acpi_set_pdc_bits(buf); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic struct acpi_object_list *acpi_processor_alloc_pdc(void) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct acpi_object_list *obj_list; 858c2ecf20Sopenharmony_ci union acpi_object *obj; 868c2ecf20Sopenharmony_ci u32 *buf; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* allocate and initialize pdc. It will be used later. */ 898c2ecf20Sopenharmony_ci obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); 908c2ecf20Sopenharmony_ci if (!obj_list) 918c2ecf20Sopenharmony_ci goto out; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); 948c2ecf20Sopenharmony_ci if (!obj) { 958c2ecf20Sopenharmony_ci kfree(obj_list); 968c2ecf20Sopenharmony_ci goto out; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci buf = kmalloc(12, GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (!buf) { 1018c2ecf20Sopenharmony_ci kfree(obj); 1028c2ecf20Sopenharmony_ci kfree(obj_list); 1038c2ecf20Sopenharmony_ci goto out; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci acpi_set_pdc_bits(buf); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci obj->type = ACPI_TYPE_BUFFER; 1098c2ecf20Sopenharmony_ci obj->buffer.length = 12; 1108c2ecf20Sopenharmony_ci obj->buffer.pointer = (u8 *) buf; 1118c2ecf20Sopenharmony_ci obj_list->count = 1; 1128c2ecf20Sopenharmony_ci obj_list->pointer = obj; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return obj_list; 1158c2ecf20Sopenharmony_ciout: 1168c2ecf20Sopenharmony_ci pr_err("Memory allocation error\n"); 1178c2ecf20Sopenharmony_ci return NULL; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* 1218c2ecf20Sopenharmony_ci * _PDC is required for a BIOS-OS handshake for most of the newer 1228c2ecf20Sopenharmony_ci * ACPI processor features. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistatic acpi_status 1258c2ecf20Sopenharmony_ciacpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (boot_option_idle_override == IDLE_NOMWAIT) { 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * If mwait is disabled for CPU C-states, the C2C3_FFH access 1328c2ecf20Sopenharmony_ci * mode will be disabled in the parameter of _PDC object. 1338c2ecf20Sopenharmony_ci * Of course C1_FFH access mode will also be disabled. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci union acpi_object *obj; 1368c2ecf20Sopenharmony_ci u32 *buffer = NULL; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci obj = pdc_in->pointer; 1398c2ecf20Sopenharmony_ci buffer = (u32 *)(obj->buffer.pointer); 1408c2ecf20Sopenharmony_ci buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1468c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1478c2ecf20Sopenharmony_ci "Could not evaluate _PDC, using legacy perf. control.\n")); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return status; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_civoid acpi_processor_set_pdc(acpi_handle handle) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct acpi_object_list *obj_list; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (arch_has_acpi_pdc() == false) 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci obj_list = acpi_processor_alloc_pdc(); 1608c2ecf20Sopenharmony_ci if (!obj_list) 1618c2ecf20Sopenharmony_ci return; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci acpi_processor_eval_pdc(handle, obj_list); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci kfree(obj_list->pointer->buffer.pointer); 1668c2ecf20Sopenharmony_ci kfree(obj_list->pointer); 1678c2ecf20Sopenharmony_ci kfree(obj_list); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic acpi_status __init 1718c2ecf20Sopenharmony_ciearly_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci if (processor_physically_present(handle) == false) 1748c2ecf20Sopenharmony_ci return AE_OK; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci acpi_processor_set_pdc(handle); 1778c2ecf20Sopenharmony_ci return AE_OK; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int __init set_no_mwait(const struct dmi_system_id *id) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci pr_notice("%s detected - disabling mwait for CPU C-states\n", 1838c2ecf20Sopenharmony_ci id->ident); 1848c2ecf20Sopenharmony_ci boot_option_idle_override = IDLE_NOMWAIT; 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic const struct dmi_system_id processor_idle_dmi_table[] __initconst = { 1898c2ecf20Sopenharmony_ci { 1908c2ecf20Sopenharmony_ci set_no_mwait, "Extensa 5220", { 1918c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), 1928c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 1938c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), 1948c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, 1958c2ecf20Sopenharmony_ci {}, 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void __init processor_dmi_check(void) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Check whether the system is DMI table. If yes, OSPM 2028c2ecf20Sopenharmony_ci * should not use mwait for CPU-states. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci dmi_check_system(processor_idle_dmi_table); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_civoid __init acpi_early_processor_set_pdc(void) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci processor_dmi_check(); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 2128c2ecf20Sopenharmony_ci ACPI_UINT32_MAX, 2138c2ecf20Sopenharmony_ci early_init_pdc, NULL, NULL, NULL); 2148c2ecf20Sopenharmony_ci acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL); 2158c2ecf20Sopenharmony_ci} 216