aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle/intel_idle.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-07 13:13:52 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-07 13:13:52 -0500
commit3c00303206c3a1ccd86579efdc90bc35f140962e (patch)
tree66170c84b5ddaeb102aea3530517a26657b6ea29 /drivers/idle/intel_idle.c
parent83dbb15e9cd78a3619e3db36777e2f81d09b2914 (diff)
parentefb90582c575084723cc14302c1300cb26c7e01f (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.c130
1 files changed, 99 insertions, 31 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 18767f8ab09..5d2f8e13cf0 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -82,7 +82,8 @@ static unsigned int mwait_substates;
82static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ 82static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
83 83
84static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; 84static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
85static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); 85static int intel_idle(struct cpuidle_device *dev,
86 struct cpuidle_driver *drv, int index);
86 87
87static struct cpuidle_state *cpuidle_state_table; 88static 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
200static 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 */
216static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) 236static 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
263static void __setup_broadcast_timer(void *arg) 289static 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 */
430static 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",