processor_perflib.c revision 613e5f3376e48bd48494cf780b79b97b057d49a7
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); 798