aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/cpuidle.c6
-rw-r--r--kernel/sched/idle.c6
-rw-r--r--kernel/sched/sched.h30
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
16struct rq; 16struct rq;
17struct 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
648static inline int cpu_of(struct rq *rq) 654static 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
1206static inline void idle_set_state(struct rq *rq,
1207 struct cpuidle_state *idle_state)
1208{
1209 rq->idle_state = idle_state;
1210}
1211
1212static 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
1218static inline void idle_set_state(struct rq *rq,
1219 struct cpuidle_state *idle_state)
1220{
1221}
1222
1223static inline struct cpuidle_state *idle_get_state(struct rq *rq)
1224{
1225 return NULL;
1226}
1227#endif
1228
1199extern void sysrq_sched_debug_show(void); 1229extern void sysrq_sched_debug_show(void);
1200extern void sched_init_granularity(void); 1230extern void sched_init_granularity(void);
1201extern void update_max_interval(void); 1231extern void update_max_interval(void);