diff options
-rw-r--r-- | arch/x86/kernel/process.c | 6 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 46 | ||||
-rw-r--r-- | drivers/idle/intel_idle.c | 2 | ||||
-rw-r--r-- | include/linux/sched.h | 78 | ||||
-rw-r--r-- | include/linux/thread_info.h | 2 | ||||
-rw-r--r-- | kernel/cpu/idle.c | 9 |
6 files changed, 91 insertions, 52 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c83516be1052..3fb8d95ab8b5 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -391,9 +391,9 @@ static void amd_e400_idle(void) | |||
391 | * The switch back from broadcast mode needs to be | 391 | * The switch back from broadcast mode needs to be |
392 | * called with interrupts disabled. | 392 | * called with interrupts disabled. |
393 | */ | 393 | */ |
394 | local_irq_disable(); | 394 | local_irq_disable(); |
395 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | 395 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); |
396 | local_irq_enable(); | 396 | local_irq_enable(); |
397 | } else | 397 | } else |
398 | default_idle(); | 398 | default_idle(); |
399 | } | 399 | } |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f98dd00b51a9..c7414a545a4f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -119,17 +119,10 @@ static struct dmi_system_id processor_power_dmi_table[] = { | |||
119 | */ | 119 | */ |
120 | static void acpi_safe_halt(void) | 120 | static void acpi_safe_halt(void) |
121 | { | 121 | { |
122 | current_thread_info()->status &= ~TS_POLLING; | 122 | if (!tif_need_resched()) { |
123 | /* | ||
124 | * TS_POLLING-cleared state must be visible before we | ||
125 | * test NEED_RESCHED: | ||
126 | */ | ||
127 | smp_mb(); | ||
128 | if (!need_resched()) { | ||
129 | safe_halt(); | 123 | safe_halt(); |
130 | local_irq_disable(); | 124 | local_irq_disable(); |
131 | } | 125 | } |
132 | current_thread_info()->status |= TS_POLLING; | ||
133 | } | 126 | } |
134 | 127 | ||
135 | #ifdef ARCH_APICTIMER_STOPS_ON_C3 | 128 | #ifdef ARCH_APICTIMER_STOPS_ON_C3 |
@@ -737,6 +730,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, | |||
737 | if (unlikely(!pr)) | 730 | if (unlikely(!pr)) |
738 | return -EINVAL; | 731 | return -EINVAL; |
739 | 732 | ||
733 | if (cx->entry_method == ACPI_CSTATE_FFH) { | ||
734 | if (current_set_polling_and_test()) | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
740 | lapic_timer_state_broadcast(pr, cx, 1); | 738 | lapic_timer_state_broadcast(pr, cx, 1); |
741 | acpi_idle_do_entry(cx); | 739 | acpi_idle_do_entry(cx); |
742 | 740 | ||
@@ -790,18 +788,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, | |||
790 | if (unlikely(!pr)) | 788 | if (unlikely(!pr)) |
791 | return -EINVAL; | 789 | return -EINVAL; |
792 | 790 | ||
793 | if (cx->entry_method != ACPI_CSTATE_FFH) { | 791 | if (cx->entry_method == ACPI_CSTATE_FFH) { |
794 | current_thread_info()->status &= ~TS_POLLING; | 792 | if (current_set_polling_and_test()) |
795 | /* | ||
796 | * TS_POLLING-cleared state must be visible before we test | ||
797 | * NEED_RESCHED: | ||
798 | */ | ||
799 | smp_mb(); | ||
800 | |||
801 | if (unlikely(need_resched())) { | ||
802 | current_thread_info()->status |= TS_POLLING; | ||
803 | return -EINVAL; | 793 | return -EINVAL; |
804 | } | ||
805 | } | 794 | } |
806 | 795 | ||
807 | /* | 796 | /* |
@@ -819,9 +808,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, | |||
819 | 808 | ||
820 | sched_clock_idle_wakeup_event(0); | 809 | sched_clock_idle_wakeup_event(0); |
821 | 810 | ||
822 | if (cx->entry_method != ACPI_CSTATE_FFH) | ||
823 | current_thread_info()->status |= TS_POLLING; | ||
824 | |||
825 | lapic_timer_state_broadcast(pr, cx, 0); | 811 | lapic_timer_state_broadcast(pr, cx, 0); |
826 | return index; | 812 | return index; |
827 | } | 813 | } |
@@ -858,18 +844,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, | |||
858 | } | 844 | } |
859 | } | 845 | } |
860 | 846 | ||
861 | if (cx->entry_method != ACPI_CSTATE_FFH) { | 847 | if (cx->entry_method == ACPI_CSTATE_FFH) { |
862 | current_thread_info()->status &= ~TS_POLLING; | 848 | if (current_set_polling_and_test()) |
863 | /* | ||
864 | * TS_POLLING-cleared state must be visible before we test | ||
865 | * NEED_RESCHED: | ||
866 | */ | ||
867 | smp_mb(); | ||
868 | |||
869 | if (unlikely(need_resched())) { | ||
870 | current_thread_info()->status |= TS_POLLING; | ||
871 | return -EINVAL; | 849 | return -EINVAL; |
872 | } | ||
873 | } | 850 | } |
874 | 851 | ||
875 | acpi_unlazy_tlb(smp_processor_id()); | 852 | acpi_unlazy_tlb(smp_processor_id()); |
@@ -915,9 +892,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, | |||
915 | 892 | ||
916 | sched_clock_idle_wakeup_event(0); | 893 | sched_clock_idle_wakeup_event(0); |
917 | 894 | ||
918 | if (cx->entry_method != ACPI_CSTATE_FFH) | ||
919 | current_thread_info()->status |= TS_POLLING; | ||
920 | |||
921 | lapic_timer_state_broadcast(pr, cx, 0); | 895 | lapic_timer_state_broadcast(pr, cx, 0); |
922 | return index; | 896 | return index; |
923 | } | 897 | } |
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index fa6964d8681a..f116d664b473 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -359,7 +359,7 @@ static int intel_idle(struct cpuidle_device *dev, | |||
359 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 359 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
360 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | 360 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); |
361 | 361 | ||
362 | if (!need_resched()) { | 362 | if (!current_set_polling_and_test()) { |
363 | 363 | ||
364 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 364 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
365 | smp_mb(); | 365 | smp_mb(); |
diff --git a/include/linux/sched.h b/include/linux/sched.h index b5344de1658b..e783ec52295a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -2479,34 +2479,98 @@ static inline int tsk_is_polling(struct task_struct *p) | |||
2479 | { | 2479 | { |
2480 | return task_thread_info(p)->status & TS_POLLING; | 2480 | return task_thread_info(p)->status & TS_POLLING; |
2481 | } | 2481 | } |
2482 | static inline void current_set_polling(void) | 2482 | static inline void __current_set_polling(void) |
2483 | { | 2483 | { |
2484 | current_thread_info()->status |= TS_POLLING; | 2484 | current_thread_info()->status |= TS_POLLING; |
2485 | } | 2485 | } |
2486 | 2486 | ||
2487 | static inline void current_clr_polling(void) | 2487 | static inline bool __must_check current_set_polling_and_test(void) |
2488 | { | ||
2489 | __current_set_polling(); | ||
2490 | |||
2491 | /* | ||
2492 | * Polling state must be visible before we test NEED_RESCHED, | ||
2493 | * paired by resched_task() | ||
2494 | */ | ||
2495 | smp_mb(); | ||
2496 | |||
2497 | return unlikely(tif_need_resched()); | ||
2498 | } | ||
2499 | |||
2500 | static inline void __current_clr_polling(void) | ||
2488 | { | 2501 | { |
2489 | current_thread_info()->status &= ~TS_POLLING; | 2502 | current_thread_info()->status &= ~TS_POLLING; |
2490 | smp_mb__after_clear_bit(); | 2503 | } |
2504 | |||
2505 | static inline bool __must_check current_clr_polling_and_test(void) | ||
2506 | { | ||
2507 | __current_clr_polling(); | ||
2508 | |||
2509 | /* | ||
2510 | * Polling state must be visible before we test NEED_RESCHED, | ||
2511 | * paired by resched_task() | ||
2512 | */ | ||
2513 | smp_mb(); | ||
2514 | |||
2515 | return unlikely(tif_need_resched()); | ||
2491 | } | 2516 | } |
2492 | #elif defined(TIF_POLLING_NRFLAG) | 2517 | #elif defined(TIF_POLLING_NRFLAG) |
2493 | static inline int tsk_is_polling(struct task_struct *p) | 2518 | static inline int tsk_is_polling(struct task_struct *p) |
2494 | { | 2519 | { |
2495 | return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); | 2520 | return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); |
2496 | } | 2521 | } |
2497 | static inline void current_set_polling(void) | 2522 | |
2523 | static inline void __current_set_polling(void) | ||
2498 | { | 2524 | { |
2499 | set_thread_flag(TIF_POLLING_NRFLAG); | 2525 | set_thread_flag(TIF_POLLING_NRFLAG); |
2500 | } | 2526 | } |
2501 | 2527 | ||
2502 | static inline void current_clr_polling(void) | 2528 | static inline bool __must_check current_set_polling_and_test(void) |
2529 | { | ||
2530 | __current_set_polling(); | ||
2531 | |||
2532 | /* | ||
2533 | * Polling state must be visible before we test NEED_RESCHED, | ||
2534 | * paired by resched_task() | ||
2535 | * | ||
2536 | * XXX: assumes set/clear bit are identical barrier wise. | ||
2537 | */ | ||
2538 | smp_mb__after_clear_bit(); | ||
2539 | |||
2540 | return unlikely(tif_need_resched()); | ||
2541 | } | ||
2542 | |||
2543 | static inline void __current_clr_polling(void) | ||
2503 | { | 2544 | { |
2504 | clear_thread_flag(TIF_POLLING_NRFLAG); | 2545 | clear_thread_flag(TIF_POLLING_NRFLAG); |
2505 | } | 2546 | } |
2547 | |||
2548 | static inline bool __must_check current_clr_polling_and_test(void) | ||
2549 | { | ||
2550 | __current_clr_polling(); | ||
2551 | |||
2552 | /* | ||
2553 | * Polling state must be visible before we test NEED_RESCHED, | ||
2554 | * paired by resched_task() | ||
2555 | */ | ||
2556 | smp_mb__after_clear_bit(); | ||
2557 | |||
2558 | return unlikely(tif_need_resched()); | ||
2559 | } | ||
2560 | |||
2506 | #else | 2561 | #else |
2507 | static inline int tsk_is_polling(struct task_struct *p) { return 0; } | 2562 | static inline int tsk_is_polling(struct task_struct *p) { return 0; } |
2508 | static inline void current_set_polling(void) { } | 2563 | static inline void __current_set_polling(void) { } |
2509 | static inline void current_clr_polling(void) { } | 2564 | static inline void __current_clr_polling(void) { } |
2565 | |||
2566 | static inline bool __must_check current_set_polling_and_test(void) | ||
2567 | { | ||
2568 | return unlikely(tif_need_resched()); | ||
2569 | } | ||
2570 | static inline bool __must_check current_clr_polling_and_test(void) | ||
2571 | { | ||
2572 | return unlikely(tif_need_resched()); | ||
2573 | } | ||
2510 | #endif | 2574 | #endif |
2511 | 2575 | ||
2512 | /* | 2576 | /* |
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index a629e4b23217..fddbe2023a5d 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h | |||
@@ -118,6 +118,8 @@ static inline __deprecated void set_need_resched(void) | |||
118 | */ | 118 | */ |
119 | } | 119 | } |
120 | 120 | ||
121 | #define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) | ||
122 | |||
121 | #if defined TIF_RESTORE_SIGMASK && !defined HAVE_SET_RESTORE_SIGMASK | 123 | #if defined TIF_RESTORE_SIGMASK && !defined HAVE_SET_RESTORE_SIGMASK |
122 | /* | 124 | /* |
123 | * An arch can define its own version of set_restore_sigmask() to get the | 125 | * An arch can define its own version of set_restore_sigmask() to get the |
diff --git a/kernel/cpu/idle.c b/kernel/cpu/idle.c index e695c0a0bcb5..c261409500e4 100644 --- a/kernel/cpu/idle.c +++ b/kernel/cpu/idle.c | |||
@@ -44,7 +44,7 @@ static inline int cpu_idle_poll(void) | |||
44 | rcu_idle_enter(); | 44 | rcu_idle_enter(); |
45 | trace_cpu_idle_rcuidle(0, smp_processor_id()); | 45 | trace_cpu_idle_rcuidle(0, smp_processor_id()); |
46 | local_irq_enable(); | 46 | local_irq_enable(); |
47 | while (!need_resched()) | 47 | while (!tif_need_resched()) |
48 | cpu_relax(); | 48 | cpu_relax(); |
49 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); | 49 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); |
50 | rcu_idle_exit(); | 50 | rcu_idle_exit(); |
@@ -92,8 +92,7 @@ static void cpu_idle_loop(void) | |||
92 | if (cpu_idle_force_poll || tick_check_broadcast_expired()) { | 92 | if (cpu_idle_force_poll || tick_check_broadcast_expired()) { |
93 | cpu_idle_poll(); | 93 | cpu_idle_poll(); |
94 | } else { | 94 | } else { |
95 | current_clr_polling(); | 95 | if (!current_clr_polling_and_test()) { |
96 | if (!need_resched()) { | ||
97 | stop_critical_timings(); | 96 | stop_critical_timings(); |
98 | rcu_idle_enter(); | 97 | rcu_idle_enter(); |
99 | arch_cpu_idle(); | 98 | arch_cpu_idle(); |
@@ -103,7 +102,7 @@ static void cpu_idle_loop(void) | |||
103 | } else { | 102 | } else { |
104 | local_irq_enable(); | 103 | local_irq_enable(); |
105 | } | 104 | } |
106 | current_set_polling(); | 105 | __current_set_polling(); |
107 | } | 106 | } |
108 | arch_cpu_idle_exit(); | 107 | arch_cpu_idle_exit(); |
109 | } | 108 | } |
@@ -129,7 +128,7 @@ void cpu_startup_entry(enum cpuhp_state state) | |||
129 | */ | 128 | */ |
130 | boot_init_stack_canary(); | 129 | boot_init_stack_canary(); |
131 | #endif | 130 | #endif |
132 | current_set_polling(); | 131 | __current_set_polling(); |
133 | arch_cpu_idle_prepare(); | 132 | arch_cpu_idle_prepare(); |
134 | cpu_idle_loop(); | 133 | cpu_idle_loop(); |
135 | } | 134 | } |