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