aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle/intel_idle.c
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2013-02-01 23:37:30 -0500
committerLen Brown <len.brown@intel.com>2013-02-08 19:29:16 -0500
commite022e7eb90f3edb83f9ff77825eda3d1b3a2f2e0 (patch)
tree3bfc121a7534712af7ca04f4d2ac6f23582a6479 /drivers/idle/intel_idle.c
parent137ecc779c80138723677209730738d76262e810 (diff)
intel_idle: remove assumption of one C-state per MWAIT flag
Remove the assumption that cstate_tables are indexed by MWAIT flag values. Each entry identifies itself via its own flags value. This change is needed to support multiple states that share the same MWAIT flags. Note that this can have an effect on what state is described by 'N' on cmdline intel_idle.max_cstate=N on some systems. intel_idle.max_cstate=0 still disables the driver intel_idle.max_cstate=1 still results in just C1(E) However, "place holders" in the sparse C-state name-space (eg. Atom) have been removed. Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r--drivers/idle/intel_idle.c110
1 files changed, 59 insertions, 51 deletions
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;