diff options
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r-- | drivers/cpuidle/coupled.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 5d3962730063..f8a86364c6b6 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c | |||
@@ -408,19 +408,22 @@ static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled) | |||
408 | * been processed and the poke bit has been cleared. | 408 | * been processed and the poke bit has been cleared. |
409 | * | 409 | * |
410 | * Other interrupts may also be processed while interrupts are enabled, so | 410 | * Other interrupts may also be processed while interrupts are enabled, so |
411 | * need_resched() must be tested after turning interrupts off again to make sure | 411 | * need_resched() must be tested after this function returns to make sure |
412 | * the interrupt didn't schedule work that should take the cpu out of idle. | 412 | * the interrupt didn't schedule work that should take the cpu out of idle. |
413 | * | 413 | * |
414 | * Returns 0 if need_resched was false, -EINTR if need_resched was true. | 414 | * Returns 0 if no poke was pending, 1 if a poke was cleared. |
415 | */ | 415 | */ |
416 | static int cpuidle_coupled_clear_pokes(int cpu) | 416 | static int cpuidle_coupled_clear_pokes(int cpu) |
417 | { | 417 | { |
418 | if (!cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) | ||
419 | return 0; | ||
420 | |||
418 | local_irq_enable(); | 421 | local_irq_enable(); |
419 | while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) | 422 | while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) |
420 | cpu_relax(); | 423 | cpu_relax(); |
421 | local_irq_disable(); | 424 | local_irq_disable(); |
422 | 425 | ||
423 | return need_resched() ? -EINTR : 0; | 426 | return 1; |
424 | } | 427 | } |
425 | 428 | ||
426 | static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled) | 429 | static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled) |
@@ -464,7 +467,8 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, | |||
464 | return -EINVAL; | 467 | return -EINVAL; |
465 | 468 | ||
466 | while (coupled->prevent) { | 469 | while (coupled->prevent) { |
467 | if (cpuidle_coupled_clear_pokes(dev->cpu)) { | 470 | cpuidle_coupled_clear_pokes(dev->cpu); |
471 | if (need_resched()) { | ||
468 | local_irq_enable(); | 472 | local_irq_enable(); |
469 | return entered_state; | 473 | return entered_state; |
470 | } | 474 | } |
@@ -503,7 +507,10 @@ retry: | |||
503 | */ | 507 | */ |
504 | while (!cpuidle_coupled_cpus_waiting(coupled) || | 508 | while (!cpuidle_coupled_cpus_waiting(coupled) || |
505 | !cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) { | 509 | !cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) { |
506 | if (cpuidle_coupled_clear_pokes(dev->cpu)) { | 510 | if (cpuidle_coupled_clear_pokes(dev->cpu)) |
511 | continue; | ||
512 | |||
513 | if (need_resched()) { | ||
507 | cpuidle_coupled_set_not_waiting(dev->cpu, coupled); | 514 | cpuidle_coupled_set_not_waiting(dev->cpu, coupled); |
508 | goto out; | 515 | goto out; |
509 | } | 516 | } |
@@ -518,7 +525,8 @@ retry: | |||
518 | local_irq_disable(); | 525 | local_irq_disable(); |
519 | } | 526 | } |
520 | 527 | ||
521 | if (cpuidle_coupled_clear_pokes(dev->cpu)) { | 528 | cpuidle_coupled_clear_pokes(dev->cpu); |
529 | if (need_resched()) { | ||
522 | cpuidle_coupled_set_not_waiting(dev->cpu, coupled); | 530 | cpuidle_coupled_set_not_waiting(dev->cpu, coupled); |
523 | goto out; | 531 | goto out; |
524 | } | 532 | } |