aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/sched/idle.c78
1 files changed, 44 insertions, 34 deletions
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index dc8a2466418f..cc7a6f3801ff 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -76,44 +76,59 @@ static int cpuidle_idle_call(void)
76 int next_state, entered_state, ret; 76 int next_state, entered_state, ret;
77 bool broadcast; 77 bool broadcast;
78 78
79 if (current_clr_polling_and_test()) {
80 local_irq_enable();
81 __current_set_polling();
82 return 0;
83 }
84
79 stop_critical_timings(); 85 stop_critical_timings();
80 rcu_idle_enter(); 86 rcu_idle_enter();
81 87
82 ret = cpuidle_enabled(drv, dev); 88 ret = cpuidle_enabled(drv, dev);
83 if (ret < 0) {
84 arch_cpu_idle();
85 goto out;
86 }
87 89
88 /* ask the governor for the next state */ 90 if (!ret) {
89 next_state = cpuidle_select(drv, dev); 91 /* ask the governor for the next state */
92 next_state = cpuidle_select(drv, dev);
90 93
91 if (need_resched()) { 94 if (current_clr_polling_and_test()) {
92 dev->last_residency = 0; 95 dev->last_residency = 0;
93 /* give the governor an opportunity to reflect on the outcome */ 96 entered_state = next_state;
94 cpuidle_reflect(dev, next_state); 97 local_irq_enable();
95 local_irq_enable(); 98 } else {
96 goto out; 99 broadcast = !!(drv->states[next_state].flags &
97 } 100 CPUIDLE_FLAG_TIMER_STOP);
101
102 if (broadcast)
103 ret = clockevents_notify(
104 CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
105 &dev->cpu);
98 106
99 broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP); 107 if (!ret) {
108 trace_cpu_idle_rcuidle(next_state, dev->cpu);
100 109
101 if (broadcast && 110 entered_state = cpuidle_enter(drv, dev,
102 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu)) 111 next_state);
103 return -EBUSY;
104 112
105 trace_cpu_idle_rcuidle(next_state, dev->cpu); 113 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT,
114 dev->cpu);
106 115
107 entered_state = cpuidle_enter(drv, dev, next_state); 116 if (broadcast)
117 clockevents_notify(
118 CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
119 &dev->cpu);
108 120
109 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); 121 /* give the governor an opportunity to reflect on the outcome */
122 cpuidle_reflect(dev, entered_state);
123 }
124 }
125 }
126
127 if (ret)
128 arch_cpu_idle();
110 129
111 if (broadcast) 130 __current_set_polling();
112 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
113 131
114 /* give the governor an opportunity to reflect on the outcome */
115 cpuidle_reflect(dev, entered_state);
116out:
117 if (WARN_ON_ONCE(irqs_disabled())) 132 if (WARN_ON_ONCE(irqs_disabled()))
118 local_irq_enable(); 133 local_irq_enable();
119 134
@@ -150,16 +165,11 @@ static void cpu_idle_loop(void)
150 * know that the IPI is going to arrive right 165 * know that the IPI is going to arrive right
151 * away 166 * away
152 */ 167 */
153 if (cpu_idle_force_poll || tick_check_broadcast_expired()) { 168 if (cpu_idle_force_poll || tick_check_broadcast_expired())
154 cpu_idle_poll(); 169 cpu_idle_poll();
155 } else { 170 else
156 if (!current_clr_polling_and_test()) { 171 cpuidle_idle_call();
157 cpuidle_idle_call(); 172
158 } else {
159 local_irq_enable();
160 }
161 __current_set_polling();
162 }
163 arch_cpu_idle_exit(); 173 arch_cpu_idle_exit();
164 } 174 }
165 175