aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpufreq/cpufreq.c37
-rw-r--r--include/linux/cpufreq.h10
2 files changed, 47 insertions, 0 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index d8d6bc9d1815..d57806a85def 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -353,6 +353,41 @@ void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
353} 353}
354EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); 354EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
355 355
356void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
357 struct cpufreq_freqs *freqs)
358{
359wait:
360 wait_event(policy->transition_wait, !policy->transition_ongoing);
361
362 spin_lock(&policy->transition_lock);
363
364 if (unlikely(policy->transition_ongoing)) {
365 spin_unlock(&policy->transition_lock);
366 goto wait;
367 }
368
369 policy->transition_ongoing = true;
370
371 spin_unlock(&policy->transition_lock);
372
373 cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
374}
375EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin);
376
377void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
378 struct cpufreq_freqs *freqs, int transition_failed)
379{
380 if (unlikely(WARN_ON(!policy->transition_ongoing)))
381 return;
382
383 cpufreq_notify_post_transition(policy, freqs, transition_failed);
384
385 policy->transition_ongoing = false;
386
387 wake_up(&policy->transition_wait);
388}
389EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end);
390
356 391
357/********************************************************************* 392/*********************************************************************
358 * SYSFS INTERFACE * 393 * SYSFS INTERFACE *
@@ -985,6 +1020,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
985 1020
986 INIT_LIST_HEAD(&policy->policy_list); 1021 INIT_LIST_HEAD(&policy->policy_list);
987 init_rwsem(&policy->rwsem); 1022 init_rwsem(&policy->rwsem);
1023 spin_lock_init(&policy->transition_lock);
1024 init_waitqueue_head(&policy->transition_wait);
988 1025
989 return policy; 1026 return policy;
990 1027
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 2d2e62c8666a..e33760268a86 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -16,6 +16,7 @@
16#include <linux/completion.h> 16#include <linux/completion.h>
17#include <linux/kobject.h> 17#include <linux/kobject.h>
18#include <linux/notifier.h> 18#include <linux/notifier.h>
19#include <linux/spinlock.h>
19#include <linux/sysfs.h> 20#include <linux/sysfs.h>
20 21
21/********************************************************************* 22/*********************************************************************
@@ -104,6 +105,11 @@ struct cpufreq_policy {
104 * __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); 105 * __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
105 */ 106 */
106 struct rw_semaphore rwsem; 107 struct rw_semaphore rwsem;
108
109 /* Synchronization for frequency transitions */
110 bool transition_ongoing; /* Tracks transition status */
111 spinlock_t transition_lock;
112 wait_queue_head_t transition_wait;
107}; 113};
108 114
109/* Only for ACPI */ 115/* Only for ACPI */
@@ -337,6 +343,10 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
337 struct cpufreq_freqs *freqs, unsigned int state); 343 struct cpufreq_freqs *freqs, unsigned int state);
338void cpufreq_notify_post_transition(struct cpufreq_policy *policy, 344void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
339 struct cpufreq_freqs *freqs, int transition_failed); 345 struct cpufreq_freqs *freqs, int transition_failed);
346void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
347 struct cpufreq_freqs *freqs);
348void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
349 struct cpufreq_freqs *freqs, int transition_failed);
340 350
341#else /* CONFIG_CPU_FREQ */ 351#else /* CONFIG_CPU_FREQ */
342static inline int cpufreq_register_notifier(struct notifier_block *nb, 352static inline int cpufreq_register_notifier(struct notifier_block *nb,