diff options
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r-- | drivers/idle/intel_idle.c | 296 |
1 files changed, 176 insertions, 120 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index b0f6b4c8ee14..1a38dd7dfe4e 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -56,7 +56,6 @@ | |||
56 | #include <linux/kernel.h> | 56 | #include <linux/kernel.h> |
57 | #include <linux/cpuidle.h> | 57 | #include <linux/cpuidle.h> |
58 | #include <linux/clockchips.h> | 58 | #include <linux/clockchips.h> |
59 | #include <linux/hrtimer.h> /* ktime_get_real() */ | ||
60 | #include <trace/events/power.h> | 59 | #include <trace/events/power.h> |
61 | #include <linux/sched.h> | 60 | #include <linux/sched.h> |
62 | #include <linux/notifier.h> | 61 | #include <linux/notifier.h> |
@@ -72,9 +71,10 @@ | |||
72 | static struct cpuidle_driver intel_idle_driver = { | 71 | static struct cpuidle_driver intel_idle_driver = { |
73 | .name = "intel_idle", | 72 | .name = "intel_idle", |
74 | .owner = THIS_MODULE, | 73 | .owner = THIS_MODULE, |
74 | .en_core_tk_irqen = 1, | ||
75 | }; | 75 | }; |
76 | /* intel_idle.max_cstate=0 disables driver */ | 76 | /* intel_idle.max_cstate=0 disables driver */ |
77 | static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1; | 77 | static int max_cstate = CPUIDLE_STATE_MAX - 1; |
78 | 78 | ||
79 | static unsigned int mwait_substates; | 79 | static unsigned int mwait_substates; |
80 | 80 | ||
@@ -90,6 +90,7 @@ struct idle_cpu { | |||
90 | * Indicate which enable bits to clear here. | 90 | * Indicate which enable bits to clear here. |
91 | */ | 91 | */ |
92 | unsigned long auto_demotion_disable_flags; | 92 | unsigned long auto_demotion_disable_flags; |
93 | bool disable_promotion_to_c1e; | ||
93 | }; | 94 | }; |
94 | 95 | ||
95 | static const struct idle_cpu *icpu; | 96 | static const struct idle_cpu *icpu; |
@@ -109,162 +110,206 @@ static struct cpuidle_state *cpuidle_state_table; | |||
109 | #define CPUIDLE_FLAG_TLB_FLUSHED 0x10000 | 110 | #define CPUIDLE_FLAG_TLB_FLUSHED 0x10000 |
110 | 111 | ||
111 | /* | 112 | /* |
113 | * MWAIT takes an 8-bit "hint" in EAX "suggesting" | ||
114 | * the C-state (top nibble) and sub-state (bottom nibble) | ||
115 | * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc. | ||
116 | * | ||
117 | * We store the hint at the top of our "flags" for each state. | ||
118 | */ | ||
119 | #define flg2MWAIT(flags) (((flags) >> 24) & 0xFF) | ||
120 | #define MWAIT2flg(eax) ((eax & 0xFF) << 24) | ||
121 | |||
122 | /* | ||
112 | * States are indexed by the cstate number, | 123 | * States are indexed by the cstate number, |
113 | * which is also the index into the MWAIT hint array. | 124 | * which is also the index into the MWAIT hint array. |
114 | * Thus C0 is a dummy. | 125 | * Thus C0 is a dummy. |
115 | */ | 126 | */ |
116 | static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { | 127 | static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { |
117 | { /* MWAIT C0 */ }, | 128 | { |
118 | { /* MWAIT C1 */ | ||
119 | .name = "C1-NHM", | 129 | .name = "C1-NHM", |
120 | .desc = "MWAIT 0x00", | 130 | .desc = "MWAIT 0x00", |
121 | .flags = CPUIDLE_FLAG_TIME_VALID, | 131 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
122 | .exit_latency = 3, | 132 | .exit_latency = 3, |
123 | .target_residency = 6, | 133 | .target_residency = 6, |
124 | .enter = &intel_idle }, | 134 | .enter = &intel_idle }, |
125 | { /* MWAIT C2 */ | 135 | { |
136 | .name = "C1E-NHM", | ||
137 | .desc = "MWAIT 0x01", | ||
138 | .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, | ||
139 | .exit_latency = 10, | ||
140 | .target_residency = 20, | ||
141 | .enter = &intel_idle }, | ||
142 | { | ||
126 | .name = "C3-NHM", | 143 | .name = "C3-NHM", |
127 | .desc = "MWAIT 0x10", | 144 | .desc = "MWAIT 0x10", |
128 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 145 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
129 | .exit_latency = 20, | 146 | .exit_latency = 20, |
130 | .target_residency = 80, | 147 | .target_residency = 80, |
131 | .enter = &intel_idle }, | 148 | .enter = &intel_idle }, |
132 | { /* MWAIT C3 */ | 149 | { |
133 | .name = "C6-NHM", | 150 | .name = "C6-NHM", |
134 | .desc = "MWAIT 0x20", | 151 | .desc = "MWAIT 0x20", |
135 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 152 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
136 | .exit_latency = 200, | 153 | .exit_latency = 200, |
137 | .target_residency = 800, | 154 | .target_residency = 800, |
138 | .enter = &intel_idle }, | 155 | .enter = &intel_idle }, |
156 | { | ||
157 | .enter = NULL } | ||
139 | }; | 158 | }; |
140 | 159 | ||
141 | static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { | 160 | static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { |
142 | { /* MWAIT C0 */ }, | 161 | { |
143 | { /* MWAIT C1 */ | ||
144 | .name = "C1-SNB", | 162 | .name = "C1-SNB", |
145 | .desc = "MWAIT 0x00", | 163 | .desc = "MWAIT 0x00", |
146 | .flags = CPUIDLE_FLAG_TIME_VALID, | 164 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
147 | .exit_latency = 1, | 165 | .exit_latency = 2, |
148 | .target_residency = 1, | 166 | .target_residency = 2, |
167 | .enter = &intel_idle }, | ||
168 | { | ||
169 | .name = "C1E-SNB", | ||
170 | .desc = "MWAIT 0x01", | ||
171 | .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, | ||
172 | .exit_latency = 10, | ||
173 | .target_residency = 20, | ||
149 | .enter = &intel_idle }, | 174 | .enter = &intel_idle }, |
150 | { /* MWAIT C2 */ | 175 | { |
151 | .name = "C3-SNB", | 176 | .name = "C3-SNB", |
152 | .desc = "MWAIT 0x10", | 177 | .desc = "MWAIT 0x10", |
153 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 178 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
154 | .exit_latency = 80, | 179 | .exit_latency = 80, |
155 | .target_residency = 211, | 180 | .target_residency = 211, |
156 | .enter = &intel_idle }, | 181 | .enter = &intel_idle }, |
157 | { /* MWAIT C3 */ | 182 | { |
158 | .name = "C6-SNB", | 183 | .name = "C6-SNB", |
159 | .desc = "MWAIT 0x20", | 184 | .desc = "MWAIT 0x20", |
160 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 185 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
161 | .exit_latency = 104, | 186 | .exit_latency = 104, |
162 | .target_residency = 345, | 187 | .target_residency = 345, |
163 | .enter = &intel_idle }, | 188 | .enter = &intel_idle }, |
164 | { /* MWAIT C4 */ | 189 | { |
165 | .name = "C7-SNB", | 190 | .name = "C7-SNB", |
166 | .desc = "MWAIT 0x30", | 191 | .desc = "MWAIT 0x30", |
167 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 192 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
168 | .exit_latency = 109, | 193 | .exit_latency = 109, |
169 | .target_residency = 345, | 194 | .target_residency = 345, |
170 | .enter = &intel_idle }, | 195 | .enter = &intel_idle }, |
196 | { | ||
197 | .enter = NULL } | ||
171 | }; | 198 | }; |
172 | 199 | ||
173 | static struct cpuidle_state ivb_cstates[MWAIT_MAX_NUM_CSTATES] = { | 200 | static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { |
174 | { /* MWAIT C0 */ }, | 201 | { |
175 | { /* MWAIT C1 */ | ||
176 | .name = "C1-IVB", | 202 | .name = "C1-IVB", |
177 | .desc = "MWAIT 0x00", | 203 | .desc = "MWAIT 0x00", |
178 | .flags = CPUIDLE_FLAG_TIME_VALID, | 204 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
179 | .exit_latency = 1, | 205 | .exit_latency = 1, |
180 | .target_residency = 1, | 206 | .target_residency = 1, |
181 | .enter = &intel_idle }, | 207 | .enter = &intel_idle }, |
182 | { /* MWAIT C2 */ | 208 | { |
209 | .name = "C1E-IVB", | ||
210 | .desc = "MWAIT 0x01", | ||
211 | .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, | ||
212 | .exit_latency = 10, | ||
213 | .target_residency = 20, | ||
214 | .enter = &intel_idle }, | ||
215 | { | ||
183 | .name = "C3-IVB", | 216 | .name = "C3-IVB", |
184 | .desc = "MWAIT 0x10", | 217 | .desc = "MWAIT 0x10", |
185 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 218 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
186 | .exit_latency = 59, | 219 | .exit_latency = 59, |
187 | .target_residency = 156, | 220 | .target_residency = 156, |
188 | .enter = &intel_idle }, | 221 | .enter = &intel_idle }, |
189 | { /* MWAIT C3 */ | 222 | { |
190 | .name = "C6-IVB", | 223 | .name = "C6-IVB", |
191 | .desc = "MWAIT 0x20", | 224 | .desc = "MWAIT 0x20", |
192 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 225 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
193 | .exit_latency = 80, | 226 | .exit_latency = 80, |
194 | .target_residency = 300, | 227 | .target_residency = 300, |
195 | .enter = &intel_idle }, | 228 | .enter = &intel_idle }, |
196 | { /* MWAIT C4 */ | 229 | { |
197 | .name = "C7-IVB", | 230 | .name = "C7-IVB", |
198 | .desc = "MWAIT 0x30", | 231 | .desc = "MWAIT 0x30", |
199 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 232 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
200 | .exit_latency = 87, | 233 | .exit_latency = 87, |
201 | .target_residency = 300, | 234 | .target_residency = 300, |
202 | .enter = &intel_idle }, | 235 | .enter = &intel_idle }, |
236 | { | ||
237 | .enter = NULL } | ||
203 | }; | 238 | }; |
204 | 239 | ||
205 | static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | 240 | static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { |
206 | { /* MWAIT C0 */ }, | 241 | { |
207 | { /* MWAIT C1 */ | 242 | .name = "C1-HSW", |
208 | .name = "C1-ATM", | ||
209 | .desc = "MWAIT 0x00", | 243 | .desc = "MWAIT 0x00", |
210 | .flags = CPUIDLE_FLAG_TIME_VALID, | 244 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
211 | .exit_latency = 1, | 245 | .exit_latency = 2, |
212 | .target_residency = 4, | 246 | .target_residency = 2, |
247 | .enter = &intel_idle }, | ||
248 | { | ||
249 | .name = "C1E-HSW", | ||
250 | .desc = "MWAIT 0x01", | ||
251 | .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, | ||
252 | .exit_latency = 10, | ||
253 | .target_residency = 20, | ||
254 | .enter = &intel_idle }, | ||
255 | { | ||
256 | .name = "C3-HSW", | ||
257 | .desc = "MWAIT 0x10", | ||
258 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | ||
259 | .exit_latency = 33, | ||
260 | .target_residency = 100, | ||
261 | .enter = &intel_idle }, | ||
262 | { | ||
263 | .name = "C6-HSW", | ||
264 | .desc = "MWAIT 0x20", | ||
265 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | ||
266 | .exit_latency = 133, | ||
267 | .target_residency = 400, | ||
213 | .enter = &intel_idle }, | 268 | .enter = &intel_idle }, |
214 | { /* MWAIT C2 */ | 269 | { |
270 | .name = "C7s-HSW", | ||
271 | .desc = "MWAIT 0x32", | ||
272 | .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | ||
273 | .exit_latency = 166, | ||
274 | .target_residency = 500, | ||
275 | .enter = &intel_idle }, | ||
276 | { | ||
277 | .enter = NULL } | ||
278 | }; | ||
279 | |||
280 | static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { | ||
281 | { | ||
282 | .name = "C1E-ATM", | ||
283 | .desc = "MWAIT 0x00", | ||
284 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, | ||
285 | .exit_latency = 10, | ||
286 | .target_residency = 20, | ||
287 | .enter = &intel_idle }, | ||
288 | { | ||
215 | .name = "C2-ATM", | 289 | .name = "C2-ATM", |
216 | .desc = "MWAIT 0x10", | 290 | .desc = "MWAIT 0x10", |
217 | .flags = CPUIDLE_FLAG_TIME_VALID, | 291 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID, |
218 | .exit_latency = 20, | 292 | .exit_latency = 20, |
219 | .target_residency = 80, | 293 | .target_residency = 80, |
220 | .enter = &intel_idle }, | 294 | .enter = &intel_idle }, |
221 | { /* MWAIT C3 */ }, | 295 | { |
222 | { /* MWAIT C4 */ | ||
223 | .name = "C4-ATM", | 296 | .name = "C4-ATM", |
224 | .desc = "MWAIT 0x30", | 297 | .desc = "MWAIT 0x30", |
225 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 298 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
226 | .exit_latency = 100, | 299 | .exit_latency = 100, |
227 | .target_residency = 400, | 300 | .target_residency = 400, |
228 | .enter = &intel_idle }, | 301 | .enter = &intel_idle }, |
229 | { /* MWAIT C5 */ }, | 302 | { |
230 | { /* MWAIT C6 */ | ||
231 | .name = "C6-ATM", | 303 | .name = "C6-ATM", |
232 | .desc = "MWAIT 0x52", | 304 | .desc = "MWAIT 0x52", |
233 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 305 | .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
234 | .exit_latency = 140, | 306 | .exit_latency = 140, |
235 | .target_residency = 560, | 307 | .target_residency = 560, |
236 | .enter = &intel_idle }, | 308 | .enter = &intel_idle }, |
309 | { | ||
310 | .enter = NULL } | ||
237 | }; | 311 | }; |
238 | 312 | ||
239 | static long get_driver_data(int cstate) | ||
240 | { | ||
241 | int driver_data; | ||
242 | switch (cstate) { | ||
243 | |||
244 | case 1: /* MWAIT C1 */ | ||
245 | driver_data = 0x00; | ||
246 | break; | ||
247 | case 2: /* MWAIT C2 */ | ||
248 | driver_data = 0x10; | ||
249 | break; | ||
250 | case 3: /* MWAIT C3 */ | ||
251 | driver_data = 0x20; | ||
252 | break; | ||
253 | case 4: /* MWAIT C4 */ | ||
254 | driver_data = 0x30; | ||
255 | break; | ||
256 | case 5: /* MWAIT C5 */ | ||
257 | driver_data = 0x40; | ||
258 | break; | ||
259 | case 6: /* MWAIT C6 */ | ||
260 | driver_data = 0x52; | ||
261 | break; | ||
262 | default: | ||
263 | driver_data = 0x00; | ||
264 | } | ||
265 | return driver_data; | ||
266 | } | ||
267 | |||
268 | /** | 313 | /** |
269 | * intel_idle | 314 | * intel_idle |
270 | * @dev: cpuidle_device | 315 | * @dev: cpuidle_device |
@@ -278,11 +323,8 @@ static int intel_idle(struct cpuidle_device *dev, | |||
278 | { | 323 | { |
279 | unsigned long ecx = 1; /* break on interrupt flag */ | 324 | unsigned long ecx = 1; /* break on interrupt flag */ |
280 | struct cpuidle_state *state = &drv->states[index]; | 325 | struct cpuidle_state *state = &drv->states[index]; |
281 | struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; | 326 | unsigned long eax = flg2MWAIT(state->flags); |
282 | unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); | ||
283 | unsigned int cstate; | 327 | unsigned int cstate; |
284 | ktime_t kt_before, kt_after; | ||
285 | s64 usec_delta; | ||
286 | int cpu = smp_processor_id(); | 328 | int cpu = smp_processor_id(); |
287 | 329 | ||
288 | cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; | 330 | cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; |
@@ -297,8 +339,6 @@ static int intel_idle(struct cpuidle_device *dev, | |||
297 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 339 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
298 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | 340 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); |
299 | 341 | ||
300 | kt_before = ktime_get_real(); | ||
301 | |||
302 | stop_critical_timings(); | 342 | stop_critical_timings(); |
303 | if (!need_resched()) { | 343 | if (!need_resched()) { |
304 | 344 | ||
@@ -310,17 +350,9 @@ static int intel_idle(struct cpuidle_device *dev, | |||
310 | 350 | ||
311 | start_critical_timings(); | 351 | start_critical_timings(); |
312 | 352 | ||
313 | kt_after = ktime_get_real(); | ||
314 | usec_delta = ktime_to_us(ktime_sub(kt_after, kt_before)); | ||
315 | |||
316 | local_irq_enable(); | ||
317 | |||
318 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 353 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
319 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | 354 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); |
320 | 355 | ||
321 | /* Update cpuidle counters */ | ||
322 | dev->last_residency = (int)usec_delta; | ||
323 | |||
324 | return index; | 356 | return index; |
325 | } | 357 | } |
326 | 358 | ||
@@ -374,10 +406,19 @@ static void auto_demotion_disable(void *dummy) | |||
374 | msr_bits &= ~(icpu->auto_demotion_disable_flags); | 406 | msr_bits &= ~(icpu->auto_demotion_disable_flags); |
375 | wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); | 407 | wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); |
376 | } | 408 | } |
409 | static void c1e_promotion_disable(void *dummy) | ||
410 | { | ||
411 | unsigned long long msr_bits; | ||
412 | |||
413 | rdmsrl(MSR_IA32_POWER_CTL, msr_bits); | ||
414 | msr_bits &= ~0x2; | ||
415 | wrmsrl(MSR_IA32_POWER_CTL, msr_bits); | ||
416 | } | ||
377 | 417 | ||
378 | static const struct idle_cpu idle_cpu_nehalem = { | 418 | static const struct idle_cpu idle_cpu_nehalem = { |
379 | .state_table = nehalem_cstates, | 419 | .state_table = nehalem_cstates, |
380 | .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE, | 420 | .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE, |
421 | .disable_promotion_to_c1e = true, | ||
381 | }; | 422 | }; |
382 | 423 | ||
383 | static const struct idle_cpu idle_cpu_atom = { | 424 | static const struct idle_cpu idle_cpu_atom = { |
@@ -391,10 +432,17 @@ static const struct idle_cpu idle_cpu_lincroft = { | |||
391 | 432 | ||
392 | static const struct idle_cpu idle_cpu_snb = { | 433 | static const struct idle_cpu idle_cpu_snb = { |
393 | .state_table = snb_cstates, | 434 | .state_table = snb_cstates, |
435 | .disable_promotion_to_c1e = true, | ||
394 | }; | 436 | }; |
395 | 437 | ||
396 | static const struct idle_cpu idle_cpu_ivb = { | 438 | static const struct idle_cpu idle_cpu_ivb = { |
397 | .state_table = ivb_cstates, | 439 | .state_table = ivb_cstates, |
440 | .disable_promotion_to_c1e = true, | ||
441 | }; | ||
442 | |||
443 | static const struct idle_cpu idle_cpu_hsw = { | ||
444 | .state_table = hsw_cstates, | ||
445 | .disable_promotion_to_c1e = true, | ||
398 | }; | 446 | }; |
399 | 447 | ||
400 | #define ICPU(model, cpu) \ | 448 | #define ICPU(model, cpu) \ |
@@ -414,6 +462,10 @@ static const struct x86_cpu_id intel_idle_ids[] = { | |||
414 | ICPU(0x2d, idle_cpu_snb), | 462 | ICPU(0x2d, idle_cpu_snb), |
415 | ICPU(0x3a, idle_cpu_ivb), | 463 | ICPU(0x3a, idle_cpu_ivb), |
416 | ICPU(0x3e, idle_cpu_ivb), | 464 | ICPU(0x3e, idle_cpu_ivb), |
465 | ICPU(0x3c, idle_cpu_hsw), | ||
466 | ICPU(0x3f, idle_cpu_hsw), | ||
467 | ICPU(0x45, idle_cpu_hsw), | ||
468 | ICPU(0x46, idle_cpu_hsw), | ||
417 | {} | 469 | {} |
418 | }; | 470 | }; |
419 | MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids); | 471 | MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids); |
@@ -460,8 +512,6 @@ static int intel_idle_probe(void) | |||
460 | else | 512 | else |
461 | on_each_cpu(__setup_broadcast_timer, (void *)true, 1); | 513 | on_each_cpu(__setup_broadcast_timer, (void *)true, 1); |
462 | 514 | ||
463 | register_cpu_notifier(&cpu_hotplug_notifier); | ||
464 | |||
465 | pr_debug(PREFIX "v" INTEL_IDLE_VERSION | 515 | pr_debug(PREFIX "v" INTEL_IDLE_VERSION |
466 | " model 0x%X\n", boot_cpu_data.x86_model); | 516 | " model 0x%X\n", boot_cpu_data.x86_model); |
467 | 517 | ||
@@ -498,32 +548,31 @@ static int intel_idle_cpuidle_driver_init(void) | |||
498 | 548 | ||
499 | drv->state_count = 1; | 549 | drv->state_count = 1; |
500 | 550 | ||
501 | for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { | 551 | for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { |
502 | int num_substates; | 552 | int num_substates, mwait_hint, mwait_cstate, mwait_substate; |
553 | |||
554 | if (cpuidle_state_table[cstate].enter == NULL) | ||
555 | break; | ||
503 | 556 | ||
504 | if (cstate > max_cstate) { | 557 | if (cstate + 1 > max_cstate) { |
505 | printk(PREFIX "max_cstate %d reached\n", | 558 | printk(PREFIX "max_cstate %d reached\n", |
506 | max_cstate); | 559 | max_cstate); |
507 | break; | 560 | break; |
508 | } | 561 | } |
509 | 562 | ||
563 | mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); | ||
564 | mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); | ||
565 | mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); | ||
566 | |||
510 | /* does the state exist in CPUID.MWAIT? */ | 567 | /* does the state exist in CPUID.MWAIT? */ |
511 | num_substates = (mwait_substates >> ((cstate) * 4)) | 568 | num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) |
512 | & MWAIT_SUBSTATE_MASK; | 569 | & MWAIT_SUBSTATE_MASK; |
513 | if (num_substates == 0) | 570 | |
514 | continue; | 571 | /* if sub-state in table is not enumerated by CPUID */ |
515 | /* is the state not enabled? */ | 572 | if ((mwait_substate + 1) > num_substates) |
516 | if (cpuidle_state_table[cstate].enter == NULL) { | ||
517 | /* does the driver not know about the state? */ | ||
518 | if (*cpuidle_state_table[cstate].name == '\0') | ||
519 | pr_debug(PREFIX "unaware of model 0x%x" | ||
520 | " MWAIT %d please" | ||
521 | " contact lenb@kernel.org", | ||
522 | boot_cpu_data.x86_model, cstate); | ||
523 | continue; | 573 | continue; |
524 | } | ||
525 | 574 | ||
526 | if ((cstate > 2) && | 575 | if (((mwait_cstate + 1) > 2) && |
527 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | 576 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) |
528 | mark_tsc_unstable("TSC halts in idle" | 577 | mark_tsc_unstable("TSC halts in idle" |
529 | " states deeper than C2"); | 578 | " states deeper than C2"); |
@@ -537,6 +586,9 @@ static int intel_idle_cpuidle_driver_init(void) | |||
537 | if (icpu->auto_demotion_disable_flags) | 586 | if (icpu->auto_demotion_disable_flags) |
538 | on_each_cpu(auto_demotion_disable, NULL, 1); | 587 | on_each_cpu(auto_demotion_disable, NULL, 1); |
539 | 588 | ||
589 | if (icpu->disable_promotion_to_c1e) /* each-cpu is redundant */ | ||
590 | on_each_cpu(c1e_promotion_disable, NULL, 1); | ||
591 | |||
540 | return 0; | 592 | return 0; |
541 | } | 593 | } |
542 | 594 | ||
@@ -555,25 +607,28 @@ static int intel_idle_cpu_init(int cpu) | |||
555 | 607 | ||
556 | dev->state_count = 1; | 608 | dev->state_count = 1; |
557 | 609 | ||
558 | for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { | 610 | for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { |
559 | int num_substates; | 611 | int num_substates, mwait_hint, mwait_cstate, mwait_substate; |
612 | |||
613 | if (cpuidle_state_table[cstate].enter == NULL) | ||
614 | continue; | ||
560 | 615 | ||
561 | if (cstate > max_cstate) { | 616 | if (cstate + 1 > max_cstate) { |
562 | printk(PREFIX "max_cstate %d reached\n", max_cstate); | 617 | printk(PREFIX "max_cstate %d reached\n", max_cstate); |
563 | break; | 618 | break; |
564 | } | 619 | } |
565 | 620 | ||
621 | mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); | ||
622 | mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); | ||
623 | mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); | ||
624 | |||
566 | /* does the state exist in CPUID.MWAIT? */ | 625 | /* does the state exist in CPUID.MWAIT? */ |
567 | num_substates = (mwait_substates >> ((cstate) * 4)) | 626 | num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) |
568 | & MWAIT_SUBSTATE_MASK; | 627 | & MWAIT_SUBSTATE_MASK; |
569 | if (num_substates == 0) | ||
570 | continue; | ||
571 | /* is the state not enabled? */ | ||
572 | if (cpuidle_state_table[cstate].enter == NULL) | ||
573 | continue; | ||
574 | 628 | ||
575 | dev->states_usage[dev->state_count].driver_data = | 629 | /* if sub-state in table is not enumerated by CPUID */ |
576 | (void *)get_driver_data(cstate); | 630 | if ((mwait_substate + 1) > num_substates) |
631 | continue; | ||
577 | 632 | ||
578 | dev->state_count += 1; | 633 | dev->state_count += 1; |
579 | } | 634 | } |
@@ -624,6 +679,7 @@ static int __init intel_idle_init(void) | |||
624 | return retval; | 679 | return retval; |
625 | } | 680 | } |
626 | } | 681 | } |
682 | register_cpu_notifier(&cpu_hotplug_notifier); | ||
627 | 683 | ||
628 | return 0; | 684 | return 0; |
629 | } | 685 | } |