diff options
| -rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c | 73 |
1 files changed, 45 insertions, 28 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c index fd561bb26c60..470c016cb254 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c | |||
| @@ -442,6 +442,13 @@ static int centrino_verify (struct cpufreq_policy *policy) | |||
| 442 | * | 442 | * |
| 443 | * Sets a new CPUFreq policy. | 443 | * Sets a new CPUFreq policy. |
| 444 | */ | 444 | */ |
| 445 | struct allmasks { | ||
| 446 | cpumask_t online_policy_cpus; | ||
| 447 | cpumask_t saved_mask; | ||
| 448 | cpumask_t set_mask; | ||
| 449 | cpumask_t covered_cpus; | ||
| 450 | }; | ||
| 451 | |||
| 445 | static int centrino_target (struct cpufreq_policy *policy, | 452 | static int centrino_target (struct cpufreq_policy *policy, |
| 446 | unsigned int target_freq, | 453 | unsigned int target_freq, |
| 447 | unsigned int relation) | 454 | unsigned int relation) |
| @@ -449,48 +456,55 @@ static int centrino_target (struct cpufreq_policy *policy, | |||
| 449 | unsigned int newstate = 0; | 456 | unsigned int newstate = 0; |
| 450 | unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; | 457 | unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; |
| 451 | struct cpufreq_freqs freqs; | 458 | struct cpufreq_freqs freqs; |
| 452 | cpumask_t online_policy_cpus; | ||
| 453 | cpumask_t saved_mask; | ||
| 454 | cpumask_t set_mask; | ||
| 455 | cpumask_t covered_cpus; | ||
| 456 | int retval = 0; | 459 | int retval = 0; |
| 457 | unsigned int j, k, first_cpu, tmp; | 460 | unsigned int j, k, first_cpu, tmp; |
| 458 | 461 | CPUMASK_ALLOC(allmasks); | |
| 459 | if (unlikely(centrino_model[cpu] == NULL)) | 462 | CPUMASK_VAR(online_policy_cpus, allmasks); |
| 460 | return -ENODEV; | 463 | CPUMASK_VAR(saved_mask, allmasks); |
| 464 | CPUMASK_VAR(set_mask, allmasks); | ||
| 465 | CPUMASK_VAR(covered_cpus, allmasks); | ||
| 466 | |||
| 467 | if (unlikely(allmasks == NULL)) | ||
| 468 | return -ENOMEM; | ||
| 469 | |||
| 470 | if (unlikely(centrino_model[cpu] == NULL)) { | ||
| 471 | retval = -ENODEV; | ||
| 472 | goto out; | ||
| 473 | } | ||
| 461 | 474 | ||
| 462 | if (unlikely(cpufreq_frequency_table_target(policy, | 475 | if (unlikely(cpufreq_frequency_table_target(policy, |
| 463 | centrino_model[cpu]->op_points, | 476 | centrino_model[cpu]->op_points, |
| 464 | target_freq, | 477 | target_freq, |
| 465 | relation, | 478 | relation, |
| 466 | &newstate))) { | 479 | &newstate))) { |
| 467 | return -EINVAL; | 480 | retval = -EINVAL; |
| 481 | goto out; | ||
| 468 | } | 482 | } |
| 469 | 483 | ||
| 470 | #ifdef CONFIG_HOTPLUG_CPU | 484 | #ifdef CONFIG_HOTPLUG_CPU |
| 471 | /* cpufreq holds the hotplug lock, so we are safe from here on */ | 485 | /* cpufreq holds the hotplug lock, so we are safe from here on */ |
| 472 | cpus_and(online_policy_cpus, cpu_online_map, policy->cpus); | 486 | cpus_and(*online_policy_cpus, cpu_online_map, policy->cpus); |
| 473 | #else | 487 | #else |
| 474 | online_policy_cpus = policy->cpus; | 488 | *online_policy_cpus = policy->cpus; |
| 475 | #endif | 489 | #endif |
| 476 | 490 | ||
| 477 | saved_mask = current->cpus_allowed; | 491 | *saved_mask = current->cpus_allowed; |
| 478 | first_cpu = 1; | 492 | first_cpu = 1; |
| 479 | cpus_clear(covered_cpus); | 493 | cpus_clear(*covered_cpus); |
| 480 | for_each_cpu_mask_nr(j, online_policy_cpus) { | 494 | for_each_cpu_mask_nr(j, *online_policy_cpus) { |
| 481 | /* | 495 | /* |
| 482 | * Support for SMP systems. | 496 | * Support for SMP systems. |
| 483 | * Make sure we are running on CPU that wants to change freq | 497 | * Make sure we are running on CPU that wants to change freq |
| 484 | */ | 498 | */ |
| 485 | cpus_clear(set_mask); | 499 | cpus_clear(*set_mask); |
| 486 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) | 500 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) |
| 487 | cpus_or(set_mask, set_mask, online_policy_cpus); | 501 | cpus_or(*set_mask, *set_mask, *online_policy_cpus); |
| 488 | else | 502 | else |
| 489 | cpu_set(j, set_mask); | 503 | cpu_set(j, *set_mask); |
| 490 | 504 | ||
| 491 | set_cpus_allowed_ptr(current, &set_mask); | 505 | set_cpus_allowed_ptr(current, set_mask); |
| 492 | preempt_disable(); | 506 | preempt_disable(); |
| 493 | if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) { | 507 | if (unlikely(!cpu_isset(smp_processor_id(), *set_mask))) { |
| 494 | dprintk("couldn't limit to CPUs in this domain\n"); | 508 | dprintk("couldn't limit to CPUs in this domain\n"); |
| 495 | retval = -EAGAIN; | 509 | retval = -EAGAIN; |
| 496 | if (first_cpu) { | 510 | if (first_cpu) { |
| @@ -518,7 +532,7 @@ static int centrino_target (struct cpufreq_policy *policy, | |||
| 518 | dprintk("target=%dkHz old=%d new=%d msr=%04x\n", | 532 | dprintk("target=%dkHz old=%d new=%d msr=%04x\n", |
| 519 | target_freq, freqs.old, freqs.new, msr); | 533 | target_freq, freqs.old, freqs.new, msr); |
| 520 | 534 | ||
| 521 | for_each_cpu_mask_nr(k, online_policy_cpus) { | 535 | for_each_cpu_mask_nr(k, *online_policy_cpus) { |
| 522 | freqs.cpu = k; | 536 | freqs.cpu = k; |
| 523 | cpufreq_notify_transition(&freqs, | 537 | cpufreq_notify_transition(&freqs, |
| 524 | CPUFREQ_PRECHANGE); | 538 | CPUFREQ_PRECHANGE); |
| @@ -537,11 +551,11 @@ static int centrino_target (struct cpufreq_policy *policy, | |||
| 537 | break; | 551 | break; |
| 538 | } | 552 | } |
| 539 | 553 | ||
| 540 | cpu_set(j, covered_cpus); | 554 | cpu_set(j, *covered_cpus); |
| 541 | preempt_enable(); | 555 | preempt_enable(); |
| 542 | } | 556 | } |
| 543 | 557 | ||
| 544 | for_each_cpu_mask_nr(k, online_policy_cpus) { | 558 | for_each_cpu_mask_nr(k, *online_policy_cpus) { |
| 545 | freqs.cpu = k; | 559 | freqs.cpu = k; |
| 546 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | 560 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
| 547 | } | 561 | } |
| @@ -554,10 +568,10 @@ static int centrino_target (struct cpufreq_policy *policy, | |||
| 554 | * Best effort undo.. | 568 | * Best effort undo.. |
| 555 | */ | 569 | */ |
| 556 | 570 | ||
| 557 | if (!cpus_empty(covered_cpus)) { | 571 | if (!cpus_empty(*covered_cpus)) { |
| 558 | cpumask_of_cpu_ptr_declare(new_mask); | 572 | cpumask_of_cpu_ptr_declare(new_mask); |
| 559 | 573 | ||
| 560 | for_each_cpu_mask_nr(j, covered_cpus) { | 574 | for_each_cpu_mask_nr(j, *covered_cpus) { |
| 561 | cpumask_of_cpu_ptr_next(new_mask, j); | 575 | cpumask_of_cpu_ptr_next(new_mask, j); |
| 562 | set_cpus_allowed_ptr(current, new_mask); | 576 | set_cpus_allowed_ptr(current, new_mask); |
| 563 | wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); | 577 | wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); |
| @@ -567,19 +581,22 @@ static int centrino_target (struct cpufreq_policy *policy, | |||
| 567 | tmp = freqs.new; | 581 | tmp = freqs.new; |
| 568 | freqs.new = freqs.old; | 582 | freqs.new = freqs.old; |
| 569 | freqs.old = tmp; | 583 | freqs.old = tmp; |
| 570 | for_each_cpu_mask_nr(j, online_policy_cpus) { | 584 | for_each_cpu_mask_nr(j, *online_policy_cpus) { |
| 571 | freqs.cpu = j; | 585 | freqs.cpu = j; |
| 572 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | 586 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
| 573 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | 587 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
| 574 | } | 588 | } |
| 575 | } | 589 | } |
| 576 | set_cpus_allowed_ptr(current, &saved_mask); | 590 | set_cpus_allowed_ptr(current, saved_mask); |
| 577 | return 0; | 591 | retval = 0; |
| 592 | goto out; | ||
| 578 | 593 | ||
| 579 | migrate_end: | 594 | migrate_end: |
| 580 | preempt_enable(); | 595 | preempt_enable(); |
| 581 | set_cpus_allowed_ptr(current, &saved_mask); | 596 | set_cpus_allowed_ptr(current, saved_mask); |
| 582 | return 0; | 597 | out: |
| 598 | CPUMASK_FREE(allmasks); | ||
| 599 | return retval; | ||
| 583 | } | 600 | } |
| 584 | |||
