.. | .. |
---|
17 | 17 | #include <linux/pm_qos.h> |
---|
18 | 18 | #include <linux/cpu.h> |
---|
19 | 19 | #include <linux/cpuidle.h> |
---|
| 20 | +#include <linux/irq_pipeline.h> |
---|
20 | 21 | #include <linux/ktime.h> |
---|
21 | 22 | #include <linux/hrtimer.h> |
---|
22 | 23 | #include <linux/module.h> |
---|
.. | .. |
---|
219 | 220 | broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP); |
---|
220 | 221 | |
---|
221 | 222 | /* |
---|
| 223 | + * A companion core running on the oob stage of the IRQ |
---|
| 224 | + * pipeline may deny switching to a deeper C-state. If so, |
---|
| 225 | + * call the default idle routine instead. If the core cannot |
---|
| 226 | + * bear with the latency induced by the default idling |
---|
| 227 | + * operation, then CPUIDLE is not usable and should be |
---|
| 228 | + * disabled at build time. The in-band stage is currently |
---|
| 229 | + * stalled, hard irqs are on. irq_cpuidle_enter() leaves us |
---|
| 230 | + * stalled but returns with hard irqs off so that no event may |
---|
| 231 | + * sneak in until we actually go idle. |
---|
| 232 | + */ |
---|
| 233 | + if (!irq_cpuidle_enter(dev, target_state)) { |
---|
| 234 | + default_idle_call(); |
---|
| 235 | + return -EBUSY; |
---|
| 236 | + } |
---|
| 237 | + |
---|
| 238 | + /* |
---|
222 | 239 | * Tell the time framework to switch to a broadcast timer because our |
---|
223 | 240 | * local timer will be shut down. If a local timer is used from another |
---|
224 | 241 | * CPU as a broadcast timer, this call may fail if it is not available. |
---|
.. | .. |
---|
247 | 264 | if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) |
---|
248 | 265 | rcu_idle_enter(); |
---|
249 | 266 | entered_state = target_state->enter(dev, drv, index); |
---|
| 267 | + hard_cond_local_irq_enable(); |
---|
250 | 268 | if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) |
---|
251 | 269 | rcu_idle_exit(); |
---|
252 | 270 | start_critical_timings(); |
---|