diff options
author | Len Brown <len.brown@intel.com> | 2013-02-01 23:37:30 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2013-02-08 19:29:16 -0500 |
commit | e022e7eb90f3edb83f9ff77825eda3d1b3a2f2e0 (patch) | |
tree | 3bfc121a7534712af7ca04f4d2ac6f23582a6479 /drivers/idle/intel_idle.c | |
parent | 137ecc779c80138723677209730738d76262e810 (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.c | 110 |
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 | */ |
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; |