diff options
-rw-r--r-- | kernel/sched/idle.c | 78 |
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); | ||
116 | out: | ||
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 | ||