aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle/intel_idle.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r--drivers/idle/intel_idle.c131
1 files changed, 100 insertions, 31 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index a46dddf61078..5d2f8e13cf0e 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -61,6 +61,7 @@
61#include <linux/sched.h> 61#include <linux/sched.h>
62#include <linux/notifier.h> 62#include <linux/notifier.h>
63#include <linux/cpu.h> 63#include <linux/cpu.h>
64#include <linux/module.h>
64#include <asm/mwait.h> 65#include <asm/mwait.h>
65#include <asm/msr.h> 66#include <asm/msr.h>
66 67
@@ -81,7 +82,8 @@ static unsigned int mwait_substates;
81static 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 */
82 83
83static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; 84static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
84static 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);
85 87
86static struct cpuidle_state *cpuidle_state_table; 88static struct cpuidle_state *cpuidle_state_table;
87 89
@@ -109,7 +111,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
109 { /* MWAIT C1 */ 111 { /* MWAIT C1 */
110 .name = "C1-NHM", 112 .name = "C1-NHM",
111 .desc = "MWAIT 0x00", 113 .desc = "MWAIT 0x00",
112 .driver_data = (void *) 0x00,
113 .flags = CPUIDLE_FLAG_TIME_VALID, 114 .flags = CPUIDLE_FLAG_TIME_VALID,
114 .exit_latency = 3, 115 .exit_latency = 3,
115 .target_residency = 6, 116 .target_residency = 6,
@@ -117,7 +118,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
117 { /* MWAIT C2 */ 118 { /* MWAIT C2 */
118 .name = "C3-NHM", 119 .name = "C3-NHM",
119 .desc = "MWAIT 0x10", 120 .desc = "MWAIT 0x10",
120 .driver_data = (void *) 0x10,
121 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 121 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
122 .exit_latency = 20, 122 .exit_latency = 20,
123 .target_residency = 80, 123 .target_residency = 80,
@@ -125,7 +125,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
125 { /* MWAIT C3 */ 125 { /* MWAIT C3 */
126 .name = "C6-NHM", 126 .name = "C6-NHM",
127 .desc = "MWAIT 0x20", 127 .desc = "MWAIT 0x20",
128 .driver_data = (void *) 0x20,
129 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 128 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
130 .exit_latency = 200, 129 .exit_latency = 200,
131 .target_residency = 800, 130 .target_residency = 800,
@@ -137,7 +136,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
137 { /* MWAIT C1 */ 136 { /* MWAIT C1 */
138 .name = "C1-SNB", 137 .name = "C1-SNB",
139 .desc = "MWAIT 0x00", 138 .desc = "MWAIT 0x00",
140 .driver_data = (void *) 0x00,
141 .flags = CPUIDLE_FLAG_TIME_VALID, 139 .flags = CPUIDLE_FLAG_TIME_VALID,
142 .exit_latency = 1, 140 .exit_latency = 1,
143 .target_residency = 1, 141 .target_residency = 1,
@@ -145,7 +143,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
145 { /* MWAIT C2 */ 143 { /* MWAIT C2 */
146 .name = "C3-SNB", 144 .name = "C3-SNB",
147 .desc = "MWAIT 0x10", 145 .desc = "MWAIT 0x10",
148 .driver_data = (void *) 0x10,
149 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 146 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
150 .exit_latency = 80, 147 .exit_latency = 80,
151 .target_residency = 211, 148 .target_residency = 211,
@@ -153,7 +150,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
153 { /* MWAIT C3 */ 150 { /* MWAIT C3 */
154 .name = "C6-SNB", 151 .name = "C6-SNB",
155 .desc = "MWAIT 0x20", 152 .desc = "MWAIT 0x20",
156 .driver_data = (void *) 0x20,
157 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 153 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
158 .exit_latency = 104, 154 .exit_latency = 104,
159 .target_residency = 345, 155 .target_residency = 345,
@@ -161,7 +157,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
161 { /* MWAIT C4 */ 157 { /* MWAIT C4 */
162 .name = "C7-SNB", 158 .name = "C7-SNB",
163 .desc = "MWAIT 0x30", 159 .desc = "MWAIT 0x30",
164 .driver_data = (void *) 0x30,
165 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 160 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
166 .exit_latency = 109, 161 .exit_latency = 109,
167 .target_residency = 345, 162 .target_residency = 345,
@@ -173,7 +168,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
173 { /* MWAIT C1 */ 168 { /* MWAIT C1 */
174 .name = "C1-ATM", 169 .name = "C1-ATM",
175 .desc = "MWAIT 0x00", 170 .desc = "MWAIT 0x00",
176 .driver_data = (void *) 0x00,
177 .flags = CPUIDLE_FLAG_TIME_VALID, 171 .flags = CPUIDLE_FLAG_TIME_VALID,
178 .exit_latency = 1, 172 .exit_latency = 1,
179 .target_residency = 4, 173 .target_residency = 4,
@@ -181,7 +175,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
181 { /* MWAIT C2 */ 175 { /* MWAIT C2 */
182 .name = "C2-ATM", 176 .name = "C2-ATM",
183 .desc = "MWAIT 0x10", 177 .desc = "MWAIT 0x10",
184 .driver_data = (void *) 0x10,
185 .flags = CPUIDLE_FLAG_TIME_VALID, 178 .flags = CPUIDLE_FLAG_TIME_VALID,
186 .exit_latency = 20, 179 .exit_latency = 20,
187 .target_residency = 80, 180 .target_residency = 80,
@@ -190,7 +183,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
190 { /* MWAIT C4 */ 183 { /* MWAIT C4 */
191 .name = "C4-ATM", 184 .name = "C4-ATM",
192 .desc = "MWAIT 0x30", 185 .desc = "MWAIT 0x30",
193 .driver_data = (void *) 0x30,
194 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 186 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
195 .exit_latency = 100, 187 .exit_latency = 100,
196 .target_residency = 400, 188 .target_residency = 400,
@@ -199,23 +191,55 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
199 { /* MWAIT C6 */ 191 { /* MWAIT C6 */
200 .name = "C6-ATM", 192 .name = "C6-ATM",
201 .desc = "MWAIT 0x52", 193 .desc = "MWAIT 0x52",
202 .driver_data = (void *) 0x52,
203 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, 194 .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
204 .exit_latency = 140, 195 .exit_latency = 140,
205 .target_residency = 560, 196 .target_residency = 560,
206 .enter = &intel_idle }, 197 .enter = &intel_idle },
207}; 198};
208 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
209/** 229/**
210 * intel_idle 230 * intel_idle
211 * @dev: cpuidle_device 231 * @dev: cpuidle_device
212 * @state: cpuidle state 232 * @drv: cpuidle driver
233 * @index: index of cpuidle state
213 * 234 *
214 */ 235 */
215static 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)
216{ 238{
217 unsigned long ecx = 1; /* break on interrupt flag */ 239 unsigned long ecx = 1; /* break on interrupt flag */
218 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);
219 unsigned int cstate; 243 unsigned int cstate;
220 ktime_t kt_before, kt_after; 244 ktime_t kt_before, kt_after;
221 s64 usec_delta; 245 s64 usec_delta;
@@ -256,7 +280,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
256 if (!(lapic_timer_reliable_states & (1 << (cstate)))) 280 if (!(lapic_timer_reliable_states & (1 << (cstate))))
257 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); 281 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
258 282
259 return usec_delta; 283 /* Update cpuidle counters */
284 dev->last_residency = (int)usec_delta;
285
286 return index;
260} 287}
261 288
262static void __setup_broadcast_timer(void *arg) 289static void __setup_broadcast_timer(void *arg)
@@ -397,6 +424,60 @@ static void intel_idle_cpuidle_devices_uninit(void)
397 return; 424 return;
398} 425}
399/* 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/*
400 * intel_idle_cpuidle_devices_init() 481 * intel_idle_cpuidle_devices_init()
401 * allocate, initialize, register cpuidle_devices 482 * allocate, initialize, register cpuidle_devices
402 */ 483 */
@@ -430,22 +511,11 @@ static int intel_idle_cpuidle_devices_init(void)
430 continue; 511 continue;
431 /* is the state not enabled? */ 512 /* is the state not enabled? */
432 if (cpuidle_state_table[cstate].enter == NULL) { 513 if (cpuidle_state_table[cstate].enter == NULL) {
433 /* does the driver not know about the state? */
434 if (*cpuidle_state_table[cstate].name == '\0')
435 pr_debug(PREFIX "unaware of model 0x%x"
436 " MWAIT %d please"
437 " contact lenb@kernel.org",
438 boot_cpu_data.x86_model, cstate);
439 continue; 514 continue;
440 } 515 }
441 516
442 if ((cstate > 2) && 517 dev->states_usage[dev->state_count].driver_data =
443 !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) 518 (void *)get_driver_data(cstate);
444 mark_tsc_unstable("TSC halts in idle"
445 " states deeper than C2");
446
447 dev->states[dev->state_count] = /* structure copy */
448 cpuidle_state_table[cstate];
449 519
450 dev->state_count += 1; 520 dev->state_count += 1;
451 } 521 }
@@ -458,8 +528,6 @@ static int intel_idle_cpuidle_devices_init(void)
458 return -EIO; 528 return -EIO;
459 } 529 }
460 } 530 }
461 if (auto_demotion_disable_flags)
462 smp_call_function(auto_demotion_disable, NULL, 1);
463 531
464 return 0; 532 return 0;
465} 533}
@@ -477,6 +545,7 @@ static int __init intel_idle_init(void)
477 if (retval) 545 if (retval)
478 return retval; 546 return retval;
479 547
548 intel_idle_cpuidle_driver_init();
480 retval = cpuidle_register_driver(&intel_idle_driver); 549 retval = cpuidle_register_driver(&intel_idle_driver);
481 if (retval) { 550 if (retval) {
482 printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", 551 printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",