aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:52:36 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:52:36 -0400
commit37224470c8c6d90a4062e76a08d4dc1fcf91fc89 (patch)
tree627f537177bf8e951c12bec04c4a85f0125f5ece /arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
parente83319510b04dd51a60da8a0b4ccf8b92b3ab1ad (diff)
parentae6c859b7dcd708efadf1c76279c33db213e3506 (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (65 commits) ACPI: suppress power button event on S3 resume ACPI: resolve merge conflict between sem2mutex and processor_perflib.c ACPI: use for_each_possible_cpu() instead of for_each_cpu() ACPI: delete newly added debugging macros in processor_perflib.c ACPI: UP build fix for bugzilla-5737 Enable P-state software coordination via _PDC P-state software coordination for speedstep-centrino P-state software coordination for acpi-cpufreq P-state software coordination for ACPI core ACPI: create acpi_thermal_resume() ACPI: create acpi_fan_suspend()/acpi_fan_resume() ACPI: pass pm_message_t from acpi_device_suspend() to root_suspend() ACPI: create acpi_device_suspend()/acpi_device_resume() ACPI: replace spin_lock_irq with mutex for ec poll mode ACPI: Allow a WAN module enable/disable on a Thinkpad X60. sem2mutex: acpi, acpi_link_lock ACPI: delete unused acpi_bus_drivers_lock sem2mutex: drivers/acpi/processor_perflib.c ACPI add ia64 exports to build acpi_memhotplug as a module ACPI: asus_acpi_init(): propagate correct return value ... Manual resolve of conflicts in: arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c include/acpi/processor.h
Diffstat (limited to 'arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c254
1 files changed, 186 insertions, 68 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index f1a82c5de1ba..31c3a5baaa7f 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -347,7 +347,36 @@ static unsigned int get_cur_freq(unsigned int cpu)
347 347
348#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 348#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
349 349
350static struct acpi_processor_performance p; 350static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
351
352/*
353 * centrino_cpu_early_init_acpi - Do the preregistering with ACPI P-States
354 * library
355 *
356 * Before doing the actual init, we need to do _PSD related setup whenever
357 * supported by the BIOS. These are handled by this early_init routine.
358 */
359static int centrino_cpu_early_init_acpi(void)
360{
361 unsigned int i, j;
362 struct acpi_processor_performance *data;
363
364 for_each_cpu(i) {
365 data = kzalloc(sizeof(struct acpi_processor_performance),
366 GFP_KERNEL);
367 if (!data) {
368 for_each_cpu(j) {
369 kfree(acpi_perf_data[j]);
370 acpi_perf_data[j] = NULL;
371 }
372 return (-ENOMEM);
373 }
374 acpi_perf_data[i] = data;
375 }
376
377 acpi_processor_preregister_performance(acpi_perf_data);
378 return 0;
379}
351 380
352/* 381/*
353 * centrino_cpu_init_acpi - register with ACPI P-States library 382 * centrino_cpu_init_acpi - register with ACPI P-States library
@@ -361,46 +390,51 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
361 unsigned long cur_freq; 390 unsigned long cur_freq;
362 int result = 0, i; 391 int result = 0, i;
363 unsigned int cpu = policy->cpu; 392 unsigned int cpu = policy->cpu;
393 struct acpi_processor_performance *p;
394
395 p = acpi_perf_data[cpu];
364 396
365 /* register with ACPI core */ 397 /* register with ACPI core */
366 if (acpi_processor_register_performance(&p, cpu)) { 398 if (acpi_processor_register_performance(p, cpu)) {
367 dprintk("obtaining ACPI data failed\n"); 399 dprintk(PFX "obtaining ACPI data failed\n");
368 return -EIO; 400 return -EIO;
369 } 401 }
402 policy->cpus = p->shared_cpu_map;
403 policy->shared_type = p->shared_type;
370 404
371 /* verify the acpi_data */ 405 /* verify the acpi_data */
372 if (p.state_count <= 1) { 406 if (p->state_count <= 1) {
373 dprintk("No P-States\n"); 407 dprintk("No P-States\n");
374 result = -ENODEV; 408 result = -ENODEV;
375 goto err_unreg; 409 goto err_unreg;
376 } 410 }
377 411
378 if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || 412 if ((p->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
379 (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { 413 (p->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
380 dprintk("Invalid control/status registers (%x - %x)\n", 414 dprintk("Invalid control/status registers (%x - %x)\n",
381 p.control_register.space_id, p.status_register.space_id); 415 p->control_register.space_id, p->status_register.space_id);
382 result = -EIO; 416 result = -EIO;
383 goto err_unreg; 417 goto err_unreg;
384 } 418 }
385 419
386 for (i=0; i<p.state_count; i++) { 420 for (i=0; i<p->state_count; i++) {
387 if (p.states[i].control != p.states[i].status) { 421 if (p->states[i].control != p->states[i].status) {
388 dprintk("Different control (%llu) and status values (%llu)\n", 422 dprintk("Different control (%llu) and status values (%llu)\n",
389 p.states[i].control, p.states[i].status); 423 p->states[i].control, p->states[i].status);
390 result = -EINVAL; 424 result = -EINVAL;
391 goto err_unreg; 425 goto err_unreg;
392 } 426 }
393 427
394 if (!p.states[i].core_frequency) { 428 if (!p->states[i].core_frequency) {
395 dprintk("Zero core frequency for state %u\n", i); 429 dprintk("Zero core frequency for state %u\n", i);
396 result = -EINVAL; 430 result = -EINVAL;
397 goto err_unreg; 431 goto err_unreg;
398 } 432 }
399 433
400 if (p.states[i].core_frequency > p.states[0].core_frequency) { 434 if (p->states[i].core_frequency > p->states[0].core_frequency) {
401 dprintk("P%u has larger frequency (%llu) than P0 (%llu), skipping\n", i, 435 dprintk("P%u has larger frequency (%llu) than P0 (%llu), skipping\n", i,
402 p.states[i].core_frequency, p.states[0].core_frequency); 436 p->states[i].core_frequency, p->states[0].core_frequency);
403 p.states[i].core_frequency = 0; 437 p->states[i].core_frequency = 0;
404 continue; 438 continue;
405 } 439 }
406 } 440 }
@@ -412,26 +446,26 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
412 } 446 }
413 447
414 centrino_model[cpu]->model_name=NULL; 448 centrino_model[cpu]->model_name=NULL;
415 centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000; 449 centrino_model[cpu]->max_freq = p->states[0].core_frequency * 1000;
416 centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * 450 centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
417 (p.state_count + 1), GFP_KERNEL); 451 (p->state_count + 1), GFP_KERNEL);
418 if (!centrino_model[cpu]->op_points) { 452 if (!centrino_model[cpu]->op_points) {
419 result = -ENOMEM; 453 result = -ENOMEM;
420 goto err_kfree; 454 goto err_kfree;
421 } 455 }
422 456
423 for (i=0; i<p.state_count; i++) { 457 for (i=0; i<p->state_count; i++) {
424 centrino_model[cpu]->op_points[i].index = p.states[i].control; 458 centrino_model[cpu]->op_points[i].index = p->states[i].control;
425 centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000; 459 centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000;
426 dprintk("adding state %i with frequency %u and control value %04x\n", 460 dprintk("adding state %i with frequency %u and control value %04x\n",
427 i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index); 461 i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
428 } 462 }
429 centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; 463 centrino_model[cpu]->op_points[p->state_count].frequency = CPUFREQ_TABLE_END;
430 464
431 cur_freq = get_cur_freq(cpu); 465 cur_freq = get_cur_freq(cpu);
432 466
433 for (i=0; i<p.state_count; i++) { 467 for (i=0; i<p->state_count; i++) {
434 if (!p.states[i].core_frequency) { 468 if (!p->states[i].core_frequency) {
435 dprintk("skipping state %u\n", i); 469 dprintk("skipping state %u\n", i);
436 centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; 470 centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID;
437 continue; 471 continue;
@@ -447,7 +481,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
447 } 481 }
448 482
449 if (cur_freq == centrino_model[cpu]->op_points[i].frequency) 483 if (cur_freq == centrino_model[cpu]->op_points[i].frequency)
450 p.state = i; 484 p->state = i;
451 } 485 }
452 486
453 /* notify BIOS that we exist */ 487 /* notify BIOS that we exist */
@@ -460,12 +494,13 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
460 err_kfree: 494 err_kfree:
461 kfree(centrino_model[cpu]); 495 kfree(centrino_model[cpu]);
462 err_unreg: 496 err_unreg:
463 acpi_processor_unregister_performance(&p, cpu); 497 acpi_processor_unregister_performance(p, cpu);
464 dprintk("invalid ACPI data\n"); 498 dprintk(PFX "invalid ACPI data\n");
465 return (result); 499 return (result);
466} 500}
467#else 501#else
468static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; } 502static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; }
503static inline int centrino_cpu_early_init_acpi(void) { return 0; }
469#endif 504#endif
470 505
471static int centrino_cpu_init(struct cpufreq_policy *policy) 506static int centrino_cpu_init(struct cpufreq_policy *policy)
@@ -551,10 +586,15 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
551 586
552#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 587#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
553 if (!centrino_model[cpu]->model_name) { 588 if (!centrino_model[cpu]->model_name) {
554 dprintk("unregistering and freeing ACPI data\n"); 589 static struct acpi_processor_performance *p;
555 acpi_processor_unregister_performance(&p, cpu); 590
556 kfree(centrino_model[cpu]->op_points); 591 if (acpi_perf_data[cpu]) {
557 kfree(centrino_model[cpu]); 592 p = acpi_perf_data[cpu];
593 dprintk("unregistering and freeing ACPI data\n");
594 acpi_processor_unregister_performance(p, cpu);
595 kfree(centrino_model[cpu]->op_points);
596 kfree(centrino_model[cpu]);
597 }
558 } 598 }
559#endif 599#endif
560 600
@@ -588,63 +628,128 @@ static int centrino_target (struct cpufreq_policy *policy,
588 unsigned int relation) 628 unsigned int relation)
589{ 629{
590 unsigned int newstate = 0; 630 unsigned int newstate = 0;
591 unsigned int msr, oldmsr, h, cpu = policy->cpu; 631 unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu;
592 struct cpufreq_freqs freqs; 632 struct cpufreq_freqs freqs;
633 cpumask_t online_policy_cpus;
593 cpumask_t saved_mask; 634 cpumask_t saved_mask;
594 int retval; 635 cpumask_t set_mask;
636 cpumask_t covered_cpus;
637 int retval = 0;
638 unsigned int j, k, first_cpu, tmp;
595 639
596 if (centrino_model[cpu] == NULL) 640 if (unlikely(centrino_model[cpu] == NULL))
597 return -ENODEV; 641 return -ENODEV;
598 642
599 /* 643 if (unlikely(cpufreq_frequency_table_target(policy,
600 * Support for SMP systems. 644 centrino_model[cpu]->op_points,
601 * Make sure we are running on the CPU that wants to change frequency 645 target_freq,
602 */ 646 relation,
603 saved_mask = current->cpus_allowed; 647 &newstate))) {
604 set_cpus_allowed(current, policy->cpus); 648 return -EINVAL;
605 if (!cpu_isset(smp_processor_id(), policy->cpus)) {
606 dprintk("couldn't limit to CPUs in this domain\n");
607 return(-EAGAIN);
608 } 649 }
609 650
610 if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq, 651#ifdef CONFIG_HOTPLUG_CPU
611 relation, &newstate)) { 652 /* cpufreq holds the hotplug lock, so we are safe from here on */
612 retval = -EINVAL; 653 cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
613 goto migrate_end; 654#else
614 } 655 online_policy_cpus = policy->cpus;
656#endif
615 657
616 msr = centrino_model[cpu]->op_points[newstate].index; 658 saved_mask = current->cpus_allowed;
617 rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); 659 first_cpu = 1;
660 cpus_clear(covered_cpus);
661 for_each_cpu_mask(j, online_policy_cpus) {
662 /*
663 * Support for SMP systems.
664 * Make sure we are running on CPU that wants to change freq
665 */
666 cpus_clear(set_mask);
667 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
668 cpus_or(set_mask, set_mask, online_policy_cpus);
669 else
670 cpu_set(j, set_mask);
671
672 set_cpus_allowed(current, set_mask);
673 if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
674 dprintk("couldn't limit to CPUs in this domain\n");
675 retval = -EAGAIN;
676 if (first_cpu) {
677 /* We haven't started the transition yet. */
678 goto migrate_end;
679 }
680 break;
681 }
618 682
619 if (msr == (oldmsr & 0xffff)) { 683 msr = centrino_model[cpu]->op_points[newstate].index;
620 retval = 0; 684
621 dprintk("no change needed - msr was and needs to be %x\n", oldmsr); 685 if (first_cpu) {
622 goto migrate_end; 686 rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
623 } 687 if (msr == (oldmsr & 0xffff)) {
688 dprintk("no change needed - msr was and needs "
689 "to be %x\n", oldmsr);
690 retval = 0;
691 goto migrate_end;
692 }
693
694 freqs.old = extract_clock(oldmsr, cpu, 0);
695 freqs.new = extract_clock(msr, cpu, 0);
696
697 dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
698 target_freq, freqs.old, freqs.new, msr);
699
700 for_each_cpu_mask(k, online_policy_cpus) {
701 freqs.cpu = k;
702 cpufreq_notify_transition(&freqs,
703 CPUFREQ_PRECHANGE);
704 }
705
706 first_cpu = 0;
707 /* all but 16 LSB are reserved, treat them with care */
708 oldmsr &= ~0xffff;
709 msr &= 0xffff;
710 oldmsr |= msr;
711 }
624 712
625 freqs.cpu = cpu; 713 wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
626 freqs.old = extract_clock(oldmsr, cpu, 0); 714 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
627 freqs.new = extract_clock(msr, cpu, 0); 715 break;
628 716
629 dprintk("target=%dkHz old=%d new=%d msr=%04x\n", 717 cpu_set(j, covered_cpus);
630 target_freq, freqs.old, freqs.new, msr); 718 }
631 719
632 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 720 for_each_cpu_mask(k, online_policy_cpus) {
721 freqs.cpu = k;
722 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
723 }
633 724
634 /* all but 16 LSB are "reserved", so treat them with 725 if (unlikely(retval)) {
635 care */ 726 /*
636 oldmsr &= ~0xffff; 727 * We have failed halfway through the frequency change.
637 msr &= 0xffff; 728 * We have sent callbacks to policy->cpus and
638 oldmsr |= msr; 729 * MSRs have already been written on coverd_cpus.
730 * Best effort undo..
731 */
639 732
640 wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); 733 if (!cpus_empty(covered_cpus)) {
734 for_each_cpu_mask(j, covered_cpus) {
735 set_cpus_allowed(current, cpumask_of_cpu(j));
736 wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
737 }
738 }
641 739
642 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 740 tmp = freqs.new;
741 freqs.new = freqs.old;
742 freqs.old = tmp;
743 for_each_cpu_mask(j, online_policy_cpus) {
744 freqs.cpu = j;
745 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
746 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
747 }
748 }
643 749
644 retval = 0;
645migrate_end: 750migrate_end:
646 set_cpus_allowed(current, saved_mask); 751 set_cpus_allowed(current, saved_mask);
647 return (retval); 752 return 0;
648} 753}
649 754
650static struct freq_attr* centrino_attr[] = { 755static struct freq_attr* centrino_attr[] = {
@@ -686,12 +791,25 @@ static int __init centrino_init(void)
686 if (!cpu_has(cpu, X86_FEATURE_EST)) 791 if (!cpu_has(cpu, X86_FEATURE_EST))
687 return -ENODEV; 792 return -ENODEV;
688 793
794 centrino_cpu_early_init_acpi();
795
689 return cpufreq_register_driver(&centrino_driver); 796 return cpufreq_register_driver(&centrino_driver);
690} 797}
691 798
692static void __exit centrino_exit(void) 799static void __exit centrino_exit(void)
693{ 800{
801#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
802 unsigned int j;
803#endif
804
694 cpufreq_unregister_driver(&centrino_driver); 805 cpufreq_unregister_driver(&centrino_driver);
806
807#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
808 for_each_cpu(j) {
809 kfree(acpi_perf_data[j]);
810 acpi_perf_data[j] = NULL;
811 }
812#endif
695} 813}
696 814
697MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); 815MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");