121 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2005 Intel Corporation4 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.5 *6 * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>7 * - Added _PDC for platforms with Intel CPUs8 */9 10#define pr_fmt(fmt) "ACPI: " fmt11 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 newer68 * ACPI processor features.69 */70static acpi_status71acpi_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 __init103early_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