Merge tag 'nfs-for-4.15-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
[sfrench/cifs-2.6.git] / drivers / acpi / processor_pdc.c
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/dmi.h>
13 #include <linux/slab.h>
14 #include <linux/acpi.h>
15 #include <acpi/processor.h>
16
17 #include "internal.h"
18
19 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
20 ACPI_MODULE_NAME("processor_pdc");
21
22 static bool __init processor_physically_present(acpi_handle handle)
23 {
24         int cpuid, type;
25         u32 acpi_id;
26         acpi_status status;
27         acpi_object_type acpi_type;
28         unsigned long long tmp;
29         union acpi_object object = { 0 };
30         struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
31
32         status = acpi_get_type(handle, &acpi_type);
33         if (ACPI_FAILURE(status))
34                 return false;
35
36         switch (acpi_type) {
37         case ACPI_TYPE_PROCESSOR:
38                 status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
39                 if (ACPI_FAILURE(status))
40                         return false;
41                 acpi_id = object.processor.proc_id;
42                 break;
43         case ACPI_TYPE_DEVICE:
44                 status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp);
45                 if (ACPI_FAILURE(status))
46                         return false;
47                 acpi_id = tmp;
48                 break;
49         default:
50                 return false;
51         }
52
53         type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
54         cpuid = acpi_get_cpuid(handle, type, acpi_id);
55
56         return !invalid_logical_cpuid(cpuid);
57 }
58
59 static void acpi_set_pdc_bits(u32 *buf)
60 {
61         buf[0] = ACPI_PDC_REVISION_ID;
62         buf[1] = 1;
63
64         /* Enable coordination with firmware's _TSD info */
65         buf[2] = ACPI_PDC_SMP_T_SWCOORD;
66
67         /* Twiddle arch-specific bits needed for _PDC */
68         arch_acpi_set_pdc_bits(buf);
69 }
70
71 static struct acpi_object_list *acpi_processor_alloc_pdc(void)
72 {
73         struct acpi_object_list *obj_list;
74         union acpi_object *obj;
75         u32 *buf;
76
77         /* allocate and initialize pdc. It will be used later. */
78         obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
79         if (!obj_list)
80                 goto out;
81
82         obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
83         if (!obj) {
84                 kfree(obj_list);
85                 goto out;
86         }
87
88         buf = kmalloc(12, GFP_KERNEL);
89         if (!buf) {
90                 kfree(obj);
91                 kfree(obj_list);
92                 goto out;
93         }
94
95         acpi_set_pdc_bits(buf);
96
97         obj->type = ACPI_TYPE_BUFFER;
98         obj->buffer.length = 12;
99         obj->buffer.pointer = (u8 *) buf;
100         obj_list->count = 1;
101         obj_list->pointer = obj;
102
103         return obj_list;
104 out:
105         pr_err("Memory allocation error\n");
106         return NULL;
107 }
108
109 /*
110  * _PDC is required for a BIOS-OS handshake for most of the newer
111  * ACPI processor features.
112  */
113 static acpi_status
114 acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
115 {
116         acpi_status status = AE_OK;
117
118         if (boot_option_idle_override == IDLE_NOMWAIT) {
119                 /*
120                  * If mwait is disabled for CPU C-states, the C2C3_FFH access
121                  * mode will be disabled in the parameter of _PDC object.
122                  * Of course C1_FFH access mode will also be disabled.
123                  */
124                 union acpi_object *obj;
125                 u32 *buffer = NULL;
126
127                 obj = pdc_in->pointer;
128                 buffer = (u32 *)(obj->buffer.pointer);
129                 buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
130
131         }
132         status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
133
134         if (ACPI_FAILURE(status))
135                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
136                     "Could not evaluate _PDC, using legacy perf. control.\n"));
137
138         return status;
139 }
140
141 void acpi_processor_set_pdc(acpi_handle handle)
142 {
143         struct acpi_object_list *obj_list;
144
145         if (arch_has_acpi_pdc() == false)
146                 return;
147
148         obj_list = acpi_processor_alloc_pdc();
149         if (!obj_list)
150                 return;
151
152         acpi_processor_eval_pdc(handle, obj_list);
153
154         kfree(obj_list->pointer->buffer.pointer);
155         kfree(obj_list->pointer);
156         kfree(obj_list);
157 }
158
159 static acpi_status __init
160 early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
161 {
162         if (processor_physically_present(handle) == false)
163                 return AE_OK;
164
165         acpi_processor_set_pdc(handle);
166         return AE_OK;
167 }
168
169 static int __init set_no_mwait(const struct dmi_system_id *id)
170 {
171         pr_notice("%s detected - disabling mwait for CPU C-states\n",
172                   id->ident);
173         boot_option_idle_override = IDLE_NOMWAIT;
174         return 0;
175 }
176
177 static const struct dmi_system_id processor_idle_dmi_table[] __initconst = {
178         {
179         set_no_mwait, "Extensa 5220", {
180         DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
181         DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
182         DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
183         DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
184         {},
185 };
186
187 static void __init processor_dmi_check(void)
188 {
189         /*
190          * Check whether the system is DMI table. If yes, OSPM
191          * should not use mwait for CPU-states.
192          */
193         dmi_check_system(processor_idle_dmi_table);
194 }
195
196 void __init acpi_early_processor_set_pdc(void)
197 {
198         processor_dmi_check();
199
200         acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
201                             ACPI_UINT32_MAX,
202                             early_init_pdc, NULL, NULL, NULL);
203         acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL);
204 }