diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 13:13:52 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 13:13:52 -0500 |
| commit | 3c00303206c3a1ccd86579efdc90bc35f140962e (patch) | |
| tree | 66170c84b5ddaeb102aea3530517a26657b6ea29 /drivers/idle | |
| parent | 83dbb15e9cd78a3619e3db36777e2f81d09b2914 (diff) | |
| parent | efb90582c575084723cc14302c1300cb26c7e01f (diff) | |
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux:
cpuidle: Single/Global registration of idle states
cpuidle: Split cpuidle_state structure and move per-cpu statistics fields
cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare()
cpuidle: Move dev->last_residency update to driver enter routine; remove dev->last_state
ACPI: Fix CONFIG_ACPI_DOCK=n compiler warning
ACPI: Export FADT pm_profile integer value to userspace
thermal: Prevent polling from happening during system suspend
ACPI: Drop ACPI_NO_HARDWARE_INIT
ACPI atomicio: Convert width in bits to bytes in __acpi_ioremap_fast()
PNPACPI: Simplify disabled resource registration
ACPI: Fix possible recursive locking in hwregs.c
ACPI: use kstrdup()
mrst pmu: update comment
tools/power turbostat: less verbose debugging
Diffstat (limited to 'drivers/idle')
| -rw-r--r-- | drivers/idle/intel_idle.c | 130 |
1 files changed, 99 insertions, 31 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 18767f8ab090..5d2f8e13cf0e 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
| @@ -82,7 +82,8 @@ static unsigned int mwait_substates; | |||
| 82 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ | 82 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ |
| 83 | 83 | ||
| 84 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; | 84 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; |
| 85 | static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); | 85 | static int intel_idle(struct cpuidle_device *dev, |
| 86 | struct cpuidle_driver *drv, int index); | ||
| 86 | 87 | ||
| 87 | static struct cpuidle_state *cpuidle_state_table; | 88 | static struct cpuidle_state *cpuidle_state_table; |
| 88 | 89 | ||
| @@ -110,7 +111,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 110 | { /* MWAIT C1 */ | 111 | { /* MWAIT C1 */ |
| 111 | .name = "C1-NHM", | 112 | .name = "C1-NHM", |
| 112 | .desc = "MWAIT 0x00", | 113 | .desc = "MWAIT 0x00", |
| 113 | .driver_data = (void *) 0x00, | ||
| 114 | .flags = CPUIDLE_FLAG_TIME_VALID, | 114 | .flags = CPUIDLE_FLAG_TIME_VALID, |
| 115 | .exit_latency = 3, | 115 | .exit_latency = 3, |
| 116 | .target_residency = 6, | 116 | .target_residency = 6, |
| @@ -118,7 +118,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 118 | { /* MWAIT C2 */ | 118 | { /* MWAIT C2 */ |
| 119 | .name = "C3-NHM", | 119 | .name = "C3-NHM", |
| 120 | .desc = "MWAIT 0x10", | 120 | .desc = "MWAIT 0x10", |
| 121 | .driver_data = (void *) 0x10, | ||
| 122 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 121 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 123 | .exit_latency = 20, | 122 | .exit_latency = 20, |
| 124 | .target_residency = 80, | 123 | .target_residency = 80, |
| @@ -126,7 +125,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 126 | { /* MWAIT C3 */ | 125 | { /* MWAIT C3 */ |
| 127 | .name = "C6-NHM", | 126 | .name = "C6-NHM", |
| 128 | .desc = "MWAIT 0x20", | 127 | .desc = "MWAIT 0x20", |
| 129 | .driver_data = (void *) 0x20, | ||
| 130 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 128 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 131 | .exit_latency = 200, | 129 | .exit_latency = 200, |
| 132 | .target_residency = 800, | 130 | .target_residency = 800, |
| @@ -138,7 +136,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 138 | { /* MWAIT C1 */ | 136 | { /* MWAIT C1 */ |
| 139 | .name = "C1-SNB", | 137 | .name = "C1-SNB", |
| 140 | .desc = "MWAIT 0x00", | 138 | .desc = "MWAIT 0x00", |
| 141 | .driver_data = (void *) 0x00, | ||
| 142 | .flags = CPUIDLE_FLAG_TIME_VALID, | 139 | .flags = CPUIDLE_FLAG_TIME_VALID, |
| 143 | .exit_latency = 1, | 140 | .exit_latency = 1, |
| 144 | .target_residency = 1, | 141 | .target_residency = 1, |
| @@ -146,7 +143,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 146 | { /* MWAIT C2 */ | 143 | { /* MWAIT C2 */ |
| 147 | .name = "C3-SNB", | 144 | .name = "C3-SNB", |
| 148 | .desc = "MWAIT 0x10", | 145 | .desc = "MWAIT 0x10", |
| 149 | .driver_data = (void *) 0x10, | ||
| 150 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 146 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 151 | .exit_latency = 80, | 147 | .exit_latency = 80, |
| 152 | .target_residency = 211, | 148 | .target_residency = 211, |
| @@ -154,7 +150,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 154 | { /* MWAIT C3 */ | 150 | { /* MWAIT C3 */ |
| 155 | .name = "C6-SNB", | 151 | .name = "C6-SNB", |
| 156 | .desc = "MWAIT 0x20", | 152 | .desc = "MWAIT 0x20", |
| 157 | .driver_data = (void *) 0x20, | ||
| 158 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 153 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 159 | .exit_latency = 104, | 154 | .exit_latency = 104, |
| 160 | .target_residency = 345, | 155 | .target_residency = 345, |
| @@ -162,7 +157,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 162 | { /* MWAIT C4 */ | 157 | { /* MWAIT C4 */ |
| 163 | .name = "C7-SNB", | 158 | .name = "C7-SNB", |
| 164 | .desc = "MWAIT 0x30", | 159 | .desc = "MWAIT 0x30", |
| 165 | .driver_data = (void *) 0x30, | ||
| 166 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 160 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 167 | .exit_latency = 109, | 161 | .exit_latency = 109, |
| 168 | .target_residency = 345, | 162 | .target_residency = 345, |
| @@ -174,7 +168,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 174 | { /* MWAIT C1 */ | 168 | { /* MWAIT C1 */ |
| 175 | .name = "C1-ATM", | 169 | .name = "C1-ATM", |
| 176 | .desc = "MWAIT 0x00", | 170 | .desc = "MWAIT 0x00", |
| 177 | .driver_data = (void *) 0x00, | ||
| 178 | .flags = CPUIDLE_FLAG_TIME_VALID, | 171 | .flags = CPUIDLE_FLAG_TIME_VALID, |
| 179 | .exit_latency = 1, | 172 | .exit_latency = 1, |
| 180 | .target_residency = 4, | 173 | .target_residency = 4, |
| @@ -182,7 +175,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 182 | { /* MWAIT C2 */ | 175 | { /* MWAIT C2 */ |
| 183 | .name = "C2-ATM", | 176 | .name = "C2-ATM", |
| 184 | .desc = "MWAIT 0x10", | 177 | .desc = "MWAIT 0x10", |
| 185 | .driver_data = (void *) 0x10, | ||
| 186 | .flags = CPUIDLE_FLAG_TIME_VALID, | 178 | .flags = CPUIDLE_FLAG_TIME_VALID, |
| 187 | .exit_latency = 20, | 179 | .exit_latency = 20, |
| 188 | .target_residency = 80, | 180 | .target_residency = 80, |
| @@ -191,7 +183,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 191 | { /* MWAIT C4 */ | 183 | { /* MWAIT C4 */ |
| 192 | .name = "C4-ATM", | 184 | .name = "C4-ATM", |
| 193 | .desc = "MWAIT 0x30", | 185 | .desc = "MWAIT 0x30", |
| 194 | .driver_data = (void *) 0x30, | ||
| 195 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 186 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 196 | .exit_latency = 100, | 187 | .exit_latency = 100, |
| 197 | .target_residency = 400, | 188 | .target_residency = 400, |
| @@ -200,23 +191,55 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
| 200 | { /* MWAIT C6 */ | 191 | { /* MWAIT C6 */ |
| 201 | .name = "C6-ATM", | 192 | .name = "C6-ATM", |
| 202 | .desc = "MWAIT 0x52", | 193 | .desc = "MWAIT 0x52", |
| 203 | .driver_data = (void *) 0x52, | ||
| 204 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 194 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 205 | .exit_latency = 140, | 195 | .exit_latency = 140, |
| 206 | .target_residency = 560, | 196 | .target_residency = 560, |
| 207 | .enter = &intel_idle }, | 197 | .enter = &intel_idle }, |
| 208 | }; | 198 | }; |
| 209 | 199 | ||
| 200 | static int get_driver_data(int cstate) | ||
| 201 | { | ||
| 202 | int driver_data; | ||
| 203 | switch (cstate) { | ||
| 204 | |||
| 205 | case 1: /* MWAIT C1 */ | ||
| 206 | driver_data = 0x00; | ||
| 207 | break; | ||
| 208 | case 2: /* MWAIT C2 */ | ||
| 209 | driver_data = 0x10; | ||
| 210 | break; | ||
| 211 | case 3: /* MWAIT C3 */ | ||
| 212 | driver_data = 0x20; | ||
| 213 | break; | ||
| 214 | case 4: /* MWAIT C4 */ | ||
| 215 | driver_data = 0x30; | ||
| 216 | break; | ||
| 217 | case 5: /* MWAIT C5 */ | ||
| 218 | driver_data = 0x40; | ||
| 219 | break; | ||
| 220 | case 6: /* MWAIT C6 */ | ||
| 221 | driver_data = 0x52; | ||
| 222 | break; | ||
| 223 | default: | ||
| 224 | driver_data = 0x00; | ||
| 225 | } | ||
| 226 | return driver_data; | ||
| 227 | } | ||
| 228 | |||
| 210 | /** | 229 | /** |
| 211 | * intel_idle | 230 | * intel_idle |
| 212 | * @dev: cpuidle_device | 231 | * @dev: cpuidle_device |
| 213 | * @state: cpuidle state | 232 | * @drv: cpuidle driver |
| 233 | * @index: index of cpuidle state | ||
| 214 | * | 234 | * |
| 215 | */ | 235 | */ |
| 216 | static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) | 236 | static int intel_idle(struct cpuidle_device *dev, |
| 237 | struct cpuidle_driver *drv, int index) | ||
| 217 | { | 238 | { |
| 218 | unsigned long ecx = 1; /* break on interrupt flag */ | 239 | unsigned long ecx = 1; /* break on interrupt flag */ |
| 219 | unsigned long eax = (unsigned long)cpuidle_get_statedata(state); | 240 | struct cpuidle_state *state = &drv->states[index]; |
| 241 | struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; | ||
| 242 | unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); | ||
| 220 | unsigned int cstate; | 243 | unsigned int cstate; |
| 221 | ktime_t kt_before, kt_after; | 244 | ktime_t kt_before, kt_after; |
| 222 | s64 usec_delta; | 245 | s64 usec_delta; |
| @@ -257,7 +280,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) | |||
| 257 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 280 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
| 258 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | 281 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); |
| 259 | 282 | ||
| 260 | return usec_delta; | 283 | /* Update cpuidle counters */ |
| 284 | dev->last_residency = (int)usec_delta; | ||
| 285 | |||
| 286 | return index; | ||
| 261 | } | 287 | } |
| 262 | 288 | ||
| 263 | static void __setup_broadcast_timer(void *arg) | 289 | static void __setup_broadcast_timer(void *arg) |
| @@ -398,6 +424,60 @@ static void intel_idle_cpuidle_devices_uninit(void) | |||
| 398 | return; | 424 | return; |
| 399 | } | 425 | } |
| 400 | /* | 426 | /* |
| 427 | * intel_idle_cpuidle_driver_init() | ||
| 428 | * allocate, initialize cpuidle_states | ||
| 429 | */ | ||
| 430 | static int intel_idle_cpuidle_driver_init(void) | ||
| 431 | { | ||
| 432 | int cstate; | ||
| 433 | struct cpuidle_driver *drv = &intel_idle_driver; | ||
| 434 | |||
| 435 | drv->state_count = 1; | ||
| 436 | |||
| 437 | for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { | ||
| 438 | int num_substates; | ||
| 439 | |||
| 440 | if (cstate > max_cstate) { | ||
| 441 | printk(PREFIX "max_cstate %d reached\n", | ||
| 442 | max_cstate); | ||
| 443 | break; | ||
| 444 | } | ||
| 445 | |||
| 446 | /* does the state exist in CPUID.MWAIT? */ | ||
| 447 | num_substates = (mwait_substates >> ((cstate) * 4)) | ||
| 448 | & MWAIT_SUBSTATE_MASK; | ||
| 449 | if (num_substates == 0) | ||
| 450 | continue; | ||
| 451 | /* is the state not enabled? */ | ||
| 452 | if (cpuidle_state_table[cstate].enter == NULL) { | ||
| 453 | /* does the driver not know about the state? */ | ||
| 454 | if (*cpuidle_state_table[cstate].name == '\0') | ||
| 455 | pr_debug(PREFIX "unaware of model 0x%x" | ||
| 456 | " MWAIT %d please" | ||
| 457 | " contact lenb@kernel.org", | ||
| 458 | boot_cpu_data.x86_model, cstate); | ||
| 459 | continue; | ||
| 460 | } | ||
| 461 | |||
| 462 | if ((cstate > 2) && | ||
| 463 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | ||
| 464 | mark_tsc_unstable("TSC halts in idle" | ||
| 465 | " states deeper than C2"); | ||
| 466 | |||
| 467 | drv->states[drv->state_count] = /* structure copy */ | ||
| 468 | cpuidle_state_table[cstate]; | ||
| 469 | |||
| 470 | drv->state_count += 1; | ||
| 471 | } | ||
| 472 | |||
| 473 | if (auto_demotion_disable_flags) | ||
| 474 | smp_call_function(auto_demotion_disable, NULL, 1); | ||
| 475 | |||
| 476 | return 0; | ||
| 477 | } | ||
| 478 | |||
| 479 | |||
| 480 | /* | ||
| 401 | * intel_idle_cpuidle_devices_init() | 481 | * intel_idle_cpuidle_devices_init() |
| 402 | * allocate, initialize, register cpuidle_devices | 482 | * allocate, initialize, register cpuidle_devices |
| 403 | */ | 483 | */ |
| @@ -431,22 +511,11 @@ static int intel_idle_cpuidle_devices_init(void) | |||
| 431 | continue; | 511 | continue; |
| 432 | /* is the state not enabled? */ | 512 | /* is the state not enabled? */ |
| 433 | if (cpuidle_state_table[cstate].enter == NULL) { | 513 | if (cpuidle_state_table[cstate].enter == NULL) { |
| 434 | /* does the driver not know about the state? */ | ||
| 435 | if (*cpuidle_state_table[cstate].name == '\0') | ||
| 436 | pr_debug(PREFIX "unaware of model 0x%x" | ||
| 437 | " MWAIT %d please" | ||
| 438 | " contact lenb@kernel.org", | ||
| 439 | boot_cpu_data.x86_model, cstate); | ||
| 440 | continue; | 514 | continue; |
| 441 | } | 515 | } |
| 442 | 516 | ||
| 443 | if ((cstate > 2) && | 517 | dev->states_usage[dev->state_count].driver_data = |
| 444 | !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | 518 | (void *)get_driver_data(cstate); |
| 445 | mark_tsc_unstable("TSC halts in idle" | ||
| 446 | " states deeper than C2"); | ||
| 447 | |||
| 448 | dev->states[dev->state_count] = /* structure copy */ | ||
| 449 | cpuidle_state_table[cstate]; | ||
| 450 | 519 | ||
| 451 | dev->state_count += 1; | 520 | dev->state_count += 1; |
| 452 | } | 521 | } |
| @@ -459,8 +528,6 @@ static int intel_idle_cpuidle_devices_init(void) | |||
| 459 | return -EIO; | 528 | return -EIO; |
| 460 | } | 529 | } |
| 461 | } | 530 | } |
| 462 | if (auto_demotion_disable_flags) | ||
| 463 | smp_call_function(auto_demotion_disable, NULL, 1); | ||
| 464 | 531 | ||
| 465 | return 0; | 532 | return 0; |
| 466 | } | 533 | } |
| @@ -478,6 +545,7 @@ static int __init intel_idle_init(void) | |||
| 478 | if (retval) | 545 | if (retval) |
| 479 | return retval; | 546 | return retval; |
| 480 | 547 | ||
| 548 | intel_idle_cpuidle_driver_init(); | ||
| 481 | retval = cpuidle_register_driver(&intel_idle_driver); | 549 | retval = cpuidle_register_driver(&intel_idle_driver); |
| 482 | if (retval) { | 550 | if (retval) { |
| 483 | printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", | 551 | printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", |
