Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * processor_perflib.c - ACPI Processor P-States Library ($Revision: 71 $)
4 : : *
5 : : * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
6 : : * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 : : * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
8 : : * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
9 : : * - Added processor hotplug support
10 : : */
11 : :
12 : : #include <linux/kernel.h>
13 : : #include <linux/module.h>
14 : : #include <linux/init.h>
15 : : #include <linux/cpufreq.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/acpi.h>
18 : : #include <acpi/processor.h>
19 : : #ifdef CONFIG_X86
20 : : #include <asm/cpufeature.h>
21 : : #endif
22 : :
23 : : #define PREFIX "ACPI: "
24 : :
25 : : #define ACPI_PROCESSOR_CLASS "processor"
26 : : #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
27 : : #define _COMPONENT ACPI_PROCESSOR_COMPONENT
28 : : ACPI_MODULE_NAME("processor_perflib");
29 : :
30 : : static DEFINE_MUTEX(performance_mutex);
31 : :
32 : : /*
33 : : * _PPC support is implemented as a CPUfreq policy notifier:
34 : : * This means each time a CPUfreq driver registered also with
35 : : * the ACPI core is asked to change the speed policy, the maximum
36 : : * value is adjusted so that it is within the platform limit.
37 : : *
38 : : * Also, when a new platform limit value is detected, the CPUfreq
39 : : * policy is adjusted accordingly.
40 : : */
41 : :
42 : : /* ignore_ppc:
43 : : * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet
44 : : * ignore _PPC
45 : : * 0 -> cpufreq low level drivers initialized -> consider _PPC values
46 : : * 1 -> ignore _PPC totally -> forced by user through boot param
47 : : */
48 : : static int ignore_ppc = -1;
49 : : module_param(ignore_ppc, int, 0644);
50 : : MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
51 : : "limited by BIOS, this should help");
52 : :
53 : : static bool acpi_processor_ppc_in_use;
54 : :
55 : 0 : static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
56 : : {
57 : 0 : acpi_status status = 0;
58 : 0 : unsigned long long ppc = 0;
59 : 0 : int ret;
60 : :
61 [ # # ]: 0 : if (!pr)
62 : : return -EINVAL;
63 : :
64 : : /*
65 : : * _PPC indicates the maximum state currently supported by the platform
66 : : * (e.g. 0 = states 0..n; 1 = states 1..n; etc.
67 : : */
68 : 0 : status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
69 : :
70 [ # # ]: 0 : if (status != AE_NOT_FOUND)
71 : 0 : acpi_processor_ppc_in_use = true;
72 : :
73 [ # # ]: 0 : if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
74 : 0 : ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
75 : 0 : return -ENODEV;
76 : : }
77 : :
78 : 0 : pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
79 : : (int)ppc, ppc ? "" : "not");
80 : :
81 : 0 : pr->performance_platform_limit = (int)ppc;
82 : :
83 [ # # ]: 0 : if (ppc >= pr->performance->state_count ||
84 [ # # # # ]: 0 : unlikely(!freq_qos_request_active(&pr->perflib_req)))
85 : : return 0;
86 : :
87 : 0 : ret = freq_qos_update_request(&pr->perflib_req,
88 : 0 : pr->performance->states[ppc].core_frequency * 1000);
89 [ # # ]: 0 : if (ret < 0) {
90 : 0 : pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n",
91 : : pr->id, ret);
92 : : }
93 : :
94 : : return 0;
95 : : }
96 : :
97 : : #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
98 : : /*
99 : : * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status
100 : : * @handle: ACPI processor handle
101 : : * @status: the status code of _PPC evaluation
102 : : * 0: success. OSPM is now using the performance state specificed.
103 : : * 1: failure. OSPM has not changed the number of P-states in use
104 : : */
105 : 0 : static void acpi_processor_ppc_ost(acpi_handle handle, int status)
106 : : {
107 [ # # ]: 0 : if (acpi_has_method(handle, "_OST"))
108 : 0 : acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE,
109 : : status, NULL);
110 : 0 : }
111 : :
112 : 28 : void acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
113 : : {
114 : 28 : int ret;
115 : :
116 [ - + - - ]: 28 : if (ignore_ppc || !pr->performance) {
117 : : /*
118 : : * Only when it is notification event, the _OST object
119 : : * will be evaluated. Otherwise it is skipped.
120 : : */
121 [ - + ]: 28 : if (event_flag)
122 : 0 : acpi_processor_ppc_ost(pr->handle, 1);
123 : 28 : return;
124 : : }
125 : :
126 : 0 : ret = acpi_processor_get_platform_limit(pr);
127 : : /*
128 : : * Only when it is notification event, the _OST object
129 : : * will be evaluated. Otherwise it is skipped.
130 : : */
131 [ # # ]: 0 : if (event_flag) {
132 [ # # ]: 0 : if (ret < 0)
133 : 0 : acpi_processor_ppc_ost(pr->handle, 1);
134 : : else
135 : 0 : acpi_processor_ppc_ost(pr->handle, 0);
136 : : }
137 [ # # ]: 0 : if (ret >= 0)
138 : 0 : cpufreq_update_limits(pr->id);
139 : : }
140 : :
141 : 0 : int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
142 : : {
143 : 0 : struct acpi_processor *pr;
144 : :
145 : 0 : pr = per_cpu(processors, cpu);
146 [ # # # # : 0 : if (!pr || !pr->performance || !pr->performance->state_count)
# # ]
147 : : return -ENODEV;
148 : 0 : *limit = pr->performance->states[pr->performance_platform_limit].
149 : : core_frequency * 1000;
150 : 0 : return 0;
151 : : }
152 : : EXPORT_SYMBOL(acpi_processor_get_bios_limit);
153 : :
154 : 28 : void acpi_processor_ignore_ppc_init(void)
155 : : {
156 [ + - ]: 28 : if (ignore_ppc < 0)
157 : 28 : ignore_ppc = 0;
158 : 28 : }
159 : :
160 : 0 : void acpi_processor_ppc_init(struct cpufreq_policy *policy)
161 : : {
162 : 0 : unsigned int cpu;
163 : :
164 [ # # ]: 0 : for_each_cpu(cpu, policy->related_cpus) {
165 : 0 : struct acpi_processor *pr = per_cpu(processors, cpu);
166 : 0 : int ret;
167 : :
168 [ # # ]: 0 : if (!pr)
169 : 0 : continue;
170 : :
171 : 0 : ret = freq_qos_add_request(&policy->constraints,
172 : : &pr->perflib_req,
173 : : FREQ_QOS_MAX, INT_MAX);
174 [ # # ]: 0 : if (ret < 0)
175 : 0 : pr_err("Failed to add freq constraint for CPU%d (%d)\n",
176 : : cpu, ret);
177 : : }
178 : 0 : }
179 : :
180 : 0 : void acpi_processor_ppc_exit(struct cpufreq_policy *policy)
181 : : {
182 : 0 : unsigned int cpu;
183 : :
184 [ # # ]: 0 : for_each_cpu(cpu, policy->related_cpus) {
185 : 0 : struct acpi_processor *pr = per_cpu(processors, cpu);
186 : :
187 [ # # ]: 0 : if (pr)
188 : 0 : freq_qos_remove_request(&pr->perflib_req);
189 : : }
190 : 0 : }
191 : :
192 : : static int acpi_processor_get_performance_control(struct acpi_processor *pr)
193 : : {
194 : : int result = 0;
195 : : acpi_status status = 0;
196 : : struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
197 : : union acpi_object *pct = NULL;
198 : : union acpi_object obj = { 0 };
199 : :
200 : :
201 : : status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
202 : : if (ACPI_FAILURE(status)) {
203 : : ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT"));
204 : : return -ENODEV;
205 : : }
206 : :
207 : : pct = (union acpi_object *)buffer.pointer;
208 : : if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
209 : : || (pct->package.count != 2)) {
210 : : printk(KERN_ERR PREFIX "Invalid _PCT data\n");
211 : : result = -EFAULT;
212 : : goto end;
213 : : }
214 : :
215 : : /*
216 : : * control_register
217 : : */
218 : :
219 : : obj = pct->package.elements[0];
220 : :
221 : : if ((obj.type != ACPI_TYPE_BUFFER)
222 : : || (obj.buffer.length < sizeof(struct acpi_pct_register))
223 : : || (obj.buffer.pointer == NULL)) {
224 : : printk(KERN_ERR PREFIX "Invalid _PCT data (control_register)\n");
225 : : result = -EFAULT;
226 : : goto end;
227 : : }
228 : : memcpy(&pr->performance->control_register, obj.buffer.pointer,
229 : : sizeof(struct acpi_pct_register));
230 : :
231 : : /*
232 : : * status_register
233 : : */
234 : :
235 : : obj = pct->package.elements[1];
236 : :
237 : : if ((obj.type != ACPI_TYPE_BUFFER)
238 : : || (obj.buffer.length < sizeof(struct acpi_pct_register))
239 : : || (obj.buffer.pointer == NULL)) {
240 : : printk(KERN_ERR PREFIX "Invalid _PCT data (status_register)\n");
241 : : result = -EFAULT;
242 : : goto end;
243 : : }
244 : :
245 : : memcpy(&pr->performance->status_register, obj.buffer.pointer,
246 : : sizeof(struct acpi_pct_register));
247 : :
248 : : end:
249 : : kfree(buffer.pointer);
250 : :
251 : : return result;
252 : : }
253 : :
254 : : #ifdef CONFIG_X86
255 : : /*
256 : : * Some AMDs have 50MHz frequency multiples, but only provide 100MHz rounding
257 : : * in their ACPI data. Calculate the real values and fix up the _PSS data.
258 : : */
259 : : static void amd_fixup_frequency(struct acpi_processor_px *px, int i)
260 : : {
261 : : u32 hi, lo, fid, did;
262 : : int index = px->control & 0x00000007;
263 : :
264 : : if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
265 : : return;
266 : :
267 : : if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
268 : : || boot_cpu_data.x86 == 0x11) {
269 : : rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi);
270 : : /*
271 : : * MSR C001_0064+:
272 : : * Bit 63: PstateEn. Read-write. If set, the P-state is valid.
273 : : */
274 : : if (!(hi & BIT(31)))
275 : : return;
276 : :
277 : : fid = lo & 0x3f;
278 : : did = (lo >> 6) & 7;
279 : : if (boot_cpu_data.x86 == 0x10)
280 : : px->core_frequency = (100 * (fid + 0x10)) >> did;
281 : : else
282 : : px->core_frequency = (100 * (fid + 8)) >> did;
283 : : }
284 : : }
285 : : #else
286 : : static void amd_fixup_frequency(struct acpi_processor_px *px, int i) {};
287 : : #endif
288 : :
289 : 0 : static int acpi_processor_get_performance_states(struct acpi_processor *pr)
290 : : {
291 : 0 : int result = 0;
292 : 0 : acpi_status status = AE_OK;
293 : 0 : struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
294 : 0 : struct acpi_buffer format = { sizeof("NNNNNN"), "NNNNNN" };
295 : 0 : struct acpi_buffer state = { 0, NULL };
296 : 0 : union acpi_object *pss = NULL;
297 : 0 : int i;
298 : 0 : int last_invalid = -1;
299 : :
300 : :
301 : 0 : status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
302 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
303 : 0 : ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS"));
304 : 0 : return -ENODEV;
305 : : }
306 : :
307 : 0 : pss = buffer.pointer;
308 [ # # # # ]: 0 : if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
309 : 0 : printk(KERN_ERR PREFIX "Invalid _PSS data\n");
310 : 0 : result = -EFAULT;
311 : 0 : goto end;
312 : : }
313 : :
314 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n",
315 : 0 : pss->package.count));
316 : :
317 : 0 : pr->performance->state_count = pss->package.count;
318 : 0 : pr->performance->states =
319 : 0 : kmalloc_array(pss->package.count,
320 : : sizeof(struct acpi_processor_px),
321 : : GFP_KERNEL);
322 [ # # ]: 0 : if (!pr->performance->states) {
323 : 0 : result = -ENOMEM;
324 : 0 : goto end;
325 : : }
326 : :
327 [ # # ]: 0 : for (i = 0; i < pr->performance->state_count; i++) {
328 : :
329 : 0 : struct acpi_processor_px *px = &(pr->performance->states[i]);
330 : :
331 : 0 : state.length = sizeof(struct acpi_processor_px);
332 : 0 : state.pointer = px;
333 : :
334 : 0 : ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
335 : :
336 : 0 : status = acpi_extract_package(&(pss->package.elements[i]),
337 : : &format, &state);
338 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
339 : 0 : ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data"));
340 : 0 : result = -EFAULT;
341 : 0 : kfree(pr->performance->states);
342 : 0 : goto end;
343 : : }
344 : :
345 : 0 : amd_fixup_frequency(px, i);
346 : :
347 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
348 : : "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n",
349 : : i,
350 : : (u32) px->core_frequency,
351 : : (u32) px->power,
352 : : (u32) px->transition_latency,
353 : : (u32) px->bus_master_latency,
354 : 0 : (u32) px->control, (u32) px->status));
355 : :
356 : : /*
357 : : * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
358 : : */
359 [ # # ]: 0 : if (!px->core_frequency ||
360 : 0 : ((u32)(px->core_frequency * 1000) !=
361 [ # # ]: 0 : (px->core_frequency * 1000))) {
362 : 0 : printk(KERN_ERR FW_BUG PREFIX
363 : : "Invalid BIOS _PSS frequency found for processor %d: 0x%llx MHz\n",
364 : : pr->id, px->core_frequency);
365 [ # # ]: 0 : if (last_invalid == -1)
366 : 0 : last_invalid = i;
367 : : } else {
368 [ # # ]: 0 : if (last_invalid != -1) {
369 : : /*
370 : : * Copy this valid entry over last_invalid entry
371 : : */
372 : 0 : memcpy(&(pr->performance->states[last_invalid]),
373 : : px, sizeof(struct acpi_processor_px));
374 : 0 : ++last_invalid;
375 : : }
376 : : }
377 : : }
378 : :
379 [ # # ]: 0 : if (last_invalid == 0) {
380 : 0 : printk(KERN_ERR FW_BUG PREFIX
381 : : "No valid BIOS _PSS frequency found for processor %d\n", pr->id);
382 : 0 : result = -EFAULT;
383 : 0 : kfree(pr->performance->states);
384 : 0 : pr->performance->states = NULL;
385 : : }
386 : :
387 [ # # ]: 0 : if (last_invalid > 0)
388 : 0 : pr->performance->state_count = last_invalid;
389 : :
390 : 0 : end:
391 : 0 : kfree(buffer.pointer);
392 : :
393 : 0 : return result;
394 : : }
395 : :
396 : 28 : int acpi_processor_get_performance_info(struct acpi_processor *pr)
397 : : {
398 : 28 : int result = 0;
399 : :
400 [ + - + - : 28 : if (!pr || !pr->performance || !pr->handle)
+ - ]
401 : : return -EINVAL;
402 : :
403 [ - + ]: 28 : if (!acpi_has_method(pr->handle, "_PCT")) {
404 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
405 : : "ACPI-based processor performance control unavailable\n"));
406 : : return -ENODEV;
407 : : }
408 : :
409 : 0 : result = acpi_processor_get_performance_control(pr);
410 [ # # ]: 0 : if (result)
411 : 0 : goto update_bios;
412 : :
413 : 0 : result = acpi_processor_get_performance_states(pr);
414 [ # # ]: 0 : if (result)
415 : 0 : goto update_bios;
416 : :
417 : : /* We need to call _PPC once when cpufreq starts */
418 [ # # ]: 0 : if (ignore_ppc != 1)
419 : 0 : result = acpi_processor_get_platform_limit(pr);
420 : :
421 : : return result;
422 : :
423 : : /*
424 : : * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
425 : : * the BIOS is older than the CPU and does not know its frequencies
426 : : */
427 : 0 : update_bios:
428 : : #ifdef CONFIG_X86
429 [ # # ]: 0 : if (acpi_has_method(pr->handle, "_PPC")) {
430 [ # # ]: 0 : if(boot_cpu_has(X86_FEATURE_EST))
431 : 0 : printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
432 : : "frequency support\n");
433 : : }
434 : : #endif
435 : : return result;
436 : : }
437 : : EXPORT_SYMBOL_GPL(acpi_processor_get_performance_info);
438 : :
439 : 0 : int acpi_processor_pstate_control(void)
440 : : {
441 : 0 : acpi_status status;
442 : :
443 [ # # # # ]: 0 : if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control)
444 : : return 0;
445 : :
446 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
447 : : "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
448 : 0 : acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
449 : :
450 : 0 : status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
451 : : (u32)acpi_gbl_FADT.pstate_control, 8);
452 [ # # ]: 0 : if (ACPI_SUCCESS(status))
453 : : return 1;
454 : :
455 : 0 : ACPI_EXCEPTION((AE_INFO, status,
456 : : "Failed to write pstate_control [0x%x] to smi_command [0x%x]",
457 : : acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
458 : 0 : return -EIO;
459 : : }
460 : :
461 : 0 : int acpi_processor_notify_smm(struct module *calling_module)
462 : : {
463 : 0 : static int is_done = 0;
464 : 0 : int result;
465 : :
466 [ # # ]: 0 : if (!acpi_processor_cpufreq_init)
467 : : return -EBUSY;
468 : :
469 [ # # ]: 0 : if (!try_module_get(calling_module))
470 : : return -EINVAL;
471 : :
472 : : /* is_done is set to negative if an error occurred,
473 : : * and to postitive if _no_ error occurred, but SMM
474 : : * was already notified. This avoids double notification
475 : : * which might lead to unexpected results...
476 : : */
477 [ # # ]: 0 : if (is_done > 0) {
478 : 0 : module_put(calling_module);
479 : 0 : return 0;
480 [ # # ]: 0 : } else if (is_done < 0) {
481 : 0 : module_put(calling_module);
482 : 0 : return is_done;
483 : : }
484 : :
485 : 0 : is_done = -EIO;
486 : :
487 : 0 : result = acpi_processor_pstate_control();
488 [ # # ]: 0 : if (!result) {
489 : 0 : ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
490 : 0 : module_put(calling_module);
491 : 0 : return 0;
492 : : }
493 [ # # ]: 0 : if (result < 0) {
494 : 0 : module_put(calling_module);
495 : 0 : return result;
496 : : }
497 : :
498 : : /* Success. If there's no _PPC, we need to fear nothing, so
499 : : * we can allow the cpufreq driver to be rmmod'ed. */
500 : 0 : is_done = 1;
501 : :
502 [ # # ]: 0 : if (!acpi_processor_ppc_in_use)
503 : 0 : module_put(calling_module);
504 : :
505 : : return 0;
506 : : }
507 : :
508 : : EXPORT_SYMBOL(acpi_processor_notify_smm);
509 : :
510 : 28 : int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
511 : : {
512 : 28 : int result = 0;
513 : 28 : acpi_status status = AE_OK;
514 : 28 : struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
515 : 28 : struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
516 : 28 : struct acpi_buffer state = {0, NULL};
517 : 28 : union acpi_object *psd = NULL;
518 : :
519 : 28 : status = acpi_evaluate_object(handle, "_PSD", NULL, &buffer);
520 [ - + ]: 28 : if (ACPI_FAILURE(status)) {
521 : : return -ENODEV;
522 : : }
523 : :
524 : 0 : psd = buffer.pointer;
525 [ # # # # ]: 0 : if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
526 : 0 : printk(KERN_ERR PREFIX "Invalid _PSD data\n");
527 : 0 : result = -EFAULT;
528 : 0 : goto end;
529 : : }
530 : :
531 [ # # ]: 0 : if (psd->package.count != 1) {
532 : 0 : printk(KERN_ERR PREFIX "Invalid _PSD data\n");
533 : 0 : result = -EFAULT;
534 : 0 : goto end;
535 : : }
536 : :
537 : 0 : state.length = sizeof(struct acpi_psd_package);
538 : 0 : state.pointer = pdomain;
539 : :
540 : 0 : status = acpi_extract_package(&(psd->package.elements[0]),
541 : : &format, &state);
542 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
543 : 0 : printk(KERN_ERR PREFIX "Invalid _PSD data\n");
544 : 0 : result = -EFAULT;
545 : 0 : goto end;
546 : : }
547 : :
548 [ # # ]: 0 : if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
549 : 0 : printk(KERN_ERR PREFIX "Unknown _PSD:num_entries\n");
550 : 0 : result = -EFAULT;
551 : 0 : goto end;
552 : : }
553 : :
554 [ # # ]: 0 : if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
555 : 0 : printk(KERN_ERR PREFIX "Unknown _PSD:revision\n");
556 : 0 : result = -EFAULT;
557 : 0 : goto end;
558 : : }
559 : :
560 : 0 : if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
561 [ # # ]: 0 : pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
562 : : pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
563 : 0 : printk(KERN_ERR PREFIX "Invalid _PSD:coord_type\n");
564 : 0 : result = -EFAULT;
565 : 0 : goto end;
566 : : }
567 : 0 : end:
568 : 0 : kfree(buffer.pointer);
569 : 0 : return result;
570 : : }
571 : : EXPORT_SYMBOL(acpi_processor_get_psd);
572 : :
573 : 28 : int acpi_processor_preregister_performance(
574 : : struct acpi_processor_performance __percpu *performance)
575 : : {
576 : 28 : int count_target;
577 : 28 : int retval = 0;
578 : 28 : unsigned int i, j;
579 : 28 : cpumask_var_t covered_cpus;
580 : 28 : struct acpi_processor *pr;
581 : 28 : struct acpi_psd_package *pdomain;
582 : 28 : struct acpi_processor *match_pr;
583 : 28 : struct acpi_psd_package *match_pdomain;
584 : :
585 : 28 : if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
586 : : return -ENOMEM;
587 : :
588 : 28 : mutex_lock(&performance_mutex);
589 : :
590 : : /*
591 : : * Check if another driver has already registered, and abort before
592 : : * changing pr->performance if it has. Check input data as well.
593 : : */
594 [ + + ]: 84 : for_each_possible_cpu(i) {
595 : 28 : pr = per_cpu(processors, i);
596 [ - + ]: 28 : if (!pr) {
597 : : /* Look only at processors in ACPI namespace */
598 : 0 : continue;
599 : : }
600 : :
601 [ - + ]: 28 : if (pr->performance) {
602 : 0 : retval = -EBUSY;
603 : 0 : goto err_out;
604 : : }
605 : :
606 [ + - - + ]: 28 : if (!performance || !per_cpu_ptr(performance, i)) {
607 : 0 : retval = -EINVAL;
608 : 0 : goto err_out;
609 : : }
610 : : }
611 : :
612 : : /* Call _PSD for all CPUs */
613 [ + + ]: 56 : for_each_possible_cpu(i) {
614 : 28 : pr = per_cpu(processors, i);
615 [ - + ]: 28 : if (!pr)
616 : 0 : continue;
617 : :
618 : 28 : pr->performance = per_cpu_ptr(performance, i);
619 : 28 : cpumask_set_cpu(i, pr->performance->shared_cpu_map);
620 : 28 : pdomain = &(pr->performance->domain_info);
621 [ + - ]: 28 : if (acpi_processor_get_psd(pr->handle, pdomain)) {
622 : 28 : retval = -EINVAL;
623 : 28 : continue;
624 : : }
625 : : }
626 [ - + ]: 28 : if (retval)
627 : 28 : goto err_ret;
628 : :
629 : : /*
630 : : * Now that we have _PSD data from all CPUs, lets setup P-state
631 : : * domain info.
632 : : */
633 [ # # ]: 0 : for_each_possible_cpu(i) {
634 : 0 : pr = per_cpu(processors, i);
635 [ # # ]: 0 : if (!pr)
636 : 0 : continue;
637 : :
638 [ # # ]: 0 : if (cpumask_test_cpu(i, covered_cpus))
639 : 0 : continue;
640 : :
641 : 0 : pdomain = &(pr->performance->domain_info);
642 : 0 : cpumask_set_cpu(i, pr->performance->shared_cpu_map);
643 : 0 : cpumask_set_cpu(i, covered_cpus);
644 [ # # ]: 0 : if (pdomain->num_processors <= 1)
645 : 0 : continue;
646 : :
647 : : /* Validate the Domain info */
648 : 0 : count_target = pdomain->num_processors;
649 [ # # ]: 0 : if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
650 : 0 : pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
651 [ # # ]: 0 : else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
652 : 0 : pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW;
653 [ # # ]: 0 : else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
654 : 0 : pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
655 : :
656 [ # # ]: 0 : for_each_possible_cpu(j) {
657 [ # # ]: 0 : if (i == j)
658 : 0 : continue;
659 : :
660 : 0 : match_pr = per_cpu(processors, j);
661 [ # # ]: 0 : if (!match_pr)
662 : 0 : continue;
663 : :
664 : 0 : match_pdomain = &(match_pr->performance->domain_info);
665 [ # # ]: 0 : if (match_pdomain->domain != pdomain->domain)
666 : 0 : continue;
667 : :
668 : : /* Here i and j are in the same domain */
669 : :
670 [ # # ]: 0 : if (match_pdomain->num_processors != count_target) {
671 : 0 : retval = -EINVAL;
672 : 0 : goto err_ret;
673 : : }
674 : :
675 [ # # ]: 0 : if (pdomain->coord_type != match_pdomain->coord_type) {
676 : 0 : retval = -EINVAL;
677 : 0 : goto err_ret;
678 : : }
679 : :
680 : 0 : cpumask_set_cpu(j, covered_cpus);
681 : 0 : cpumask_set_cpu(j, pr->performance->shared_cpu_map);
682 : : }
683 : :
684 [ # # ]: 0 : for_each_possible_cpu(j) {
685 [ # # ]: 0 : if (i == j)
686 : 0 : continue;
687 : :
688 : 0 : match_pr = per_cpu(processors, j);
689 [ # # ]: 0 : if (!match_pr)
690 : 0 : continue;
691 : :
692 : 0 : match_pdomain = &(match_pr->performance->domain_info);
693 [ # # ]: 0 : if (match_pdomain->domain != pdomain->domain)
694 : 0 : continue;
695 : :
696 : 0 : match_pr->performance->shared_type =
697 : 0 : pr->performance->shared_type;
698 : 0 : cpumask_copy(match_pr->performance->shared_cpu_map,
699 : 0 : pr->performance->shared_cpu_map);
700 : : }
701 : : }
702 : :
703 : 0 : err_ret:
704 [ + + ]: 56 : for_each_possible_cpu(i) {
705 : 28 : pr = per_cpu(processors, i);
706 [ + - - + ]: 28 : if (!pr || !pr->performance)
707 : 0 : continue;
708 : :
709 : : /* Assume no coordination on any error parsing domain info */
710 [ + - ]: 28 : if (retval) {
711 : 28 : cpumask_clear(pr->performance->shared_cpu_map);
712 : 28 : cpumask_set_cpu(i, pr->performance->shared_cpu_map);
713 : 28 : pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
714 : : }
715 : 28 : pr->performance = NULL; /* Will be set for real in register */
716 : : }
717 : :
718 : 28 : err_out:
719 : 28 : mutex_unlock(&performance_mutex);
720 : 28 : free_cpumask_var(covered_cpus);
721 : 28 : return retval;
722 : : }
723 : : EXPORT_SYMBOL(acpi_processor_preregister_performance);
724 : :
725 : : int
726 : 28 : acpi_processor_register_performance(struct acpi_processor_performance
727 : : *performance, unsigned int cpu)
728 : : {
729 : 28 : struct acpi_processor *pr;
730 : :
731 [ + - ]: 28 : if (!acpi_processor_cpufreq_init)
732 : : return -EINVAL;
733 : :
734 : 28 : mutex_lock(&performance_mutex);
735 : :
736 : 28 : pr = per_cpu(processors, cpu);
737 [ - + ]: 28 : if (!pr) {
738 : 0 : mutex_unlock(&performance_mutex);
739 : 0 : return -ENODEV;
740 : : }
741 : :
742 [ - + ]: 28 : if (pr->performance) {
743 : 0 : mutex_unlock(&performance_mutex);
744 : 0 : return -EBUSY;
745 : : }
746 : :
747 [ - + ]: 28 : WARN_ON(!performance);
748 : :
749 : 28 : pr->performance = performance;
750 : :
751 [ + - ]: 28 : if (acpi_processor_get_performance_info(pr)) {
752 : 28 : pr->performance = NULL;
753 : 28 : mutex_unlock(&performance_mutex);
754 : 28 : return -EIO;
755 : : }
756 : :
757 : 0 : mutex_unlock(&performance_mutex);
758 : 0 : return 0;
759 : : }
760 : :
761 : : EXPORT_SYMBOL(acpi_processor_register_performance);
762 : :
763 : 0 : void acpi_processor_unregister_performance(unsigned int cpu)
764 : : {
765 : 0 : struct acpi_processor *pr;
766 : :
767 : 0 : mutex_lock(&performance_mutex);
768 : :
769 : 0 : pr = per_cpu(processors, cpu);
770 [ # # ]: 0 : if (!pr) {
771 : 0 : mutex_unlock(&performance_mutex);
772 : 0 : return;
773 : : }
774 : :
775 [ # # ]: 0 : if (pr->performance)
776 : 0 : kfree(pr->performance->states);
777 : 0 : pr->performance = NULL;
778 : :
779 : 0 : mutex_unlock(&performance_mutex);
780 : :
781 : 0 : return;
782 : : }
783 : :
784 : : EXPORT_SYMBOL(acpi_processor_unregister_performance);
|