diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 14:10:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 14:10:21 -0700 |
commit | 70f6c087573eeb406252ff8d98f511eb5f71496e (patch) | |
tree | c02dcd0e75409490f11b173924ad1f2c4f45a2ff /drivers/cpufreq/cpufreq.c | |
parent | e6d9bfc63813882c896bf7ea6f6b14ca7b50b755 (diff) | |
parent | 7b5c39389c86063e86fe8f2e0093c7197ddfa60a (diff) |
Merge tag 'pm+acpi-3.15-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more ACPI and power management updates from Rafael Wysocki:
"These are commits that were not quite ready when I sent the original
pull request for 3.15-rc1 several days ago, but they have spent some
time in linux-next since then and appear to be good to go. All of
them are fixes and cleanups.
Specifics:
- Remaining changes from upstream ACPICA release 20140214 that
introduce code to automatically serialize the execution of methods
creating any named objects which really cannot be executed in
parallel with each other anyway (previously ACPICA attempted to
address that by aborting methods upon conflict detection, but that
wasn't reliable enough and led to other issues). From Bob Moore
and Lv Zheng.
- intel_pstate fix to use del_timer_sync() instead of del_timer() in
the exit path before freeing the timer structure from Dirk
Brandewie (original patch from Thomas Gleixner).
- cpufreq fix related to system resume from Viresh Kumar.
- Serialization of frequency transitions in cpufreq that involve
PRECHANGE and POSTCHANGE notifications to avoid ordering issues
resulting from race conditions. From Srivatsa S Bhat and Viresh
Kumar.
- Revert of an ACPI processor driver change that was based on a
specific interpretation of the ACPI spec which may not be correct
(the relevant part of the spec appears to be incomplete). From
Hanjun Guo.
- Runtime PM core cleanups and documentation updates from Geert
Uytterhoeven.
- PNP core cleanup from Michael Opdenacker"
* tag 'pm+acpi-3.15-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
cpufreq: Make cpufreq_notify_transition & cpufreq_notify_post_transition static
cpufreq: Convert existing drivers to use cpufreq_freq_transition_{begin|end}
cpufreq: Make sure frequency transitions are serialized
intel_pstate: Use del_timer_sync in intel_pstate_cpu_stop
cpufreq: resume drivers before enabling governors
PM / Runtime: Spelling s/competing/completing/
PM / Runtime: s/foo_process_requests/foo_process_next_request/
PM / Runtime: GENERIC_SUBSYS_PM_OPS is gone
PM / Runtime: Correct documented return values for generic PM callbacks
PM / Runtime: Split line longer than 80 characters
PM / Runtime: dev_pm_info.runtime_error is signed
Revert "ACPI / processor: Make it possible to get APIC ID via GIC"
ACPICA: Enable auto-serialization as a default kernel behavior.
ACPICA: Ignore sync_level for methods that have been auto-serialized.
ACPICA: Add additional named objects for the auto-serialize method scan.
ACPICA: Add auto-serialization support for ill-behaved control methods.
ACPICA: Remove global option to serialize all control methods.
PNP: remove deprecated IRQF_DISABLED
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 61 |
1 files changed, 47 insertions, 14 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3aa7a7a226b..abda6609d3e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -331,16 +331,15 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, * function. It is called twice on all CPU frequency changes that have * external effects. */ -void cpufreq_notify_transition(struct cpufreq_policy *policy, +static void cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) { for_each_cpu(freqs->cpu, policy->cpus) __cpufreq_notify_transition(policy, freqs, state); } -EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /* Do post notifications when there are chances that transition has failed */ -void cpufreq_notify_post_transition(struct cpufreq_policy *policy, +static void cpufreq_notify_post_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, int transition_failed) { cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); @@ -351,7 +350,41 @@ void cpufreq_notify_post_transition(struct cpufreq_policy *policy, cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); } -EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); + +void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs) +{ +wait: + wait_event(policy->transition_wait, !policy->transition_ongoing); + + spin_lock(&policy->transition_lock); + + if (unlikely(policy->transition_ongoing)) { + spin_unlock(&policy->transition_lock); + goto wait; + } + + policy->transition_ongoing = true; + + spin_unlock(&policy->transition_lock); + + cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); +} +EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin); + +void cpufreq_freq_transition_end(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed) +{ + if (unlikely(WARN_ON(!policy->transition_ongoing))) + return; + + cpufreq_notify_post_transition(policy, freqs, transition_failed); + + policy->transition_ongoing = false; + + wake_up(&policy->transition_wait); +} +EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end); /********************************************************************* @@ -985,6 +1018,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void) INIT_LIST_HEAD(&policy->policy_list); init_rwsem(&policy->rwsem); + spin_lock_init(&policy->transition_lock); + init_waitqueue_head(&policy->transition_wait); return policy; @@ -1470,8 +1505,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, policy = per_cpu(cpufreq_cpu_data, cpu); read_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_begin(policy, &freqs); + cpufreq_freq_transition_end(policy, &freqs, 0); } /** @@ -1652,14 +1687,13 @@ void cpufreq_resume(void) cpufreq_suspended = false; list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { - if (__cpufreq_governor(policy, CPUFREQ_GOV_START) + if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) + pr_err("%s: Failed to resume driver: %p\n", __func__, + policy); + else if (__cpufreq_governor(policy, CPUFREQ_GOV_START) || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) pr_err("%s: Failed to start governor for policy: %p\n", __func__, policy); - else if (cpufreq_driver->resume - && cpufreq_driver->resume(policy)) - pr_err("%s: Failed to resume driver: %p\n", __func__, - policy); /* * schedule call cpufreq_update_policy() for boot CPU, i.e. last @@ -1832,8 +1866,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", __func__, policy->cpu, freqs.old, freqs.new); - cpufreq_notify_transition(policy, &freqs, - CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); } retval = cpufreq_driver->target_index(policy, index); @@ -1842,7 +1875,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, __func__, retval); if (notify) - cpufreq_notify_post_transition(policy, &freqs, retval); + cpufreq_freq_transition_end(policy, &freqs, retval); } out: |