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 */ |
