Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/init.h>
32#include <linux/cpufreq.h>
33
34#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
35#include <linux/proc_fs.h>
36#include <linux/seq_file.h>
37#include <linux/mutex.h>
38
39#include <asm/uaccess.h>
40#endif
41
42#include <acpi/acpi_bus.h>
43#include <acpi/processor.h>
44
45#define ACPI_PROCESSOR_COMPONENT 0x01000000
46#define ACPI_PROCESSOR_CLASS "processor"
47#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
48#define _COMPONENT ACPI_PROCESSOR_COMPONENT
49ACPI_MODULE_NAME("processor_perflib");
50
51static DEFINE_MUTEX(performance_mutex);
52
53/* Use cpufreq debug layer for _PPC changes. */
54#define cpufreq_printk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
55 "cpufreq-core", msg)
56
57/*
58 * _PPC support is implemented as a CPUfreq policy notifier:
59 * This means each time a CPUfreq driver registered also with
60 * the ACPI core is asked to change the speed policy, the maximum
61 * value is adjusted so that it is within the platform limit.
62 *
63 * Also, when a new platform limit value is detected, the CPUfreq
64 * policy is adjusted accordingly.
65 */
66
67/* ignore_ppc:
68 * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet
69 * ignore _PPC
70 * 0 -> cpufreq low level drivers initialized -> consider _PPC values
71 * 1 -> ignore _PPC totally -> forced by user through boot param
72 */
73static int ignore_ppc = -1;
74module_param(ignore_ppc, int, 0644);
75MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
76 "limited by BIOS, this should help");
77
78#define PPC_REGISTERED 1
79#define PPC_IN_USE 2
80
81static int acpi_processor_ppc_status;
82
83static int acpi_processor_ppc_notifier(struct notifier_block *nb,
84 unsigned long event, void *data)
85{
86 struct cpufreq_policy *policy = data;
87 struct acpi_processor *pr;
88 unsigned int ppc = 0;
89
90 if (event == CPUFREQ_START && ignore_ppc <= 0) {
91 ignore_ppc = 0;
92 return 0;
93 }
94
95 if (ignore_ppc)
96 return 0;
97
98 if (event != CPUFREQ_INCOMPATIBLE)
99 return 0;
100
101 mutex_lock(&performance_mutex);
102
103 pr = per_cpu(processors, policy->cpu);
104 if (!pr || !pr->performance)
105 goto out;
106
107 ppc = (unsigned int)pr->performance_platform_limit;
108
109 if (ppc >= pr->performance->state_count)
110 goto out;
111
112 cpufreq_verify_within_limits(policy, 0,
113 pr->performance->states[ppc].
114 core_frequency * 1000);
115
116 out:
117 mutex_unlock(&performance_mutex);
118
119 return 0;
120}
121
122static struct notifier_block acpi_ppc_notifier_block = {
123 .notifier_call = acpi_processor_ppc_notifier,
124};
125
126static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
127{
128 acpi_status status = 0;
129 unsigned long ppc = 0;
130
131
132 if (!pr)
133 return -EINVAL;
134
135 /*
136 * _PPC indicates the maximum state currently supported by the platform
137 * (e.g. 0 = states 0..n; 1 = states 1..n; etc.
138 */
139 status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
140
141 if (status != AE_NOT_FOUND)
142 acpi_processor_ppc_status |= PPC_IN_USE;
143
144 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
145 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
146 return -ENODEV;
147 }
148
149 cpufreq_printk("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
150 (int)ppc, ppc ? "" : "not");
151
152 pr->performance_platform_limit = (int)ppc;
153
154 return 0;
155}
156
157int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
158{
159 int ret;
160
161 if (ignore_ppc)
162 return 0;
163
164 ret = acpi_processor_get_platform_limit(pr);
165
166 if (ret < 0)
167 return (ret);
168 else
169 return cpufreq_update_policy(pr->id);
170}
171
172void acpi_processor_ppc_init(void)
173{
174 if (!cpufreq_register_notifier
175 (&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER))
176 acpi_processor_ppc_status |= PPC_REGISTERED;
177 else
178 printk(KERN_DEBUG
179 "Warning: Processor Platform Limit not supported.\n");
180}
181
182void acpi_processor_ppc_exit(void)
183{
184 if (acpi_processor_ppc_status & PPC_REGISTERED)
185 cpufreq_unregister_notifier(&acpi_ppc_notifier_block,
186 CPUFREQ_POLICY_NOTIFIER);
187
188 acpi_processor_ppc_status &= ~PPC_REGISTERED;
189}
190
191static int acpi_processor_get_performance_control(struct acpi_processor *pr)
192{
193 int result = 0;
194 acpi_status status = 0;
195 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
196 union acpi_object *pct = NULL;
197 union acpi_object obj = { 0 };
198
199
200 status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
201 if (ACPI_FAILURE(status)) {
202 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT"));
203 return -ENODEV;
204 }
205
206 pct = (union acpi_object *)buffer.pointer;
207 if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
208 || (pct->package.count != 2)) {
209 printk(KERN_ERR PREFIX "Invalid _PCT data\n");
210 result = -EFAULT;
211 goto end;
212 }
213
214 /*
215 * control_register
216 */
217
218 obj = pct->package.elements[0];
219
220 if ((obj.type != ACPI_TYPE_BUFFER)
221 || (obj.buffer.length < sizeof(struct acpi_pct_register))
222 || (obj.buffer.pointer == NULL)) {
223 printk(KERN_ERR PREFIX "Invalid _PCT data (control_register)\n");
224 result = -EFAULT;
225 goto end;
226 }
227 memcpy(&pr->performance->control_register, obj.buffer.pointer,
228 sizeof(struct acpi_pct_register));
229
230 /*
231 * status_register
232 */
233
234 obj = pct->package.elements[1];
235
236 if ((obj.type != ACPI_TYPE_BUFFER)
237 || (obj.buffer.length < sizeof(struct acpi_pct_register))
238 || (obj.buffer.pointer == NULL)) {
239 printk(KERN_ERR PREFIX "Invalid _PCT data (status_register)\n");
240 result = -EFAULT;
241 goto end;
242 }
243
244 memcpy(&pr->performance->status_register, obj.buffer.pointer,
245 sizeof(struct acpi_pct_register));
246
247 end:
248 kfree(buffer.pointer);
249
250 return result;
251}
252
253static int acpi_processor_get_performance_states(struct acpi_processor *pr)
254{
255 int result = 0;
256 acpi_status status = AE_OK;
257 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
258 struct acpi_buffer format = { sizeof("NNNNNN"), "NNNNNN" };
259 struct acpi_buffer state = { 0, NULL };
260 union acpi_object *pss = NULL;
261 int i;
262
263
264 status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
265 if (ACPI_FAILURE(status)) {
266 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS"));
267 return -ENODEV;
268 }
269
270 pss = buffer.pointer;
271 if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
272 printk(KERN_ERR PREFIX "Invalid _PSS data\n");
273 result = -EFAULT;
274 goto end;
275 }
276
277 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n",
278 pss->package.count));
279
280 pr->performance->state_count = pss->package.count;
281 pr->performance->states =
282 kmalloc(sizeof(struct acpi_processor_px) * pss->package.count,
283 GFP_KERNEL);
284 if (!pr->performance->states) {
285 result = -ENOMEM;
286 goto end;
287 }
288
289 for (i = 0; i < pr->performance->state_count; i++) {
290
291 struct acpi_processor_px *px = &(pr->performance->states[i]);
292
293 state.length = sizeof(struct acpi_processor_px);
294 state.pointer = px;
295
296 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
297
298 status = acpi_extract_package(&(pss->package.elements[i]),
299 &format, &state);
300 if (ACPI_FAILURE(status)) {
301 ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data"));
302 result = -EFAULT;
303 kfree(pr->performance->states);
304 goto end;
305 }
306
307 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
308 "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n",
309 i,
310 (u32) px->core_frequency,
311 (u32) px->power,
312 (u32) px->transition_latency,
313 (u32) px->bus_master_latency,
314 (u32) px->control, (u32) px->status));
315
316 if (!px->core_frequency) {
317 printk(KERN_ERR PREFIX
318 "Invalid _PSS data: freq is zero\n");
319 result = -EFAULT;
320 kfree(pr->performance->states);
321 goto end;
322 }
323 }
324
325 end:
326 kfree(buffer.pointer);
327
328 return result;
329}
330
331static int acpi_processor_get_performance_info(struct acpi_processor *pr)
332{
333 int result = 0;
334 acpi_status status = AE_OK;
335 acpi_handle handle = NULL;
336
337
338 if (!pr || !pr->performance || !pr->handle)
339 return -EINVAL;
340
341 status = acpi_get_handle(pr->handle, "_PCT", &handle);
342 if (ACPI_FAILURE(status)) {
343 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
344 "ACPI-based processor performance control unavailable\n"));
345 return -ENODEV;
346 }
347
348 result = acpi_processor_get_performance_control(pr);
349 if (result)
350 return result;
351
352 result = acpi_processor_get_performance_states(pr);
353 if (result)
354 return result;
355
356 return 0;
357}
358
359int acpi_processor_notify_smm(struct module *calling_module)
360{
361 acpi_status status;
362 static int is_done = 0;
363
364
365 if (!(acpi_processor_ppc_status & PPC_REGISTERED))
366 return -EBUSY;
367
368 if (!try_module_get(calling_module))
369 return -EINVAL;
370
371 /* is_done is set to negative if an error occured,
372 * and to postitive if _no_ error occured, but SMM
373 * was already notified. This avoids double notification
374 * which might lead to unexpected results...
375 */
376 if (is_done > 0) {
377 module_put(calling_module);
378 return 0;
379 } else if (is_done < 0) {
380 module_put(calling_module);
381 return is_done;
382 }
383
384 is_done = -EIO;
385
386 /* Can't write pstate_control to smi_command if either value is zero */
387 if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
388 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
389 module_put(calling_module);
390 return 0;
391 }
392
393 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
394 "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
395 acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
396
397 status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
398 (u32) acpi_gbl_FADT.pstate_control, 8);
399 if (ACPI_FAILURE(status)) {
400 ACPI_EXCEPTION((AE_INFO, status,
401 "Failed to write pstate_control [0x%x] to "
402 "smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
403 acpi_gbl_FADT.smi_command));
404 module_put(calling_module);
405 return status;
406 }
407
408 /* Success. If there's no _PPC, we need to fear nothing, so
409 * we can allow the cpufreq driver to be rmmod'ed. */
410 is_done = 1;
411
412 if (!(acpi_processor_ppc_status & PPC_IN_USE))
413 module_put(calling_module);
414
415 return 0;
416}
417
418EXPORT_SYMBOL(acpi_processor_notify_smm);
419
420#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
421/* /proc/acpi/processor/../performance interface (DEPRECATED) */
422
423static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
424static struct file_operations acpi_processor_perf_fops = {
425 .owner = THIS_MODULE,
426 .open = acpi_processor_perf_open_fs,
427 .read = seq_read,
428 .llseek = seq_lseek,
429 .release = single_release,
430};
431
432static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
433{
434 struct acpi_processor *pr = seq->private;
435 int i;
436
437
438 if (!pr)
439 goto end;
440
441 if (!pr->performance) {
442 seq_puts(seq, "<not supported>\n");
443 goto end;
444 }
445
446 seq_printf(seq, "state count: %d\n"
447 "active state: P%d\n",
448 pr->performance->state_count, pr->performance->state);
449
450 seq_puts(seq, "states:\n");
451 for (i = 0; i < pr->performance->state_count; i++)
452 seq_printf(seq,
453 " %cP%d: %d MHz, %d mW, %d uS\n",
454 (i == pr->performance->state ? '*' : ' '), i,
455 (u32) pr->performance->states[i].core_frequency,
456 (u32) pr->performance->states[i].power,
457 (u32) pr->performance->states[i].transition_latency);
458
459 end:
460 return 0;
461}
462
463static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
464{
465 return single_open(file, acpi_processor_perf_seq_show,
466 PDE(inode)->data);
467}
468
469static void acpi_cpufreq_add_file(struct acpi_processor *pr)
470{
471 struct acpi_device *device = NULL;
472
473
474 if (acpi_bus_get_device(pr->handle, &device))
475 return;
476
477 /* add file 'performance' [R/W] */
478 proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO,
479 acpi_device_dir(device),
480 &acpi_processor_perf_fops, acpi_driver_data(device));
481 return;
482}
483
484static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
485{
486 struct acpi_device *device = NULL;
487
488
489 if (acpi_bus_get_device(pr->handle, &device))
490 return;
491
492 /* remove file 'performance' */
493 remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
494 acpi_device_dir(device));
495
496 return;
497}
498
499#else
500static void acpi_cpufreq_add_file(struct acpi_processor *pr)
501{
502 return;
503}
504static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
505{
506 return;
507}
508#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
509
510static int acpi_processor_get_psd(struct acpi_processor *pr)
511{
512 int result = 0;
513 acpi_status status = AE_OK;
514 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
515 struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
516 struct acpi_buffer state = {0, NULL};
517 union acpi_object *psd = NULL;
518 struct acpi_psd_package *pdomain;
519
520 status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer);
521 if (ACPI_FAILURE(status)) {
522 return -ENODEV;
523 }
524
525 psd = buffer.pointer;
526 if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
527 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
528 result = -EFAULT;
529 goto end;
530 }
531
532 if (psd->package.count != 1) {
533 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
534 result = -EFAULT;
535 goto end;
536 }
537
538 pdomain = &(pr->performance->domain_info);
539
540 state.length = sizeof(struct acpi_psd_package);
541 state.pointer = pdomain;
542
543 status = acpi_extract_package(&(psd->package.elements[0]),
544 &format, &state);
545 if (ACPI_FAILURE(status)) {
546 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
547 result = -EFAULT;
548 goto end;
549 }
550
551 if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
552 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
553 result = -EFAULT;
554 goto end;
555 }
556
557 if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
558 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
559 result = -EFAULT;
560 goto end;
561 }
562
563end:
564 kfree(buffer.pointer);
565 return result;
566}
567
568int acpi_processor_preregister_performance(
569 struct acpi_processor_performance *performance)
570{
571 int count, count_target;
572 int retval = 0;
573 unsigned int i, j;
574 cpumask_t covered_cpus;
575 struct acpi_processor *pr;
576 struct acpi_psd_package *pdomain;
577 struct acpi_processor *match_pr;
578 struct acpi_psd_package *match_pdomain;
579
580 mutex_lock(&performance_mutex);
581
582 retval = 0;
583
584 /* Call _PSD for all CPUs */
585 for_each_possible_cpu(i) {
586 pr = per_cpu(processors, i);
587 if (!pr) {
588 /* Look only at processors in ACPI namespace */
589 continue;
590 }
591
592 if (pr->performance) {
593 retval = -EBUSY;
594 continue;
595 }
596
597 if (!performance || !percpu_ptr(performance, i)) {
598 retval = -EINVAL;
599 continue;
600 }
601
602 pr->performance = percpu_ptr(performance, i);
603 cpu_set(i, pr->performance->shared_cpu_map);
604 if (acpi_processor_get_psd(pr)) {
605 retval = -EINVAL;
606 continue;
607 }
608 }
609 if (retval)
610 goto err_ret;
611
612 /*
613 * Now that we have _PSD data from all CPUs, lets setup P-state
614 * domain info.
615 */
616 for_each_possible_cpu(i) {
617 pr = per_cpu(processors, i);
618 if (!pr)
619 continue;
620
621 /* Basic validity check for domain info */
622 pdomain = &(pr->performance->domain_info);
623 if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
624 (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) {
625 retval = -EINVAL;
626 goto err_ret;
627 }
628 if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
629 pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
630 pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
631 retval = -EINVAL;
632 goto err_ret;
633 }
634 }
635
636 cpus_clear(covered_cpus);
637 for_each_possible_cpu(i) {
638 pr = per_cpu(processors, i);
639 if (!pr)
640 continue;
641
642 if (cpu_isset(i, covered_cpus))
643 continue;
644
645 pdomain = &(pr->performance->domain_info);
646 cpu_set(i, pr->performance->shared_cpu_map);
647 cpu_set(i, covered_cpus);
648 if (pdomain->num_processors <= 1)
649 continue;
650
651 /* Validate the Domain info */
652 count_target = pdomain->num_processors;
653 count = 1;
654 if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
655 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
656 else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
657 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW;
658 else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
659 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
660
661 for_each_possible_cpu(j) {
662 if (i == j)
663 continue;
664
665 match_pr = per_cpu(processors, j);
666 if (!match_pr)
667 continue;
668
669 match_pdomain = &(match_pr->performance->domain_info);
670 if (match_pdomain->domain != pdomain->domain)
671 continue;
672
673 /* Here i and j are in the same domain */
674
675 if (match_pdomain->num_processors != count_target) {
676 retval = -EINVAL;
677 goto err_ret;
678 }
679
680 if (pdomain->coord_type != match_pdomain->coord_type) {
681 retval = -EINVAL;
682 goto err_ret;
683 }
684
685 cpu_set(j, covered_cpus);
686 cpu_set(j, pr->performance->shared_cpu_map);
687 count++;
688 }
689
690 for_each_possible_cpu(j) {
691 if (i == j)
692 continue;
693
694 match_pr = per_cpu(processors, j);
695 if (!match_pr)
696 continue;
697
698 match_pdomain = &(match_pr->performance->domain_info);
699 if (match_pdomain->domain != pdomain->domain)
700 continue;
701
702 match_pr->performance->shared_type =
703 pr->performance->shared_type;
704 match_pr->performance->shared_cpu_map =
705 pr->performance->shared_cpu_map;
706 }
707 }
708
709err_ret:
710 for_each_possible_cpu(i) {
711 pr = per_cpu(processors, i);
712 if (!pr || !pr->performance)
713 continue;
714
715 /* Assume no coordination on any error parsing domain info */
716 if (retval) {
717 cpus_clear(pr->performance->shared_cpu_map);
718 cpu_set(i, pr->performance->shared_cpu_map);
719 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
720 }
721 pr->performance = NULL; /* Will be set for real in register */
722 }
723
724 mutex_unlock(&performance_mutex);
725 return retval;
726}
727EXPORT_SYMBOL(acpi_processor_preregister_performance);
728
729
730int
731acpi_processor_register_performance(struct acpi_processor_performance
732 *performance, unsigned int cpu)
733{
734 struct acpi_processor *pr;
735
736
737 if (!(acpi_processor_ppc_status & PPC_REGISTERED))
738 return -EINVAL;
739
740 mutex_lock(&performance_mutex);
741
742 pr = per_cpu(processors, cpu);
743 if (!pr) {
744 mutex_unlock(&performance_mutex);
745 return -ENODEV;
746 }
747
748 if (pr->performance) {
749 mutex_unlock(&performance_mutex);
750 return -EBUSY;
751 }
752
753 WARN_ON(!performance);
754
755 pr->performance = performance;
756
757 if (acpi_processor_get_performance_info(pr)) {
758 pr->performance = NULL;
759 mutex_unlock(&performance_mutex);
760 return -EIO;
761 }
762
763 acpi_cpufreq_add_file(pr);
764
765 mutex_unlock(&performance_mutex);
766 return 0;
767}
768
769EXPORT_SYMBOL(acpi_processor_register_performance);
770
771void
772acpi_processor_unregister_performance(struct acpi_processor_performance
773 *performance, unsigned int cpu)
774{
775 struct acpi_processor *pr;
776
777
778 mutex_lock(&performance_mutex);
779
780 pr = per_cpu(processors, cpu);
781 if (!pr) {
782 mutex_unlock(&performance_mutex);
783 return;
784 }
785
786 if (pr->performance)
787 kfree(pr->performance->states);
788 pr->performance = NULL;
789
790 acpi_cpufreq_remove_file(pr);
791
792 mutex_unlock(&performance_mutex);
793
794 return;
795}
796
797EXPORT_SYMBOL(acpi_processor_unregister_performance);