1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2005 Intel Corporation 4 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 5 * 6 * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 7 * - Added _PDC for platforms with Intel CPUs 8 */ 9 10#define pr_fmt(fmt) "ACPI: " fmt 11 12#include <linux/slab.h> 13#include <linux/acpi.h> 14#include <acpi/processor.h> 15 16#include "internal.h" 17 18static void acpi_set_pdc_bits(u32 *buf) 19{ 20 buf[0] = ACPI_PDC_REVISION_ID; 21 buf[1] = 1; 22 buf[2] = 0; 23 24 /* Twiddle arch-specific bits needed for _PDC */ 25 arch_acpi_set_proc_cap_bits(&buf[2]); 26} 27 28static struct acpi_object_list *acpi_processor_alloc_pdc(void) 29{ 30 struct acpi_object_list *obj_list; 31 union acpi_object *obj; 32 u32 *buf; 33 34 /* allocate and initialize pdc. It will be used later. */ 35 obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); 36 if (!obj_list) 37 goto out; 38 39 obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); 40 if (!obj) { 41 kfree(obj_list); 42 goto out; 43 } 44 45 buf = kmalloc(12, GFP_KERNEL); 46 if (!buf) { 47 kfree(obj); 48 kfree(obj_list); 49 goto out; 50 } 51 52 acpi_set_pdc_bits(buf); 53 54 obj->type = ACPI_TYPE_BUFFER; 55 obj->buffer.length = 12; 56 obj->buffer.pointer = (u8 *) buf; 57 obj_list->count = 1; 58 obj_list->pointer = obj; 59 60 return obj_list; 61out: 62 pr_err("Memory allocation error\n"); 63 return NULL; 64} 65 66/* 67 * _PDC is required for a BIOS-OS handshake for most of the newer 68 * ACPI processor features. 69 */ 70static acpi_status 71acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) 72{ 73 acpi_status status = AE_OK; 74 75 status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); 76 77 if (ACPI_FAILURE(status)) 78 acpi_handle_debug(handle, 79 "Could not evaluate _PDC, using legacy perf control\n"); 80 81 return status; 82} 83 84void acpi_processor_set_pdc(acpi_handle handle) 85{ 86 struct acpi_object_list *obj_list; 87 88 if (arch_has_acpi_pdc() == false) 89 return; 90 91 obj_list = acpi_processor_alloc_pdc(); 92 if (!obj_list) 93 return; 94 95 acpi_processor_eval_pdc(handle, obj_list); 96 97 kfree(obj_list->pointer->buffer.pointer); 98 kfree(obj_list->pointer); 99 kfree(obj_list); 100} 101 102static acpi_status __init 103early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) 104{ 105 if (processor_physically_present(handle) == false) 106 return AE_OK; 107 108 acpi_processor_set_pdc(handle); 109 return AE_OK; 110} 111 112void __init acpi_early_processor_set_pdc(void) 113{ 114 acpi_proc_quirk_mwait_check(); 115 116 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 117 ACPI_UINT32_MAX, 118 early_init_pdc, NULL, NULL, NULL); 119 acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL); 120} 121