aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/mwait.h2
-rw-r--r--drivers/idle/intel_idle.c110
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 */
126static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { 126static 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
151static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { 152static 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
183static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { 185static 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
215static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { 218static 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
247static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { 251static 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;