diff options
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r-- | drivers/idle/intel_idle.c | 80 |
1 files changed, 61 insertions, 19 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 3aa8d4cb6dca..5be9d599ff6b 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -81,7 +81,8 @@ static unsigned int mwait_substates; | |||
81 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ | 81 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ |
82 | 82 | ||
83 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; | 83 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; |
84 | static int intel_idle(struct cpuidle_device *dev, int index); | 84 | static int intel_idle(struct cpuidle_device *dev, |
85 | struct cpuidle_driver *drv, int index); | ||
85 | 86 | ||
86 | static struct cpuidle_state *cpuidle_state_table; | 87 | static struct cpuidle_state *cpuidle_state_table; |
87 | 88 | ||
@@ -227,13 +228,15 @@ static int get_driver_data(int cstate) | |||
227 | /** | 228 | /** |
228 | * intel_idle | 229 | * intel_idle |
229 | * @dev: cpuidle_device | 230 | * @dev: cpuidle_device |
231 | * @drv: cpuidle driver | ||
230 | * @index: index of cpuidle state | 232 | * @index: index of cpuidle state |
231 | * | 233 | * |
232 | */ | 234 | */ |
233 | static int intel_idle(struct cpuidle_device *dev, int index) | 235 | static int intel_idle(struct cpuidle_device *dev, |
236 | struct cpuidle_driver *drv, int index) | ||
234 | { | 237 | { |
235 | unsigned long ecx = 1; /* break on interrupt flag */ | 238 | unsigned long ecx = 1; /* break on interrupt flag */ |
236 | struct cpuidle_state *state = &dev->states[index]; | 239 | struct cpuidle_state *state = &drv->states[index]; |
237 | struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; | 240 | struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; |
238 | unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); | 241 | unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); |
239 | unsigned int cstate; | 242 | unsigned int cstate; |
@@ -420,6 +423,60 @@ static void intel_idle_cpuidle_devices_uninit(void) | |||
420 | return; | 423 | return; |
421 | } | 424 | } |
422 | /* | 425 | /* |
426 | * intel_idle_cpuidle_driver_init() | ||
427 | * allocate, initialize cpuidle_states | ||
428 | */ | ||
429 | static int intel_idle_cpuidle_driver_init(void) | ||
430 | { | ||
431 | int cstate; | ||
432 | struct cpuidle_driver *drv = &intel_idle_driver; | ||
433 | |||
434 | drv->state_count = 1; | ||
435 | |||
436 | for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { | ||
437 | int num_substates; | ||
438 | |||
439 | if (cstate > max_cstate) { | ||
440 | printk(PREFIX "max_cstate %d reached\n", | ||
441 | max_cstate); | ||
442 | break; | ||
443 | } | ||
444 | |||
445 | /* does the state exist in CPUID.MWAIT? */ | ||
446 | num_substates = (mwait_substates >> ((cstate) * 4)) | ||
447 | & MWAIT_SUBSTATE_MASK; | ||
448 | if (num_substates == 0) | ||
449 | continue; | ||
450 | /* is the state not enabled? */ | ||
451 | if (cpuidle_state_table[cstate].enter == NULL) { | ||
452 | /* does the driver not know about the state? */ | ||
453 | if (*cpuidle_state_table[cstate].name == '\0') | ||
454 | pr_debug(PREFIX "unaware of model 0x%x" | ||
455 | " MWAIT %d please" | ||
456 | " contact lenb@kernel.org", | ||
457 | boot_cpu_data.x86_model, cstate); | ||
458 | continue; | ||
459 | } | ||
460 | |||
461 | if ((cstate > 2) && | ||
462 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | ||
463 | mark_tsc_unstable("TSC halts in idle" | ||
464 | " states deeper than C2"); | ||
465 | |||
466 | drv->states[drv->state_count] = /* structure copy */ | ||
467 | cpuidle_state_table[cstate]; | ||
468 | |||
469 | drv->state_count += 1; | ||
470 | } | ||
471 | |||
472 | if (auto_demotion_disable_flags) | ||
473 | smp_call_function(auto_demotion_disable, NULL, 1); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | |||
479 | /* | ||
423 | * intel_idle_cpuidle_devices_init() | 480 | * intel_idle_cpuidle_devices_init() |
424 | * allocate, initialize, register cpuidle_devices | 481 | * allocate, initialize, register cpuidle_devices |
425 | */ | 482 | */ |
@@ -453,23 +510,9 @@ static int intel_idle_cpuidle_devices_init(void) | |||
453 | continue; | 510 | continue; |
454 | /* is the state not enabled? */ | 511 | /* is the state not enabled? */ |
455 | if (cpuidle_state_table[cstate].enter == NULL) { | 512 | if (cpuidle_state_table[cstate].enter == NULL) { |
456 | /* does the driver not know about the state? */ | ||
457 | if (*cpuidle_state_table[cstate].name == '\0') | ||
458 | pr_debug(PREFIX "unaware of model 0x%x" | ||
459 | " MWAIT %d please" | ||
460 | " contact lenb@kernel.org", | ||
461 | boot_cpu_data.x86_model, cstate); | ||
462 | continue; | 513 | continue; |
463 | } | 514 | } |
464 | 515 | ||
465 | if ((cstate > 2) && | ||
466 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | ||
467 | mark_tsc_unstable("TSC halts in idle" | ||
468 | " states deeper than C2"); | ||
469 | |||
470 | dev->states[dev->state_count] = /* structure copy */ | ||
471 | cpuidle_state_table[cstate]; | ||
472 | |||
473 | dev->states_usage[dev->state_count].driver_data = | 516 | dev->states_usage[dev->state_count].driver_data = |
474 | (void *)get_driver_data(cstate); | 517 | (void *)get_driver_data(cstate); |
475 | 518 | ||
@@ -484,8 +527,6 @@ static int intel_idle_cpuidle_devices_init(void) | |||
484 | return -EIO; | 527 | return -EIO; |
485 | } | 528 | } |
486 | } | 529 | } |
487 | if (auto_demotion_disable_flags) | ||
488 | smp_call_function(auto_demotion_disable, NULL, 1); | ||
489 | 530 | ||
490 | return 0; | 531 | return 0; |
491 | } | 532 | } |
@@ -503,6 +544,7 @@ static int __init intel_idle_init(void) | |||
503 | if (retval) | 544 | if (retval) |
504 | return retval; | 545 | return retval; |
505 | 546 | ||
547 | intel_idle_cpuidle_driver_init(); | ||
506 | retval = cpuidle_register_driver(&intel_idle_driver); | 548 | retval = cpuidle_register_driver(&intel_idle_driver); |
507 | if (retval) { | 549 | if (retval) { |
508 | printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", | 550 | printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", |