aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/cpuidle.h2
-rw-r--r--kernel/sched/idle.c33
2 files changed, 17 insertions, 18 deletions
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 8d97962d6d64..b0238cba440b 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -180,6 +180,8 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
180{return -ENODEV; } 180{return -ENODEV; }
181static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } 181static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
182static inline int cpuidle_play_dead(void) {return -ENODEV; } 182static inline int cpuidle_play_dead(void) {return -ENODEV; }
183static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
184 struct cpuidle_device *dev) {return NULL; }
183#endif 185#endif
184 186
185#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED 187#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index d5aaf5eb4531..dc8a2466418f 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -63,7 +63,6 @@ void __weak arch_cpu_idle(void)
63 local_irq_enable(); 63 local_irq_enable();
64} 64}
65 65
66#ifdef CONFIG_CPU_IDLE
67/** 66/**
68 * cpuidle_idle_call - the main idle function 67 * cpuidle_idle_call - the main idle function
69 * 68 *
@@ -77,9 +76,14 @@ static int cpuidle_idle_call(void)
77 int next_state, entered_state, ret; 76 int next_state, entered_state, ret;
78 bool broadcast; 77 bool broadcast;
79 78
79 stop_critical_timings();
80 rcu_idle_enter();
81
80 ret = cpuidle_enabled(drv, dev); 82 ret = cpuidle_enabled(drv, dev);
81 if (ret < 0) 83 if (ret < 0) {
82 return ret; 84 arch_cpu_idle();
85 goto out;
86 }
83 87
84 /* ask the governor for the next state */ 88 /* ask the governor for the next state */
85 next_state = cpuidle_select(drv, dev); 89 next_state = cpuidle_select(drv, dev);
@@ -89,7 +93,7 @@ static int cpuidle_idle_call(void)
89 /* give the governor an opportunity to reflect on the outcome */ 93 /* give the governor an opportunity to reflect on the outcome */
90 cpuidle_reflect(dev, next_state); 94 cpuidle_reflect(dev, next_state);
91 local_irq_enable(); 95 local_irq_enable();
92 return 0; 96 goto out;
93 } 97 }
94 98
95 broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP); 99 broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP);
@@ -109,15 +113,15 @@ static int cpuidle_idle_call(void)
109 113
110 /* give the governor an opportunity to reflect on the outcome */ 114 /* give the governor an opportunity to reflect on the outcome */
111 cpuidle_reflect(dev, entered_state); 115 cpuidle_reflect(dev, entered_state);
116out:
117 if (WARN_ON_ONCE(irqs_disabled()))
118 local_irq_enable();
119
120 rcu_idle_exit();
121 start_critical_timings();
112 122
113 return 0; 123 return 0;
114} 124}
115#else
116static inline int cpuidle_idle_call(void)
117{
118 return -ENODEV;
119}
120#endif
121 125
122/* 126/*
123 * Generic idle loop implementation 127 * Generic idle loop implementation
@@ -150,14 +154,7 @@ static void cpu_idle_loop(void)
150 cpu_idle_poll(); 154 cpu_idle_poll();
151 } else { 155 } else {
152 if (!current_clr_polling_and_test()) { 156 if (!current_clr_polling_and_test()) {
153 stop_critical_timings(); 157 cpuidle_idle_call();
154 rcu_idle_enter();
155 if (cpuidle_idle_call())
156 arch_cpu_idle();
157 if (WARN_ON_ONCE(irqs_disabled()))
158 local_irq_enable();
159 rcu_idle_exit();
160 start_critical_timings();
161 } else { 158 } else {
162 local_irq_enable(); 159 local_irq_enable();
163 } 160 }