Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

Len Brown e022e7eb 137ecc77

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