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/intel_idle.c | |
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/intel_idle.c')
-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", |