Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

P-state software coordination for speedstep-centrino

http://bugzilla.kernel.org/show_bug.cgi?id=5737

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Venkatesh Pallipadi and committed by
Len Brown
c52851b6 09b4d1ee

+183 -69
+183 -69
arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
··· 351 351 352 352 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 353 353 354 - static struct acpi_processor_performance p; 354 + static struct acpi_processor_performance *acpi_perf_data[NR_CPUS]; 355 + 356 + /* 357 + * centrino_cpu_early_init_acpi - Do the preregistering with ACPI P-States 358 + * library 359 + * 360 + * Before doing the actual init, we need to do _PSD related setup whenever 361 + * supported by the BIOS. These are handled by this early_init routine. 362 + */ 363 + static int centrino_cpu_early_init_acpi(void) 364 + { 365 + unsigned int i, j; 366 + struct acpi_processor_performance *data; 367 + 368 + for_each_cpu(i) { 369 + data = kzalloc(sizeof(struct acpi_processor_performance), 370 + GFP_KERNEL); 371 + if (!data) { 372 + for_each_cpu(j) { 373 + kfree(acpi_perf_data[j]); 374 + acpi_perf_data[j] = NULL; 375 + } 376 + return (-ENOMEM); 377 + } 378 + acpi_perf_data[i] = data; 379 + } 380 + 381 + acpi_processor_preregister_performance(acpi_perf_data); 382 + return 0; 383 + } 355 384 356 385 /* 357 386 * centrino_cpu_init_acpi - register with ACPI P-States library ··· 394 365 unsigned long cur_freq; 395 366 int result = 0, i; 396 367 unsigned int cpu = policy->cpu; 368 + struct acpi_processor_performance *p; 369 + 370 + p = acpi_perf_data[cpu]; 397 371 398 372 /* register with ACPI core */ 399 - if (acpi_processor_register_performance(&p, cpu)) { 373 + if (acpi_processor_register_performance(p, cpu)) { 400 374 dprintk(KERN_INFO PFX "obtaining ACPI data failed\n"); 401 375 return -EIO; 402 376 } 377 + policy->cpus = p->shared_cpu_map; 378 + policy->shared_type = p->shared_type; 403 379 404 380 /* verify the acpi_data */ 405 - if (p.state_count <= 1) { 381 + if (p->state_count <= 1) { 406 382 dprintk("No P-States\n"); 407 383 result = -ENODEV; 408 384 goto err_unreg; 409 385 } 410 386 411 - if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || 412 - (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { 387 + if ((p->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || 388 + (p->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { 413 389 dprintk("Invalid control/status registers (%x - %x)\n", 414 - p.control_register.space_id, p.status_register.space_id); 390 + p->control_register.space_id, p->status_register.space_id); 415 391 result = -EIO; 416 392 goto err_unreg; 417 393 } 418 394 419 - for (i=0; i<p.state_count; i++) { 420 - if (p.states[i].control != p.states[i].status) { 395 + for (i=0; i<p->state_count; i++) { 396 + if (p->states[i].control != p->states[i].status) { 421 397 dprintk("Different control (%llu) and status values (%llu)\n", 422 - p.states[i].control, p.states[i].status); 398 + p->states[i].control, p->states[i].status); 423 399 result = -EINVAL; 424 400 goto err_unreg; 425 401 } 426 402 427 - if (!p.states[i].core_frequency) { 403 + if (!p->states[i].core_frequency) { 428 404 dprintk("Zero core frequency for state %u\n", i); 429 405 result = -EINVAL; 430 406 goto err_unreg; 431 407 } 432 408 433 - if (p.states[i].core_frequency > p.states[0].core_frequency) { 409 + if (p->states[i].core_frequency > p->states[0].core_frequency) { 434 410 dprintk("P%u has larger frequency (%llu) than P0 (%llu), skipping\n", i, 435 - p.states[i].core_frequency, p.states[0].core_frequency); 436 - p.states[i].core_frequency = 0; 411 + p->states[i].core_frequency, p->states[0].core_frequency); 412 + p->states[i].core_frequency = 0; 437 413 continue; 438 414 } 439 415 } ··· 450 416 } 451 417 452 418 centrino_model[cpu]->model_name=NULL; 453 - centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000; 419 + centrino_model[cpu]->max_freq = p->states[0].core_frequency * 1000; 454 420 centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * 455 - (p.state_count + 1), GFP_KERNEL); 421 + (p->state_count + 1), GFP_KERNEL); 456 422 if (!centrino_model[cpu]->op_points) { 457 423 result = -ENOMEM; 458 424 goto err_kfree; 459 425 } 460 426 461 - for (i=0; i<p.state_count; i++) { 462 - centrino_model[cpu]->op_points[i].index = p.states[i].control; 463 - centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000; 427 + for (i=0; i<p->state_count; i++) { 428 + centrino_model[cpu]->op_points[i].index = p->states[i].control; 429 + centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000; 464 430 dprintk("adding state %i with frequency %u and control value %04x\n", 465 431 i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index); 466 432 } 467 - centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; 433 + centrino_model[cpu]->op_points[p->state_count].frequency = CPUFREQ_TABLE_END; 468 434 469 435 cur_freq = get_cur_freq(cpu); 470 436 471 - for (i=0; i<p.state_count; i++) { 472 - if (!p.states[i].core_frequency) { 437 + for (i=0; i<p->state_count; i++) { 438 + if (!p->states[i].core_frequency) { 473 439 dprintk("skipping state %u\n", i); 474 440 centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; 475 441 continue; ··· 485 451 } 486 452 487 453 if (cur_freq == centrino_model[cpu]->op_points[i].frequency) 488 - p.state = i; 454 + p->state = i; 489 455 } 490 456 491 457 /* notify BIOS that we exist */ ··· 498 464 err_kfree: 499 465 kfree(centrino_model[cpu]); 500 466 err_unreg: 501 - acpi_processor_unregister_performance(&p, cpu); 467 + acpi_processor_unregister_performance(p, cpu); 502 468 dprintk(KERN_INFO PFX "invalid ACPI data\n"); 503 469 return (result); 504 470 } 505 471 #else 506 472 static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; } 473 + static inline int centrino_cpu_early_init_acpi(void) { return 0; } 507 474 #endif 508 475 509 476 static int centrino_cpu_init(struct cpufreq_policy *policy) ··· 592 557 593 558 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 594 559 if (!centrino_model[cpu]->model_name) { 595 - dprintk("unregistering and freeing ACPI data\n"); 596 - acpi_processor_unregister_performance(&p, cpu); 597 - kfree(centrino_model[cpu]->op_points); 598 - kfree(centrino_model[cpu]); 560 + static struct acpi_processor_performance *p; 561 + 562 + if (acpi_perf_data[cpu]) { 563 + p = acpi_perf_data[cpu]; 564 + dprintk("unregistering and freeing ACPI data\n"); 565 + acpi_processor_unregister_performance(p, cpu); 566 + kfree(centrino_model[cpu]->op_points); 567 + kfree(centrino_model[cpu]); 568 + } 599 569 } 600 570 #endif 601 571 ··· 634 594 unsigned int relation) 635 595 { 636 596 unsigned int newstate = 0; 637 - unsigned int msr, oldmsr, h, cpu = policy->cpu; 597 + unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; 638 598 struct cpufreq_freqs freqs; 599 + cpumask_t online_policy_cpus; 639 600 cpumask_t saved_mask; 640 - int retval; 601 + cpumask_t set_mask; 602 + cpumask_t covered_cpus; 603 + int retval = 0; 604 + unsigned int j, k, first_cpu, tmp; 641 605 642 - if (centrino_model[cpu] == NULL) 606 + if (unlikely(centrino_model[cpu] == NULL)) 643 607 return -ENODEV; 644 608 645 - /* 646 - * Support for SMP systems. 647 - * Make sure we are running on the CPU that wants to change frequency 648 - */ 609 + if (unlikely(cpufreq_frequency_table_target(policy, 610 + centrino_model[cpu]->op_points, 611 + target_freq, 612 + relation, 613 + &newstate))) { 614 + return -EINVAL; 615 + } 616 + 617 + /* cpufreq holds the hotplug lock, so we are safe from here on */ 618 + cpus_and(online_policy_cpus, cpu_online_map, policy->cpus); 619 + 649 620 saved_mask = current->cpus_allowed; 650 - set_cpus_allowed(current, policy->cpus); 651 - if (!cpu_isset(smp_processor_id(), policy->cpus)) { 652 - dprintk("couldn't limit to CPUs in this domain\n"); 653 - return(-EAGAIN); 621 + first_cpu = 1; 622 + cpus_clear(covered_cpus); 623 + for_each_cpu_mask(j, online_policy_cpus) { 624 + /* 625 + * Support for SMP systems. 626 + * Make sure we are running on CPU that wants to change freq 627 + */ 628 + cpus_clear(set_mask); 629 + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 630 + cpus_or(set_mask, set_mask, online_policy_cpus); 631 + else 632 + cpu_set(j, set_mask); 633 + 634 + set_cpus_allowed(current, set_mask); 635 + if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) { 636 + dprintk("couldn't limit to CPUs in this domain\n"); 637 + retval = -EAGAIN; 638 + if (first_cpu) { 639 + /* We haven't started the transition yet. */ 640 + goto migrate_end; 641 + } 642 + break; 643 + } 644 + 645 + msr = centrino_model[cpu]->op_points[newstate].index; 646 + 647 + if (first_cpu) { 648 + rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); 649 + if (msr == (oldmsr & 0xffff)) { 650 + dprintk("no change needed - msr was and needs " 651 + "to be %x\n", oldmsr); 652 + retval = 0; 653 + goto migrate_end; 654 + } 655 + 656 + freqs.old = extract_clock(oldmsr, cpu, 0); 657 + freqs.new = extract_clock(msr, cpu, 0); 658 + 659 + dprintk("target=%dkHz old=%d new=%d msr=%04x\n", 660 + target_freq, freqs.old, freqs.new, msr); 661 + 662 + for_each_cpu_mask(k, online_policy_cpus) { 663 + freqs.cpu = k; 664 + cpufreq_notify_transition(&freqs, 665 + CPUFREQ_PRECHANGE); 666 + } 667 + 668 + first_cpu = 0; 669 + /* all but 16 LSB are reserved, treat them with care */ 670 + oldmsr &= ~0xffff; 671 + msr &= 0xffff; 672 + oldmsr |= msr; 673 + } 674 + 675 + wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); 676 + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 677 + break; 678 + 679 + cpu_set(j, covered_cpus); 654 680 } 655 681 656 - if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq, 657 - relation, &newstate)) { 658 - retval = -EINVAL; 659 - goto migrate_end; 682 + for_each_cpu_mask(k, online_policy_cpus) { 683 + freqs.cpu = k; 684 + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 660 685 } 661 686 662 - msr = centrino_model[cpu]->op_points[newstate].index; 663 - rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); 687 + if (unlikely(retval)) { 688 + /* 689 + * We have failed halfway through the frequency change. 690 + * We have sent callbacks to policy->cpus and 691 + * MSRs have already been written on coverd_cpus. 692 + * Best effort undo.. 693 + */ 664 694 665 - if (msr == (oldmsr & 0xffff)) { 666 - retval = 0; 667 - dprintk("no change needed - msr was and needs to be %x\n", oldmsr); 668 - goto migrate_end; 695 + if (!cpus_empty(covered_cpus)) { 696 + for_each_cpu_mask(j, covered_cpus) { 697 + set_cpus_allowed(current, cpumask_of_cpu(j)); 698 + wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); 699 + } 700 + } 701 + 702 + tmp = freqs.new; 703 + freqs.new = freqs.old; 704 + freqs.old = tmp; 705 + for_each_cpu_mask(j, online_policy_cpus) { 706 + freqs.cpu = j; 707 + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 708 + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 709 + } 669 710 } 670 711 671 - freqs.cpu = cpu; 672 - freqs.old = extract_clock(oldmsr, cpu, 0); 673 - freqs.new = extract_clock(msr, cpu, 0); 674 - 675 - dprintk("target=%dkHz old=%d new=%d msr=%04x\n", 676 - target_freq, freqs.old, freqs.new, msr); 677 - 678 - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 679 - 680 - /* all but 16 LSB are "reserved", so treat them with 681 - care */ 682 - oldmsr &= ~0xffff; 683 - msr &= 0xffff; 684 - oldmsr |= msr; 685 - 686 - wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); 687 - 688 - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 689 - 690 - retval = 0; 691 712 migrate_end: 692 713 set_cpus_allowed(current, saved_mask); 693 - return (retval); 714 + return 0; 694 715 } 695 716 696 717 static struct freq_attr* centrino_attr[] = { ··· 793 692 if (!cpu_has(cpu, X86_FEATURE_EST)) 794 693 return -ENODEV; 795 694 695 + centrino_cpu_early_init_acpi(); 696 + 796 697 return cpufreq_register_driver(&centrino_driver); 797 698 } 798 699 799 700 static void __exit centrino_exit(void) 800 701 { 702 + #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 703 + unsigned int j; 704 + #endif 705 + 801 706 cpufreq_unregister_driver(&centrino_driver); 707 + 708 + #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 709 + for_each_cpu(j) { 710 + kfree(acpi_perf_data[j]); 711 + acpi_perf_data[j] = NULL; 712 + } 713 + #endif 802 714 } 803 715 804 716 MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");