aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/cpuidle.c49
-rw-r--r--include/linux/cpuidle.h2
-rw-r--r--kernel/sched/idle.c56
3 files changed, 56 insertions, 51 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 1506d69b3f0f..166a7322a2b6 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -173,55 +173,6 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index)
173} 173}
174 174
175/** 175/**
176 * cpuidle_idle_call - the main idle loop
177 *
178 * NOTE: no locks or semaphores should be used here
179 * return non-zero on failure
180 */
181int cpuidle_idle_call(void)
182{
183 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
184 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
185 int next_state, entered_state, ret;
186 bool broadcast;
187
188 ret = cpuidle_enabled(drv, dev);
189 if (ret < 0)
190 return ret;
191
192 /* ask the governor for the next state */
193 next_state = cpuidle_select(drv, dev);
194
195 if (need_resched()) {
196 dev->last_residency = 0;
197 /* give the governor an opportunity to reflect on the outcome */
198 cpuidle_reflect(dev, next_state);
199 local_irq_enable();
200 return 0;
201 }
202
203 broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP);
204
205 if (broadcast &&
206 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu))
207 return -EBUSY;
208
209 trace_cpu_idle_rcuidle(next_state, dev->cpu);
210
211 entered_state = cpuidle_enter(drv, dev, next_state);
212
213 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
214
215 if (broadcast)
216 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
217
218 /* give the governor an opportunity to reflect on the outcome */
219 cpuidle_reflect(dev, entered_state);
220
221 return 0;
222}
223
224/**
225 * cpuidle_install_idle_handler - installs the cpuidle idle loop handler 176 * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
226 */ 177 */
227void cpuidle_install_idle_handler(void) 178void cpuidle_install_idle_handler(void)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index accc2dd72049..8d97962d6d64 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -128,7 +128,6 @@ extern int cpuidle_enter(struct cpuidle_driver *drv,
128 struct cpuidle_device *dev, int index); 128 struct cpuidle_device *dev, int index);
129extern void cpuidle_reflect(struct cpuidle_device *dev, int index); 129extern void cpuidle_reflect(struct cpuidle_device *dev, int index);
130 130
131extern int cpuidle_idle_call(void);
132extern int cpuidle_register_driver(struct cpuidle_driver *drv); 131extern int cpuidle_register_driver(struct cpuidle_driver *drv);
133extern struct cpuidle_driver *cpuidle_get_driver(void); 132extern struct cpuidle_driver *cpuidle_get_driver(void);
134extern struct cpuidle_driver *cpuidle_driver_ref(void); 133extern struct cpuidle_driver *cpuidle_driver_ref(void);
@@ -160,7 +159,6 @@ static inline int cpuidle_enter(struct cpuidle_driver *drv,
160 struct cpuidle_device *dev, int index) 159 struct cpuidle_device *dev, int index)
161{return -ENODEV; } 160{return -ENODEV; }
162static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { } 161static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { }
163static inline int cpuidle_idle_call(void) { return -ENODEV; }
164static inline int cpuidle_register_driver(struct cpuidle_driver *drv) 162static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
165{return -ENODEV; } 163{return -ENODEV; }
166static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; } 164static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index b7976a127178..d5aaf5eb4531 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -63,6 +63,62 @@ void __weak arch_cpu_idle(void)
63 local_irq_enable(); 63 local_irq_enable();
64} 64}
65 65
66#ifdef CONFIG_CPU_IDLE
67/**
68 * cpuidle_idle_call - the main idle function
69 *
70 * NOTE: no locks or semaphores should be used here
71 * return non-zero on failure
72 */
73static int cpuidle_idle_call(void)
74{
75 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
76 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
77 int next_state, entered_state, ret;
78 bool broadcast;
79
80 ret = cpuidle_enabled(drv, dev);
81 if (ret < 0)
82 return ret;
83
84 /* ask the governor for the next state */
85 next_state = cpuidle_select(drv, dev);
86
87 if (need_resched()) {
88 dev->last_residency = 0;
89 /* give the governor an opportunity to reflect on the outcome */
90 cpuidle_reflect(dev, next_state);
91 local_irq_enable();
92 return 0;
93 }
94
95 broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP);
96
97 if (broadcast &&
98 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu))
99 return -EBUSY;
100
101 trace_cpu_idle_rcuidle(next_state, dev->cpu);
102
103 entered_state = cpuidle_enter(drv, dev, next_state);
104
105 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
106
107 if (broadcast)
108 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
109
110 /* give the governor an opportunity to reflect on the outcome */
111 cpuidle_reflect(dev, entered_state);
112
113 return 0;
114}
115#else
116static inline int cpuidle_idle_call(void)
117{
118 return -ENODEV;
119}
120#endif
121
66/* 122/*
67 * Generic idle loop implementation 123 * Generic idle loop implementation
68 */ 124 */