Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

P-state software coordination for acpi-cpufreq

http://bugzilla.kernel.org/show_bug.cgi?id=5737

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Venkatesh Pallipadi and committed by
Len Brown
09b4d1ee 3b2d9942

+197 -88
+197 -88
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
··· 48 48 49 49 50 50 struct cpufreq_acpi_io { 51 - struct acpi_processor_performance acpi_data; 51 + struct acpi_processor_performance *acpi_data; 52 52 struct cpufreq_frequency_table *freq_table; 53 53 unsigned int resume; 54 54 }; 55 55 56 56 static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; 57 + static struct acpi_processor_performance *acpi_perf_data[NR_CPUS]; 57 58 58 59 static struct cpufreq_driver acpi_cpufreq_driver; 59 60 ··· 105 104 { 106 105 u16 port = 0; 107 106 u8 bit_width = 0; 107 + int i = 0; 108 108 int ret = 0; 109 109 u32 value = 0; 110 - int i = 0; 111 - struct cpufreq_freqs cpufreq_freqs; 112 - cpumask_t saved_mask; 113 110 int retval; 111 + struct acpi_processor_performance *perf; 114 112 115 113 dprintk("acpi_processor_set_performance\n"); 116 114 117 - /* 118 - * TBD: Use something other than set_cpus_allowed. 119 - * As set_cpus_allowed is a bit racy, 120 - * with any other set_cpus_allowed for this process. 121 - */ 122 - saved_mask = current->cpus_allowed; 123 - set_cpus_allowed(current, cpumask_of_cpu(cpu)); 124 - if (smp_processor_id() != cpu) { 125 - return (-EAGAIN); 126 - } 127 - 128 - if (state == data->acpi_data.state) { 115 + retval = 0; 116 + perf = data->acpi_data; 117 + if (state == perf->state) { 129 118 if (unlikely(data->resume)) { 130 119 dprintk("Called after resume, resetting to P%d\n", state); 131 120 data->resume = 0; 132 121 } else { 133 122 dprintk("Already at target state (P%d)\n", state); 134 - retval = 0; 135 - goto migrate_end; 123 + return (retval); 136 124 } 137 125 } 138 126 139 - dprintk("Transitioning from P%d to P%d\n", 140 - data->acpi_data.state, state); 141 - 142 - /* cpufreq frequency struct */ 143 - cpufreq_freqs.cpu = cpu; 144 - cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; 145 - cpufreq_freqs.new = data->freq_table[state].frequency; 146 - 147 - /* notify cpufreq */ 148 - cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); 127 + dprintk("Transitioning from P%d to P%d\n", perf->state, state); 149 128 150 129 /* 151 130 * First we write the target state's 'control' value to the 152 131 * control_register. 153 132 */ 154 133 155 - port = data->acpi_data.control_register.address; 156 - bit_width = data->acpi_data.control_register.bit_width; 157 - value = (u32) data->acpi_data.states[state].control; 134 + port = perf->control_register.address; 135 + bit_width = perf->control_register.bit_width; 136 + value = (u32) perf->states[state].control; 158 137 159 138 dprintk("Writing 0x%08x to port 0x%04x\n", value, port); 160 139 161 140 ret = acpi_processor_write_port(port, bit_width, value); 162 141 if (ret) { 163 142 dprintk("Invalid port width 0x%04x\n", bit_width); 164 - retval = ret; 165 - goto migrate_end; 143 + return (ret); 166 144 } 167 145 168 146 /* ··· 157 177 * before giving up. 158 178 */ 159 179 160 - port = data->acpi_data.status_register.address; 161 - bit_width = data->acpi_data.status_register.bit_width; 180 + port = perf->status_register.address; 181 + bit_width = perf->status_register.bit_width; 162 182 163 183 dprintk("Looking for 0x%08x from port 0x%04x\n", 164 - (u32) data->acpi_data.states[state].status, port); 184 + (u32) perf->states[state].status, port); 165 185 166 - for (i=0; i<100; i++) { 186 + for (i = 0; i < 100; i++) { 167 187 ret = acpi_processor_read_port(port, bit_width, &value); 168 188 if (ret) { 169 189 dprintk("Invalid port width 0x%04x\n", bit_width); 170 - retval = ret; 171 - goto migrate_end; 190 + return (ret); 172 191 } 173 - if (value == (u32) data->acpi_data.states[state].status) 192 + if (value == (u32) perf->states[state].status) 174 193 break; 175 194 udelay(10); 176 195 } 177 196 } else { 178 197 i = 0; 179 - value = (u32) data->acpi_data.states[state].status; 198 + value = (u32) perf->states[state].status; 180 199 } 181 200 182 - /* notify cpufreq */ 183 - cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); 184 - 185 - if (unlikely(value != (u32) data->acpi_data.states[state].status)) { 186 - unsigned int tmp = cpufreq_freqs.new; 187 - cpufreq_freqs.new = cpufreq_freqs.old; 188 - cpufreq_freqs.old = tmp; 189 - cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); 190 - cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); 201 + if (unlikely(value != (u32) perf->states[state].status)) { 191 202 printk(KERN_WARNING "acpi-cpufreq: Transition failed\n"); 192 203 retval = -ENODEV; 193 - goto migrate_end; 204 + return (retval); 194 205 } 195 206 196 207 dprintk("Transition successful after %d microseconds\n", i * 10); 197 208 198 - data->acpi_data.state = state; 199 - 200 - retval = 0; 201 - migrate_end: 202 - set_cpus_allowed(current, saved_mask); 209 + perf->state = state; 203 210 return (retval); 204 211 } 205 212 ··· 198 231 unsigned int relation) 199 232 { 200 233 struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; 234 + struct acpi_processor_performance *perf; 235 + struct cpufreq_freqs freqs; 236 + cpumask_t online_policy_cpus; 237 + cpumask_t saved_mask; 238 + cpumask_t set_mask; 239 + cpumask_t covered_cpus; 240 + unsigned int cur_state = 0; 201 241 unsigned int next_state = 0; 202 242 unsigned int result = 0; 243 + unsigned int j; 244 + unsigned int tmp; 203 245 204 246 dprintk("acpi_cpufreq_setpolicy\n"); 205 247 ··· 217 241 target_freq, 218 242 relation, 219 243 &next_state); 220 - if (result) 244 + if (unlikely(result)) 221 245 return (result); 222 246 223 - result = acpi_processor_set_performance (data, policy->cpu, next_state); 247 + perf = data->acpi_data; 248 + cur_state = perf->state; 249 + freqs.old = data->freq_table[cur_state].frequency; 250 + freqs.new = data->freq_table[next_state].frequency; 224 251 252 + /* cpufreq holds the hotplug lock, so we are safe from here on */ 253 + cpus_and(online_policy_cpus, cpu_online_map, policy->cpus); 254 + 255 + for_each_cpu_mask(j, online_policy_cpus) { 256 + freqs.cpu = j; 257 + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 258 + } 259 + 260 + /* 261 + * We need to call driver->target() on all or any CPU in 262 + * policy->cpus, depending on policy->shared_type. 263 + */ 264 + saved_mask = current->cpus_allowed; 265 + cpus_clear(covered_cpus); 266 + for_each_cpu_mask(j, online_policy_cpus) { 267 + /* 268 + * Support for SMP systems. 269 + * Make sure we are running on CPU that wants to change freq 270 + */ 271 + cpus_clear(set_mask); 272 + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 273 + cpus_or(set_mask, set_mask, online_policy_cpus); 274 + else 275 + cpu_set(j, set_mask); 276 + 277 + set_cpus_allowed(current, set_mask); 278 + if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) { 279 + dprintk("couldn't limit to CPUs in this domain\n"); 280 + result = -EAGAIN; 281 + break; 282 + } 283 + 284 + result = acpi_processor_set_performance (data, j, next_state); 285 + if (result) { 286 + result = -EAGAIN; 287 + break; 288 + } 289 + 290 + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 291 + break; 292 + 293 + cpu_set(j, covered_cpus); 294 + } 295 + 296 + for_each_cpu_mask(j, online_policy_cpus) { 297 + freqs.cpu = j; 298 + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 299 + } 300 + 301 + if (unlikely(result)) { 302 + /* 303 + * We have failed halfway through the frequency change. 304 + * We have sent callbacks to online_policy_cpus and 305 + * acpi_processor_set_performance() has been called on 306 + * coverd_cpus. Best effort undo.. 307 + */ 308 + 309 + if (!cpus_empty(covered_cpus)) { 310 + for_each_cpu_mask(j, covered_cpus) { 311 + policy->cpu = j; 312 + acpi_processor_set_performance (data, 313 + j, 314 + cur_state); 315 + } 316 + } 317 + 318 + tmp = freqs.new; 319 + freqs.new = freqs.old; 320 + freqs.old = tmp; 321 + for_each_cpu_mask(j, online_policy_cpus) { 322 + freqs.cpu = j; 323 + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 324 + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 325 + } 326 + } 327 + 328 + set_cpus_allowed(current, saved_mask); 225 329 return (result); 226 330 } 227 331 ··· 327 271 struct cpufreq_acpi_io *data, 328 272 unsigned int cpu) 329 273 { 274 + struct acpi_processor_performance *perf = data->acpi_data; 275 + 330 276 if (cpu_khz) { 331 277 /* search the closest match to cpu_khz */ 332 278 unsigned int i; 333 279 unsigned long freq; 334 - unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000; 280 + unsigned long freqn = perf->states[0].core_frequency * 1000; 335 281 336 - for (i=0; i < (data->acpi_data.state_count - 1); i++) { 282 + for (i = 0; i < (perf->state_count - 1); i++) { 337 283 freq = freqn; 338 - freqn = data->acpi_data.states[i+1].core_frequency * 1000; 284 + freqn = perf->states[i+1].core_frequency * 1000; 339 285 if ((2 * cpu_khz) > (freqn + freq)) { 340 - data->acpi_data.state = i; 286 + perf->state = i; 341 287 return (freq); 342 288 } 343 289 } 344 - data->acpi_data.state = data->acpi_data.state_count - 1; 290 + perf->state = perf->state_count - 1; 345 291 return (freqn); 346 - } else 292 + } else { 347 293 /* assume CPU is at P0... */ 348 - data->acpi_data.state = 0; 349 - return data->acpi_data.states[0].core_frequency * 1000; 350 - 294 + perf->state = 0; 295 + return perf->states[0].core_frequency * 1000; 296 + } 351 297 } 352 298 299 + 300 + /* 301 + * acpi_cpufreq_early_init - initialize ACPI P-States library 302 + * 303 + * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c) 304 + * in order to determine correct frequency and voltage pairings. We can 305 + * do _PDC and _PSD and find out the processor dependency for the 306 + * actual init that will happen later... 307 + */ 308 + static int acpi_cpufreq_early_init_acpi(void) 309 + { 310 + struct acpi_processor_performance *data; 311 + unsigned int i, j; 312 + 313 + dprintk("acpi_cpufreq_early_init\n"); 314 + 315 + for_each_cpu(i) { 316 + data = kzalloc(sizeof(struct acpi_processor_performance), 317 + GFP_KERNEL); 318 + if (!data) { 319 + for_each_cpu(j) { 320 + kfree(acpi_perf_data[j]); 321 + acpi_perf_data[j] = NULL; 322 + } 323 + return (-ENOMEM); 324 + } 325 + acpi_perf_data[i] = data; 326 + } 327 + 328 + /* Do initialization in ACPI core */ 329 + acpi_processor_preregister_performance(acpi_perf_data); 330 + return 0; 331 + } 353 332 354 333 static int 355 334 acpi_cpufreq_cpu_init ( ··· 395 304 struct cpufreq_acpi_io *data; 396 305 unsigned int result = 0; 397 306 struct cpuinfo_x86 *c = &cpu_data[policy->cpu]; 307 + struct acpi_processor_performance *perf; 398 308 399 309 dprintk("acpi_cpufreq_cpu_init\n"); 310 + 311 + if (!acpi_perf_data[cpu]) 312 + return (-ENODEV); 400 313 401 314 data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); 402 315 if (!data) 403 316 return (-ENOMEM); 404 317 318 + data->acpi_data = acpi_perf_data[cpu]; 405 319 acpi_io_data[cpu] = data; 406 320 407 - result = acpi_processor_register_performance(&data->acpi_data, cpu); 321 + result = acpi_processor_register_performance(data->acpi_data, cpu); 408 322 409 323 if (result) 410 324 goto err_free; 325 + 326 + perf = data->acpi_data; 327 + policy->cpus = perf->shared_cpu_map; 328 + policy->shared_type = perf->shared_type; 411 329 412 330 if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { 413 331 acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; 414 332 } 415 333 416 334 /* capability check */ 417 - if (data->acpi_data.state_count <= 1) { 335 + if (perf->state_count <= 1) { 418 336 dprintk("No P-States\n"); 419 337 result = -ENODEV; 420 338 goto err_unreg; 421 339 } 422 - if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || 423 - (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 340 + 341 + if ((perf->control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || 342 + (perf->status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 424 343 dprintk("Unsupported address space [%d, %d]\n", 425 - (u32) (data->acpi_data.control_register.space_id), 426 - (u32) (data->acpi_data.status_register.space_id)); 344 + (u32) (perf->control_register.space_id), 345 + (u32) (perf->status_register.space_id)); 427 346 result = -ENODEV; 428 347 goto err_unreg; 429 348 } 430 349 431 350 /* alloc freq_table */ 432 - data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); 351 + data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (perf->state_count + 1), GFP_KERNEL); 433 352 if (!data->freq_table) { 434 353 result = -ENOMEM; 435 354 goto err_unreg; ··· 447 346 448 347 /* detect transition latency */ 449 348 policy->cpuinfo.transition_latency = 0; 450 - for (i=0; i<data->acpi_data.state_count; i++) { 451 - if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) 452 - policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000; 349 + for (i=0; i<perf->state_count; i++) { 350 + if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) 351 + policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; 453 352 } 454 353 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 455 354 ··· 457 356 policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); 458 357 459 358 /* table init */ 460 - for (i=0; i<=data->acpi_data.state_count; i++) 359 + for (i=0; i<=perf->state_count; i++) 461 360 { 462 361 data->freq_table[i].index = i; 463 - if (i<data->acpi_data.state_count) 464 - data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; 362 + if (i<perf->state_count) 363 + data->freq_table[i].frequency = perf->states[i].core_frequency * 1000; 465 364 else 466 365 data->freq_table[i].frequency = CPUFREQ_TABLE_END; 467 366 } ··· 476 375 477 376 printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n", 478 377 cpu); 479 - for (i = 0; i < data->acpi_data.state_count; i++) 378 + for (i = 0; i < perf->state_count; i++) 480 379 dprintk(" %cP%d: %d MHz, %d mW, %d uS\n", 481 - (i == data->acpi_data.state?'*':' '), i, 482 - (u32) data->acpi_data.states[i].core_frequency, 483 - (u32) data->acpi_data.states[i].power, 484 - (u32) data->acpi_data.states[i].transition_latency); 380 + (i == perf->state?'*':' '), i, 381 + (u32) perf->states[i].core_frequency, 382 + (u32) perf->states[i].power, 383 + (u32) perf->states[i].transition_latency); 485 384 486 385 cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); 487 386 ··· 496 395 err_freqfree: 497 396 kfree(data->freq_table); 498 397 err_unreg: 499 - acpi_processor_unregister_performance(&data->acpi_data, cpu); 398 + acpi_processor_unregister_performance(perf, cpu); 500 399 err_free: 501 400 kfree(data); 502 401 acpi_io_data[cpu] = NULL; ··· 517 416 if (data) { 518 417 cpufreq_frequency_table_put_attr(policy->cpu); 519 418 acpi_io_data[policy->cpu] = NULL; 520 - acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); 419 + acpi_processor_unregister_performance(data->acpi_data, policy->cpu); 521 420 kfree(data); 522 421 } 523 422 ··· 563 462 564 463 dprintk("acpi_cpufreq_init\n"); 565 464 566 - result = cpufreq_register_driver(&acpi_cpufreq_driver); 465 + result = acpi_cpufreq_early_init_acpi(); 466 + 467 + if (!result) 468 + result = cpufreq_register_driver(&acpi_cpufreq_driver); 567 469 568 470 return (result); 569 471 } ··· 575 471 static void __exit 576 472 acpi_cpufreq_exit (void) 577 473 { 474 + unsigned int i; 578 475 dprintk("acpi_cpufreq_exit\n"); 579 476 580 477 cpufreq_unregister_driver(&acpi_cpufreq_driver); 581 478 479 + for_each_cpu(i) { 480 + kfree(acpi_perf_data[i]); 481 + acpi_perf_data[i] = NULL; 482 + } 582 483 return; 583 484 } 584 485