diff options
-rw-r--r-- | arch/x86/include/asm/mwait.h | 2 | ||||
-rw-r--r-- | drivers/idle/intel_idle.c | 110 |
2 files changed, 61 insertions, 51 deletions
diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h index 3f447320ce87..2f366d0ac6b4 100644 --- a/arch/x86/include/asm/mwait.h +++ b/arch/x86/include/asm/mwait.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #define MWAIT_SUBSTATE_MASK 0xf | 4 | #define MWAIT_SUBSTATE_MASK 0xf |
5 | #define MWAIT_CSTATE_MASK 0xf | 5 | #define MWAIT_CSTATE_MASK 0xf |
6 | #define MWAIT_SUBSTATE_SIZE 4 | 6 | #define MWAIT_SUBSTATE_SIZE 4 |
7 | #define MWAIT_HINT2CSTATE(hint) (((hint) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) | ||
8 | #define MWAIT_HINT2SUBSTATE(hint) ((hint) & MWAIT_CSTATE_MASK) | ||
7 | 9 | ||
8 | #define CPUID_MWAIT_LEAF 5 | 10 | #define CPUID_MWAIT_LEAF 5 |
9 | #define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1 | 11 | #define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1 |
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index c949a6f25a83..927cfb4d66f4 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -124,158 +124,161 @@ static struct cpuidle_state *cpuidle_state_table; | |||
124 | * Thus C0 is a dummy. | 124 | * Thus C0 is a dummy. |
125 | */ | 125 | */ |
126 | static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { | 126 | static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { |
127 | { /* MWAIT C0 */ }, | 127 | { |
128 | { /* MWAIT C1 */ | ||
129 | .name = "C1-NHM", | 128 | .name = "C1-NHM", |
130 | .desc = "MWAIT 0x00", | 129 | .desc = "MWAIT 0x00", |
131 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, | 130 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
132 | .exit_latency = 3, | 131 | .exit_latency = 3, |
133 | .target_residency = 6, | 132 | .target_residency = 6, |
134 | .enter = &intel_idle }, | 133 | .enter = &intel_idle }, |
135 | { /* MWAIT C2 */ | 134 | { |
136 | .name = "C3-NHM", | 135 | .name = "C3-NHM", |
137 | .desc = "MWAIT 0x10", | 136 | .desc = "MWAIT 0x10", |
138 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 137 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
139 | .exit_latency = 20, | 138 | .exit_latency = 20, |
140 | .target_residency = 80, | 139 | .target_residency = 80, |
141 | .enter = &intel_idle }, | 140 | .enter = &intel_idle }, |
142 | { /* MWAIT C3 */ | 141 | { |
143 | .name = "C6-NHM", | 142 | .name = "C6-NHM", |
144 | .desc = "MWAIT 0x20", | 143 | .desc = "MWAIT 0x20", |
145 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 144 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
146 | .exit_latency = 200, | 145 | .exit_latency = 200, |
147 | .target_residency = 800, | 146 | .target_residency = 800, |
148 | .enter = &intel_idle }, | 147 | .enter = &intel_idle }, |
148 | { | ||
149 | .enter = NULL } | ||
149 | }; | 150 | }; |
150 | 151 | ||
151 | static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { | 152 | static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { |
152 | { /* MWAIT C0 */ }, | 153 | { |
153 | { /* MWAIT C1 */ | ||
154 | .name = "C1-SNB", | 154 | .name = "C1-SNB", |
155 | .desc = "MWAIT 0x00", | 155 | .desc = "MWAIT 0x00", |
156 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, | 156 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
157 | .exit_latency = 1, | 157 | .exit_latency = 1, |
158 | .target_residency = 1, | 158 | .target_residency = 1, |
159 | .enter = &intel_idle }, | 159 | .enter = &intel_idle }, |
160 | { /* MWAIT C2 */ | 160 | { |
161 | .name = "C3-SNB", | 161 | .name = "C3-SNB", |
162 | .desc = "MWAIT 0x10", | 162 | .desc = "MWAIT 0x10", |
163 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 163 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
164 | .exit_latency = 80, | 164 | .exit_latency = 80, |
165 | .target_residency = 211, | 165 | .target_residency = 211, |
166 | .enter = &intel_idle }, | 166 | .enter = &intel_idle }, |
167 | { /* MWAIT C3 */ | 167 | { |
168 | .name = "C6-SNB", | 168 | .name = "C6-SNB", |
169 | .desc = "MWAIT 0x20", | 169 | .desc = "MWAIT 0x20", |
170 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 170 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
171 | .exit_latency = 104, | 171 | .exit_latency = 104, |
172 | .target_residency = 345, | 172 | .target_residency = 345, |
173 | .enter = &intel_idle }, | 173 | .enter = &intel_idle }, |
174 | { /* MWAIT C4 */ | 174 | { |
175 | .name = "C7-SNB", | 175 | .name = "C7-SNB", |
176 | .desc = "MWAIT 0x30", | 176 | .desc = "MWAIT 0x30", |
177 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 177 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
178 | .exit_latency = 109, | 178 | .exit_latency = 109, |
179 | .target_residency = 345, | 179 | .target_residency = 345, |
180 | .enter = &intel_idle }, | 180 | .enter = &intel_idle }, |
181 | { | ||
182 | .enter = NULL } | ||
181 | }; | 183 | }; |
182 | 184 | ||
183 | static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { | 185 | static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { |
184 | { /* MWAIT C0 */ }, | 186 | { |
185 | { /* MWAIT C1 */ | ||
186 | .name = "C1-IVB", | 187 | .name = "C1-IVB", |
187 | .desc = "MWAIT 0x00", | 188 | .desc = "MWAIT 0x00", |
188 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, | 189 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
189 | .exit_latency = 1, | 190 | .exit_latency = 1, |
190 | .target_residency = 1, | 191 | .target_residency = 1, |
191 | .enter = &intel_idle }, | 192 | .enter = &intel_idle }, |
192 | { /* MWAIT C2 */ | 193 | { |
193 | .name = "C3-IVB", | 194 | .name = "C3-IVB", |
194 | .desc = "MWAIT 0x10", | 195 | .desc = "MWAIT 0x10", |
195 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 196 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
196 | .exit_latency = 59, | 197 | .exit_latency = 59, |
197 | .target_residency = 156, | 198 | .target_residency = 156, |
198 | .enter = &intel_idle }, | 199 | .enter = &intel_idle }, |
199 | { /* MWAIT C3 */ | 200 | { |
200 | .name = "C6-IVB", | 201 | .name = "C6-IVB", |
201 | .desc = "MWAIT 0x20", | 202 | .desc = "MWAIT 0x20", |
202 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 203 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
203 | .exit_latency = 80, | 204 | .exit_latency = 80, |
204 | .target_residency = 300, | 205 | .target_residency = 300, |
205 | .enter = &intel_idle }, | 206 | .enter = &intel_idle }, |
206 | { /* MWAIT C4 */ | 207 | { |
207 | .name = "C7-IVB", | 208 | .name = "C7-IVB", |
208 | .desc = "MWAIT 0x30", | 209 | .desc = "MWAIT 0x30", |
209 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 210 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
210 | .exit_latency = 87, | 211 | .exit_latency = 87, |
211 | .target_residency = 300, | 212 | .target_residency = 300, |
212 | .enter = &intel_idle }, | 213 | .enter = &intel_idle }, |
214 | { | ||
215 | .enter = NULL } | ||
213 | }; | 216 | }; |
214 | 217 | ||
215 | static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { | 218 | static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { |
216 | { /* MWAIT C0 */ }, | 219 | { |
217 | { /* MWAIT C1 */ | ||
218 | .name = "C1-HSW", | 220 | .name = "C1-HSW", |
219 | .desc = "MWAIT 0x00", | 221 | .desc = "MWAIT 0x00", |
220 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, | 222 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
221 | .exit_latency = 2, | 223 | .exit_latency = 2, |
222 | .target_residency = 2, | 224 | .target_residency = 2, |
223 | .enter = &intel_idle }, | 225 | .enter = &intel_idle }, |
224 | { /* MWAIT C2 */ | 226 | { |
225 | .name = "C3-HSW", | 227 | .name = "C3-HSW", |
226 | .desc = "MWAIT 0x10", | 228 | .desc = "MWAIT 0x10", |
227 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 229 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
228 | .exit_latency = 33, | 230 | .exit_latency = 33, |
229 | .target_residency = 100, | 231 | .target_residency = 100, |
230 | .enter = &intel_idle }, | 232 | .enter = &intel_idle }, |
231 | { /* MWAIT C3 */ | 233 | { |
232 | .name = "C6-HSW", | 234 | .name = "C6-HSW", |
233 | .desc = "MWAIT 0x20", | 235 | .desc = "MWAIT 0x20", |
234 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 236 | .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
235 | .exit_latency = 133, | 237 | .exit_latency = 133, |
236 | .target_residency = 400, | 238 | .target_residency = 400, |
237 | .enter = &intel_idle }, | 239 | .enter = &intel_idle }, |
238 | { /* MWAIT C4 */ | 240 | { |
239 | .name = "C7s-HSW", | 241 | .name = "C7s-HSW", |
240 | .desc = "MWAIT 0x32", | 242 | .desc = "MWAIT 0x32", |
241 | .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 243 | .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
242 | .exit_latency = 166, | 244 | .exit_latency = 166, |
243 | .target_residency = 500, | 245 | .target_residency = 500, |
244 | .enter = &intel_idle }, | 246 | .enter = &intel_idle }, |
247 | { | ||
248 | .enter = NULL } | ||
245 | }; | 249 | }; |
246 | 250 | ||
247 | static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { | 251 | static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { |
248 | { /* MWAIT C0 */ }, | 252 | { |
249 | { /* MWAIT C1 */ | ||
250 | .name = "C1-ATM", | 253 | .name = "C1-ATM", |
251 | .desc = "MWAIT 0x00", | 254 | .desc = "MWAIT 0x00", |
252 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, | 255 | .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, |
253 | .exit_latency = 1, | 256 | .exit_latency = 1, |
254 | .target_residency = 4, | 257 | .target_residency = 4, |
255 | .enter = &intel_idle }, | 258 | .enter = &intel_idle }, |
256 | { /* MWAIT C2 */ | 259 | { |
257 | .name = "C2-ATM", | 260 | .name = "C2-ATM", |
258 | .desc = "MWAIT 0x10", | 261 | .desc = "MWAIT 0x10", |
259 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID, | 262 | .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID, |
260 | .exit_latency = 20, | 263 | .exit_latency = 20, |
261 | .target_residency = 80, | 264 | .target_residency = 80, |
262 | .enter = &intel_idle }, | 265 | .enter = &intel_idle }, |
263 | { /* MWAIT C3 */ }, | 266 | { |
264 | { /* MWAIT C4 */ | ||
265 | .name = "C4-ATM", | 267 | .name = "C4-ATM", |
266 | .desc = "MWAIT 0x30", | 268 | .desc = "MWAIT 0x30", |
267 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 269 | .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
268 | .exit_latency = 100, | 270 | .exit_latency = 100, |
269 | .target_residency = 400, | 271 | .target_residency = 400, |
270 | .enter = &intel_idle }, | 272 | .enter = &intel_idle }, |
271 | { /* MWAIT C5 */ }, | 273 | { |
272 | { /* MWAIT C6 */ | ||
273 | .name = "C6-ATM", | 274 | .name = "C6-ATM", |
274 | .desc = "MWAIT 0x52", | 275 | .desc = "MWAIT 0x52", |
275 | .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 276 | .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
276 | .exit_latency = 140, | 277 | .exit_latency = 140, |
277 | .target_residency = 560, | 278 | .target_residency = 560, |
278 | .enter = &intel_idle }, | 279 | .enter = &intel_idle }, |
280 | { | ||
281 | .enter = NULL } | ||
279 | }; | 282 | }; |
280 | 283 | ||
281 | /** | 284 | /** |
@@ -503,32 +506,31 @@ static int intel_idle_cpuidle_driver_init(void) | |||
503 | 506 | ||
504 | drv->state_count = 1; | 507 | drv->state_count = 1; |
505 | 508 | ||
506 | for (cstate = 1; cstate < CPUIDLE_STATE_MAX; ++cstate) { | 509 | for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { |
507 | int num_substates; | 510 | int num_substates, mwait_hint, mwait_cstate, mwait_substate; |
508 | 511 | ||
509 | if (cstate > max_cstate) { | 512 | if (cpuidle_state_table[cstate].enter == NULL) |
513 | break; | ||
514 | |||
515 | if (cstate + 1 > max_cstate) { | ||
510 | printk(PREFIX "max_cstate %d reached\n", | 516 | printk(PREFIX "max_cstate %d reached\n", |
511 | max_cstate); | 517 | max_cstate); |
512 | break; | 518 | break; |
513 | } | 519 | } |
514 | 520 | ||
521 | mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); | ||
522 | mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); | ||
523 | mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); | ||
524 | |||
515 | /* does the state exist in CPUID.MWAIT? */ | 525 | /* does the state exist in CPUID.MWAIT? */ |
516 | num_substates = (mwait_substates >> ((cstate) * 4)) | 526 | num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) |
517 | & MWAIT_SUBSTATE_MASK; | 527 | & MWAIT_SUBSTATE_MASK; |
518 | if (num_substates == 0) | 528 | |
519 | continue; | 529 | /* if sub-state in table is not enumerated by CPUID */ |
520 | /* is the state not enabled? */ | 530 | if ((mwait_substate + 1) > num_substates) |
521 | if (cpuidle_state_table[cstate].enter == NULL) { | ||
522 | /* does the driver not know about the state? */ | ||
523 | if (*cpuidle_state_table[cstate].name == '\0') | ||
524 | pr_debug(PREFIX "unaware of model 0x%x" | ||
525 | " MWAIT %d please" | ||
526 | " contact lenb@kernel.org\n", | ||
527 | boot_cpu_data.x86_model, cstate); | ||
528 | continue; | 531 | continue; |
529 | } | ||
530 | 532 | ||
531 | if ((cstate > 2) && | 533 | if (((mwait_cstate + 1) > 2) && |
532 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | 534 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) |
533 | mark_tsc_unstable("TSC halts in idle" | 535 | mark_tsc_unstable("TSC halts in idle" |
534 | " states deeper than C2"); | 536 | " states deeper than C2"); |
@@ -560,21 +562,27 @@ static int intel_idle_cpu_init(int cpu) | |||
560 | 562 | ||
561 | dev->state_count = 1; | 563 | dev->state_count = 1; |
562 | 564 | ||
563 | for (cstate = 1; cstate < CPUIDLE_STATE_MAX; ++cstate) { | 565 | for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { |
564 | int num_substates; | 566 | int num_substates, mwait_hint, mwait_cstate, mwait_substate; |
565 | 567 | ||
566 | if (cstate > max_cstate) { | 568 | if (cpuidle_state_table[cstate].enter == NULL) |
569 | continue; | ||
570 | |||
571 | if (cstate + 1 > max_cstate) { | ||
567 | printk(PREFIX "max_cstate %d reached\n", max_cstate); | 572 | printk(PREFIX "max_cstate %d reached\n", max_cstate); |
568 | break; | 573 | break; |
569 | } | 574 | } |
570 | 575 | ||
576 | mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); | ||
577 | mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); | ||
578 | mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); | ||
579 | |||
571 | /* does the state exist in CPUID.MWAIT? */ | 580 | /* does the state exist in CPUID.MWAIT? */ |
572 | num_substates = (mwait_substates >> ((cstate) * 4)) | 581 | num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) |
573 | & MWAIT_SUBSTATE_MASK; | 582 | & MWAIT_SUBSTATE_MASK; |
574 | if (num_substates == 0) | 583 | |
575 | continue; | 584 | /* if sub-state in table is not enumerated by CPUID */ |
576 | /* is the state not enabled? */ | 585 | if ((mwait_substate + 1) > num_substates) |
577 | if (cpuidle_state_table[cstate].enter == NULL) | ||
578 | continue; | 586 | continue; |
579 | 587 | ||
580 | dev->state_count += 1; | 588 | dev->state_count += 1; |