1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 246ba51eaSHanjun Guo /* 346ba51eaSHanjun Guo * Copyright (C) 2005 Intel Corporation 446ba51eaSHanjun Guo * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 546ba51eaSHanjun Guo * 646ba51eaSHanjun Guo * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 746ba51eaSHanjun Guo * - Added _PDC for platforms with Intel CPUs 846ba51eaSHanjun Guo */ 946ba51eaSHanjun Guo 1046ba51eaSHanjun Guo #define pr_fmt(fmt) "ACPI: " fmt 1146ba51eaSHanjun Guo 1246ba51eaSHanjun Guo #include <linux/slab.h> 1346ba51eaSHanjun Guo #include <linux/acpi.h> 1446ba51eaSHanjun Guo #include <acpi/processor.h> 1546ba51eaSHanjun Guo 1646ba51eaSHanjun Guo #include "internal.h" 1746ba51eaSHanjun Guo 1846ba51eaSHanjun Guo static void acpi_set_pdc_bits(u32 *buf) 1946ba51eaSHanjun Guo { 2046ba51eaSHanjun Guo buf[0] = ACPI_PDC_REVISION_ID; 2146ba51eaSHanjun Guo buf[1] = 1; 2246ba51eaSHanjun Guo 2346ba51eaSHanjun Guo /* Enable coordination with firmware's _TSD info */ 2446ba51eaSHanjun Guo buf[2] = ACPI_PDC_SMP_T_SWCOORD; 2546ba51eaSHanjun Guo 2646ba51eaSHanjun Guo /* Twiddle arch-specific bits needed for _PDC */ 27*c5e4d05dSMichal Wilczynski arch_acpi_set_proc_cap_bits(&buf[2]); 2846ba51eaSHanjun Guo } 2946ba51eaSHanjun Guo 3046ba51eaSHanjun Guo static struct acpi_object_list *acpi_processor_alloc_pdc(void) 3146ba51eaSHanjun Guo { 3246ba51eaSHanjun Guo struct acpi_object_list *obj_list; 3346ba51eaSHanjun Guo union acpi_object *obj; 3446ba51eaSHanjun Guo u32 *buf; 3546ba51eaSHanjun Guo 3646ba51eaSHanjun Guo /* allocate and initialize pdc. It will be used later. */ 3746ba51eaSHanjun Guo obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); 3846ba51eaSHanjun Guo if (!obj_list) 3946ba51eaSHanjun Guo goto out; 4046ba51eaSHanjun Guo 4146ba51eaSHanjun Guo obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); 4246ba51eaSHanjun Guo if (!obj) { 4346ba51eaSHanjun Guo kfree(obj_list); 4446ba51eaSHanjun Guo goto out; 4546ba51eaSHanjun Guo } 4646ba51eaSHanjun Guo 4746ba51eaSHanjun Guo buf = kmalloc(12, GFP_KERNEL); 4846ba51eaSHanjun Guo if (!buf) { 4946ba51eaSHanjun Guo kfree(obj); 5046ba51eaSHanjun Guo kfree(obj_list); 5146ba51eaSHanjun Guo goto out; 5246ba51eaSHanjun Guo } 5346ba51eaSHanjun Guo 5446ba51eaSHanjun Guo acpi_set_pdc_bits(buf); 5546ba51eaSHanjun Guo 5646ba51eaSHanjun Guo obj->type = ACPI_TYPE_BUFFER; 5746ba51eaSHanjun Guo obj->buffer.length = 12; 5846ba51eaSHanjun Guo obj->buffer.pointer = (u8 *) buf; 5946ba51eaSHanjun Guo obj_list->count = 1; 6046ba51eaSHanjun Guo obj_list->pointer = obj; 6146ba51eaSHanjun Guo 6246ba51eaSHanjun Guo return obj_list; 6346ba51eaSHanjun Guo out: 6446ba51eaSHanjun Guo pr_err("Memory allocation error\n"); 6546ba51eaSHanjun Guo return NULL; 6646ba51eaSHanjun Guo } 6746ba51eaSHanjun Guo 6846ba51eaSHanjun Guo /* 6946ba51eaSHanjun Guo * _PDC is required for a BIOS-OS handshake for most of the newer 7046ba51eaSHanjun Guo * ACPI processor features. 7146ba51eaSHanjun Guo */ 7246ba51eaSHanjun Guo static acpi_status 7346ba51eaSHanjun Guo acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) 7446ba51eaSHanjun Guo { 7546ba51eaSHanjun Guo acpi_status status = AE_OK; 7646ba51eaSHanjun Guo 7746ba51eaSHanjun Guo if (boot_option_idle_override == IDLE_NOMWAIT) { 7846ba51eaSHanjun Guo /* 7946ba51eaSHanjun Guo * If mwait is disabled for CPU C-states, the C2C3_FFH access 8046ba51eaSHanjun Guo * mode will be disabled in the parameter of _PDC object. 8146ba51eaSHanjun Guo * Of course C1_FFH access mode will also be disabled. 8246ba51eaSHanjun Guo */ 8346ba51eaSHanjun Guo union acpi_object *obj; 8446ba51eaSHanjun Guo u32 *buffer = NULL; 8546ba51eaSHanjun Guo 8646ba51eaSHanjun Guo obj = pdc_in->pointer; 8746ba51eaSHanjun Guo buffer = (u32 *)(obj->buffer.pointer); 8846ba51eaSHanjun Guo buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); 8946ba51eaSHanjun Guo 9046ba51eaSHanjun Guo } 9146ba51eaSHanjun Guo status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); 9246ba51eaSHanjun Guo 9346ba51eaSHanjun Guo if (ACPI_FAILURE(status)) 9452af99c3SRafael J. Wysocki acpi_handle_debug(handle, 9552af99c3SRafael J. Wysocki "Could not evaluate _PDC, using legacy perf control\n"); 9646ba51eaSHanjun Guo 9746ba51eaSHanjun Guo return status; 9846ba51eaSHanjun Guo } 9946ba51eaSHanjun Guo 10046ba51eaSHanjun Guo void acpi_processor_set_pdc(acpi_handle handle) 10146ba51eaSHanjun Guo { 10246ba51eaSHanjun Guo struct acpi_object_list *obj_list; 10346ba51eaSHanjun Guo 10446ba51eaSHanjun Guo if (arch_has_acpi_pdc() == false) 10546ba51eaSHanjun Guo return; 10646ba51eaSHanjun Guo 10746ba51eaSHanjun Guo obj_list = acpi_processor_alloc_pdc(); 10846ba51eaSHanjun Guo if (!obj_list) 10946ba51eaSHanjun Guo return; 11046ba51eaSHanjun Guo 11146ba51eaSHanjun Guo acpi_processor_eval_pdc(handle, obj_list); 11246ba51eaSHanjun Guo 11346ba51eaSHanjun Guo kfree(obj_list->pointer->buffer.pointer); 11446ba51eaSHanjun Guo kfree(obj_list->pointer); 11546ba51eaSHanjun Guo kfree(obj_list); 11646ba51eaSHanjun Guo } 11746ba51eaSHanjun Guo 11846ba51eaSHanjun Guo static acpi_status __init 11946ba51eaSHanjun Guo early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) 12046ba51eaSHanjun Guo { 12146ba51eaSHanjun Guo if (processor_physically_present(handle) == false) 12246ba51eaSHanjun Guo return AE_OK; 12346ba51eaSHanjun Guo 12446ba51eaSHanjun Guo acpi_processor_set_pdc(handle); 12546ba51eaSHanjun Guo return AE_OK; 12646ba51eaSHanjun Guo } 12746ba51eaSHanjun Guo 12846ba51eaSHanjun Guo void __init acpi_early_processor_set_pdc(void) 12946ba51eaSHanjun Guo { 1300a0e2ea6SMichal Wilczynski acpi_proc_quirk_mwait_check(); 13146ba51eaSHanjun Guo 13246ba51eaSHanjun Guo acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 13346ba51eaSHanjun Guo ACPI_UINT32_MAX, 13446ba51eaSHanjun Guo early_init_pdc, NULL, NULL, NULL); 13546ba51eaSHanjun Guo acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL); 13646ba51eaSHanjun Guo } 137