diff options
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 14 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 1 |
2 files changed, 15 insertions, 0 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a517da996aaf..bfe82b63875f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -365,6 +365,18 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy, | |||
365 | void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, | 365 | void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, |
366 | struct cpufreq_freqs *freqs) | 366 | struct cpufreq_freqs *freqs) |
367 | { | 367 | { |
368 | |||
369 | /* | ||
370 | * Catch double invocations of _begin() which lead to self-deadlock. | ||
371 | * ASYNC_NOTIFICATION drivers are left out because the cpufreq core | ||
372 | * doesn't invoke _begin() on their behalf, and hence the chances of | ||
373 | * double invocations are very low. Moreover, there are scenarios | ||
374 | * where these checks can emit false-positive warnings in these | ||
375 | * drivers; so we avoid that by skipping them altogether. | ||
376 | */ | ||
377 | WARN_ON(!(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION) | ||
378 | && current == policy->transition_task); | ||
379 | |||
368 | wait: | 380 | wait: |
369 | wait_event(policy->transition_wait, !policy->transition_ongoing); | 381 | wait_event(policy->transition_wait, !policy->transition_ongoing); |
370 | 382 | ||
@@ -376,6 +388,7 @@ wait: | |||
376 | } | 388 | } |
377 | 389 | ||
378 | policy->transition_ongoing = true; | 390 | policy->transition_ongoing = true; |
391 | policy->transition_task = current; | ||
379 | 392 | ||
380 | spin_unlock(&policy->transition_lock); | 393 | spin_unlock(&policy->transition_lock); |
381 | 394 | ||
@@ -392,6 +405,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, | |||
392 | cpufreq_notify_post_transition(policy, freqs, transition_failed); | 405 | cpufreq_notify_post_transition(policy, freqs, transition_failed); |
393 | 406 | ||
394 | policy->transition_ongoing = false; | 407 | policy->transition_ongoing = false; |
408 | policy->transition_task = NULL; | ||
395 | 409 | ||
396 | wake_up(&policy->transition_wait); | 410 | wake_up(&policy->transition_wait); |
397 | } | 411 | } |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 77a5fa191502..f3822f836e14 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
@@ -110,6 +110,7 @@ struct cpufreq_policy { | |||
110 | bool transition_ongoing; /* Tracks transition status */ | 110 | bool transition_ongoing; /* Tracks transition status */ |
111 | spinlock_t transition_lock; | 111 | spinlock_t transition_lock; |
112 | wait_queue_head_t transition_wait; | 112 | wait_queue_head_t transition_wait; |
113 | struct task_struct *transition_task; /* Task which is doing the transition */ | ||
113 | }; | 114 | }; |
114 | 115 | ||
115 | /* Only for ACPI */ | 116 | /* Only for ACPI */ |