diff options
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 6 | ||||
-rw-r--r-- | kernel/sched/idle.c | 6 | ||||
-rw-r--r-- | kernel/sched/sched.h | 30 |
3 files changed, 42 insertions, 0 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index d31e04ca8703..125150dc6e81 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -225,6 +225,12 @@ void cpuidle_uninstall_idle_handler(void) | |||
225 | initialized = 0; | 225 | initialized = 0; |
226 | wake_up_all_idle_cpus(); | 226 | wake_up_all_idle_cpus(); |
227 | } | 227 | } |
228 | |||
229 | /* | ||
230 | * Make sure external observers (such as the scheduler) | ||
231 | * are done looking at pointed idle states. | ||
232 | */ | ||
233 | synchronize_rcu(); | ||
228 | } | 234 | } |
229 | 235 | ||
230 | /** | 236 | /** |
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 11e7bc434f43..c47fce75e666 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c | |||
@@ -147,6 +147,9 @@ use_default: | |||
147 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu)) | 147 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu)) |
148 | goto use_default; | 148 | goto use_default; |
149 | 149 | ||
150 | /* Take note of the planned idle state. */ | ||
151 | idle_set_state(this_rq(), &drv->states[next_state]); | ||
152 | |||
150 | /* | 153 | /* |
151 | * Enter the idle state previously returned by the governor decision. | 154 | * Enter the idle state previously returned by the governor decision. |
152 | * This function will block until an interrupt occurs and will take | 155 | * This function will block until an interrupt occurs and will take |
@@ -154,6 +157,9 @@ use_default: | |||
154 | */ | 157 | */ |
155 | entered_state = cpuidle_enter(drv, dev, next_state); | 158 | entered_state = cpuidle_enter(drv, dev, next_state); |
156 | 159 | ||
160 | /* The cpu is no longer idle or about to enter idle. */ | ||
161 | idle_set_state(this_rq(), NULL); | ||
162 | |||
157 | if (broadcast) | 163 | if (broadcast) |
158 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); | 164 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); |
159 | 165 | ||
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 76f3a38a401c..16e1ca9cb7e8 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "cpuacct.h" | 14 | #include "cpuacct.h" |
15 | 15 | ||
16 | struct rq; | 16 | struct rq; |
17 | struct cpuidle_state; | ||
17 | 18 | ||
18 | /* task_struct::on_rq states: */ | 19 | /* task_struct::on_rq states: */ |
19 | #define TASK_ON_RQ_QUEUED 1 | 20 | #define TASK_ON_RQ_QUEUED 1 |
@@ -643,6 +644,11 @@ struct rq { | |||
643 | #ifdef CONFIG_SMP | 644 | #ifdef CONFIG_SMP |
644 | struct llist_head wake_list; | 645 | struct llist_head wake_list; |
645 | #endif | 646 | #endif |
647 | |||
648 | #ifdef CONFIG_CPU_IDLE | ||
649 | /* Must be inspected within a rcu lock section */ | ||
650 | struct cpuidle_state *idle_state; | ||
651 | #endif | ||
646 | }; | 652 | }; |
647 | 653 | ||
648 | static inline int cpu_of(struct rq *rq) | 654 | static inline int cpu_of(struct rq *rq) |
@@ -1196,6 +1202,30 @@ static inline void idle_exit_fair(struct rq *rq) { } | |||
1196 | 1202 | ||
1197 | #endif | 1203 | #endif |
1198 | 1204 | ||
1205 | #ifdef CONFIG_CPU_IDLE | ||
1206 | static inline void idle_set_state(struct rq *rq, | ||
1207 | struct cpuidle_state *idle_state) | ||
1208 | { | ||
1209 | rq->idle_state = idle_state; | ||
1210 | } | ||
1211 | |||
1212 | static inline struct cpuidle_state *idle_get_state(struct rq *rq) | ||
1213 | { | ||
1214 | WARN_ON(!rcu_read_lock_held()); | ||
1215 | return rq->idle_state; | ||
1216 | } | ||
1217 | #else | ||
1218 | static inline void idle_set_state(struct rq *rq, | ||
1219 | struct cpuidle_state *idle_state) | ||
1220 | { | ||
1221 | } | ||
1222 | |||
1223 | static inline struct cpuidle_state *idle_get_state(struct rq *rq) | ||
1224 | { | ||
1225 | return NULL; | ||
1226 | } | ||
1227 | #endif | ||
1228 | |||
1199 | extern void sysrq_sched_debug_show(void); | 1229 | extern void sysrq_sched_debug_show(void); |
1200 | extern void sched_init_granularity(void); | 1230 | extern void sched_init_granularity(void); |
1201 | extern void update_max_interval(void); | 1231 | extern void update_max_interval(void); |