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

Pull acpi-p-state into release branch

Tony Luck 7115c13b 7d2e423a

+562
+6
arch/ia64/Kconfig
··· 383 383 384 384 endif 385 385 386 + if PM 387 + 388 + source "arch/ia64/kernel/cpufreq/Kconfig" 389 + 390 + endif 391 + 386 392 endmenu 387 393 388 394 if !IA64_HP_SIM
+1
arch/ia64/kernel/Makefile
··· 20 20 obj-$(CONFIG_NUMA) += numa.o 21 21 obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o 22 22 obj-$(CONFIG_IA64_CYCLONE) += cyclone.o 23 + obj-$(CONFIG_CPU_FREQ) += cpufreq/ 23 24 obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o 24 25 obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o 25 26 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
+29
arch/ia64/kernel/cpufreq/Kconfig
··· 1 + 2 + # 3 + # CPU Frequency scaling 4 + # 5 + 6 + menu "CPU Frequency scaling" 7 + 8 + source "drivers/cpufreq/Kconfig" 9 + 10 + if CPU_FREQ 11 + 12 + comment "CPUFreq processor drivers" 13 + 14 + config IA64_ACPI_CPUFREQ 15 + tristate "ACPI Processor P-States driver" 16 + select CPU_FREQ_TABLE 17 + depends on ACPI_PROCESSOR 18 + help 19 + This driver adds a CPUFreq driver which utilizes the ACPI 20 + Processor Performance States. 21 + 22 + For details, take a look at <file:Documentation/cpu-freq/>. 23 + 24 + If in doubt, say N. 25 + 26 + endif # CPU_FREQ 27 + 28 + endmenu 29 +
+1
arch/ia64/kernel/cpufreq/Makefile
··· 1 + obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
+499
arch/ia64/kernel/cpufreq/acpi-cpufreq.c
··· 1 + /* 2 + * arch/ia64/kernel/cpufreq/acpi-cpufreq.c 3 + * This file provides the ACPI based P-state support. This 4 + * module works with generic cpufreq infrastructure. Most of 5 + * the code is based on i386 version 6 + * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c) 7 + * 8 + * Copyright (C) 2005 Intel Corp 9 + * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 10 + */ 11 + 12 + #include <linux/config.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/init.h> 16 + #include <linux/cpufreq.h> 17 + #include <linux/proc_fs.h> 18 + #include <linux/seq_file.h> 19 + #include <asm/io.h> 20 + #include <asm/uaccess.h> 21 + #include <asm/pal.h> 22 + 23 + #include <linux/acpi.h> 24 + #include <acpi/processor.h> 25 + 26 + #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) 27 + 28 + MODULE_AUTHOR("Venkatesh Pallipadi"); 29 + MODULE_DESCRIPTION("ACPI Processor P-States Driver"); 30 + MODULE_LICENSE("GPL"); 31 + 32 + 33 + struct cpufreq_acpi_io { 34 + struct acpi_processor_performance acpi_data; 35 + struct cpufreq_frequency_table *freq_table; 36 + unsigned int resume; 37 + }; 38 + 39 + static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; 40 + 41 + static struct cpufreq_driver acpi_cpufreq_driver; 42 + 43 + 44 + static int 45 + processor_set_pstate ( 46 + u32 value) 47 + { 48 + s64 retval; 49 + 50 + dprintk("processor_set_pstate\n"); 51 + 52 + retval = ia64_pal_set_pstate((u64)value); 53 + 54 + if (retval) { 55 + dprintk("Failed to set freq to 0x%x, with error 0x%x\n", 56 + value, retval); 57 + return -ENODEV; 58 + } 59 + return (int)retval; 60 + } 61 + 62 + 63 + static int 64 + processor_get_pstate ( 65 + u32 *value) 66 + { 67 + u64 pstate_index = 0; 68 + s64 retval; 69 + 70 + dprintk("processor_get_pstate\n"); 71 + 72 + retval = ia64_pal_get_pstate(&pstate_index); 73 + *value = (u32) pstate_index; 74 + 75 + if (retval) 76 + dprintk("Failed to get current freq with " 77 + "error 0x%x, idx 0x%x\n", retval, *value); 78 + 79 + return (int)retval; 80 + } 81 + 82 + 83 + /* To be used only after data->acpi_data is initialized */ 84 + static unsigned 85 + extract_clock ( 86 + struct cpufreq_acpi_io *data, 87 + unsigned value, 88 + unsigned int cpu) 89 + { 90 + unsigned long i; 91 + 92 + dprintk("extract_clock\n"); 93 + 94 + for (i = 0; i < data->acpi_data.state_count; i++) { 95 + if (value >= data->acpi_data.states[i].control) 96 + return data->acpi_data.states[i].core_frequency; 97 + } 98 + return data->acpi_data.states[i-1].core_frequency; 99 + } 100 + 101 + 102 + static unsigned int 103 + processor_get_freq ( 104 + struct cpufreq_acpi_io *data, 105 + unsigned int cpu) 106 + { 107 + int ret = 0; 108 + u32 value = 0; 109 + cpumask_t saved_mask; 110 + unsigned long clock_freq; 111 + 112 + dprintk("processor_get_freq\n"); 113 + 114 + saved_mask = current->cpus_allowed; 115 + set_cpus_allowed(current, cpumask_of_cpu(cpu)); 116 + if (smp_processor_id() != cpu) { 117 + ret = -EAGAIN; 118 + goto migrate_end; 119 + } 120 + 121 + /* 122 + * processor_get_pstate gets the average frequency since the 123 + * last get. So, do two PAL_get_freq()... 124 + */ 125 + ret = processor_get_pstate(&value); 126 + ret = processor_get_pstate(&value); 127 + 128 + if (ret) { 129 + set_cpus_allowed(current, saved_mask); 130 + printk(KERN_WARNING "get performance failed with error %d\n", 131 + ret); 132 + ret = -EAGAIN; 133 + goto migrate_end; 134 + } 135 + clock_freq = extract_clock(data, value, cpu); 136 + ret = (clock_freq*1000); 137 + 138 + migrate_end: 139 + set_cpus_allowed(current, saved_mask); 140 + return ret; 141 + } 142 + 143 + 144 + static int 145 + processor_set_freq ( 146 + struct cpufreq_acpi_io *data, 147 + unsigned int cpu, 148 + int state) 149 + { 150 + int ret = 0; 151 + u32 value = 0; 152 + struct cpufreq_freqs cpufreq_freqs; 153 + cpumask_t saved_mask; 154 + int retval; 155 + 156 + dprintk("processor_set_freq\n"); 157 + 158 + saved_mask = current->cpus_allowed; 159 + set_cpus_allowed(current, cpumask_of_cpu(cpu)); 160 + if (smp_processor_id() != cpu) { 161 + retval = -EAGAIN; 162 + goto migrate_end; 163 + } 164 + 165 + if (state == data->acpi_data.state) { 166 + if (unlikely(data->resume)) { 167 + dprintk("Called after resume, resetting to P%d\n", state); 168 + data->resume = 0; 169 + } else { 170 + dprintk("Already at target state (P%d)\n", state); 171 + retval = 0; 172 + goto migrate_end; 173 + } 174 + } 175 + 176 + dprintk("Transitioning from P%d to P%d\n", 177 + data->acpi_data.state, state); 178 + 179 + /* cpufreq frequency struct */ 180 + cpufreq_freqs.cpu = cpu; 181 + cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; 182 + cpufreq_freqs.new = data->freq_table[state].frequency; 183 + 184 + /* notify cpufreq */ 185 + cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); 186 + 187 + /* 188 + * First we write the target state's 'control' value to the 189 + * control_register. 190 + */ 191 + 192 + value = (u32) data->acpi_data.states[state].control; 193 + 194 + dprintk("Transitioning to state: 0x%08x\n", value); 195 + 196 + ret = processor_set_pstate(value); 197 + if (ret) { 198 + unsigned int tmp = cpufreq_freqs.new; 199 + cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); 200 + cpufreq_freqs.new = cpufreq_freqs.old; 201 + cpufreq_freqs.old = tmp; 202 + cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); 203 + cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); 204 + printk(KERN_WARNING "Transition failed with error %d\n", ret); 205 + retval = -ENODEV; 206 + goto migrate_end; 207 + } 208 + 209 + cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); 210 + 211 + data->acpi_data.state = state; 212 + 213 + retval = 0; 214 + 215 + migrate_end: 216 + set_cpus_allowed(current, saved_mask); 217 + return (retval); 218 + } 219 + 220 + 221 + static unsigned int 222 + acpi_cpufreq_get ( 223 + unsigned int cpu) 224 + { 225 + struct cpufreq_acpi_io *data = acpi_io_data[cpu]; 226 + 227 + dprintk("acpi_cpufreq_get\n"); 228 + 229 + return processor_get_freq(data, cpu); 230 + } 231 + 232 + 233 + static int 234 + acpi_cpufreq_target ( 235 + struct cpufreq_policy *policy, 236 + unsigned int target_freq, 237 + unsigned int relation) 238 + { 239 + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; 240 + unsigned int next_state = 0; 241 + unsigned int result = 0; 242 + 243 + dprintk("acpi_cpufreq_setpolicy\n"); 244 + 245 + result = cpufreq_frequency_table_target(policy, 246 + data->freq_table, target_freq, relation, &next_state); 247 + if (result) 248 + return (result); 249 + 250 + result = processor_set_freq(data, policy->cpu, next_state); 251 + 252 + return (result); 253 + } 254 + 255 + 256 + static int 257 + acpi_cpufreq_verify ( 258 + struct cpufreq_policy *policy) 259 + { 260 + unsigned int result = 0; 261 + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; 262 + 263 + dprintk("acpi_cpufreq_verify\n"); 264 + 265 + result = cpufreq_frequency_table_verify(policy, 266 + data->freq_table); 267 + 268 + return (result); 269 + } 270 + 271 + 272 + /* 273 + * processor_init_pdc - let BIOS know about the SMP capabilities 274 + * of this driver 275 + * @perf: processor-specific acpi_io_data struct 276 + * @cpu: CPU being initialized 277 + * 278 + * To avoid issues with legacy OSes, some BIOSes require to be informed of 279 + * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC 280 + * accordingly. Actual call to _PDC is done in driver/acpi/processor.c 281 + */ 282 + static void 283 + processor_init_pdc ( 284 + struct acpi_processor_performance *perf, 285 + unsigned int cpu, 286 + struct acpi_object_list *obj_list 287 + ) 288 + { 289 + union acpi_object *obj; 290 + u32 *buf; 291 + 292 + dprintk("processor_init_pdc\n"); 293 + 294 + perf->pdc = NULL; 295 + /* Initialize pdc. It will be used later. */ 296 + if (!obj_list) 297 + return; 298 + 299 + if (!(obj_list->count && obj_list->pointer)) 300 + return; 301 + 302 + obj = obj_list->pointer; 303 + if ((obj->buffer.length == 12) && obj->buffer.pointer) { 304 + buf = (u32 *)obj->buffer.pointer; 305 + buf[0] = ACPI_PDC_REVISION_ID; 306 + buf[1] = 1; 307 + buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; 308 + perf->pdc = obj_list; 309 + } 310 + return; 311 + } 312 + 313 + 314 + static int 315 + acpi_cpufreq_cpu_init ( 316 + struct cpufreq_policy *policy) 317 + { 318 + unsigned int i; 319 + unsigned int cpu = policy->cpu; 320 + struct cpufreq_acpi_io *data; 321 + unsigned int result = 0; 322 + 323 + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; 324 + u32 arg0_buf[3]; 325 + struct acpi_object_list arg_list = {1, &arg0}; 326 + 327 + dprintk("acpi_cpufreq_cpu_init\n"); 328 + /* setup arg_list for _PDC settings */ 329 + arg0.buffer.length = 12; 330 + arg0.buffer.pointer = (u8 *) arg0_buf; 331 + 332 + data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); 333 + if (!data) 334 + return (-ENOMEM); 335 + 336 + memset(data, 0, sizeof(struct cpufreq_acpi_io)); 337 + 338 + acpi_io_data[cpu] = data; 339 + 340 + processor_init_pdc(&data->acpi_data, cpu, &arg_list); 341 + result = acpi_processor_register_performance(&data->acpi_data, cpu); 342 + data->acpi_data.pdc = NULL; 343 + 344 + if (result) 345 + goto err_free; 346 + 347 + /* capability check */ 348 + if (data->acpi_data.state_count <= 1) { 349 + dprintk("No P-States\n"); 350 + result = -ENODEV; 351 + goto err_unreg; 352 + } 353 + 354 + if ((data->acpi_data.control_register.space_id != 355 + ACPI_ADR_SPACE_FIXED_HARDWARE) || 356 + (data->acpi_data.status_register.space_id != 357 + ACPI_ADR_SPACE_FIXED_HARDWARE)) { 358 + dprintk("Unsupported address space [%d, %d]\n", 359 + (u32) (data->acpi_data.control_register.space_id), 360 + (u32) (data->acpi_data.status_register.space_id)); 361 + result = -ENODEV; 362 + goto err_unreg; 363 + } 364 + 365 + /* alloc freq_table */ 366 + data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * 367 + (data->acpi_data.state_count + 1), 368 + GFP_KERNEL); 369 + if (!data->freq_table) { 370 + result = -ENOMEM; 371 + goto err_unreg; 372 + } 373 + 374 + /* detect transition latency */ 375 + policy->cpuinfo.transition_latency = 0; 376 + for (i=0; i<data->acpi_data.state_count; i++) { 377 + if ((data->acpi_data.states[i].transition_latency * 1000) > 378 + policy->cpuinfo.transition_latency) { 379 + policy->cpuinfo.transition_latency = 380 + data->acpi_data.states[i].transition_latency * 1000; 381 + } 382 + } 383 + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 384 + 385 + policy->cur = processor_get_freq(data, policy->cpu); 386 + 387 + /* table init */ 388 + for (i = 0; i <= data->acpi_data.state_count; i++) 389 + { 390 + data->freq_table[i].index = i; 391 + if (i < data->acpi_data.state_count) { 392 + data->freq_table[i].frequency = 393 + data->acpi_data.states[i].core_frequency * 1000; 394 + } else { 395 + data->freq_table[i].frequency = CPUFREQ_TABLE_END; 396 + } 397 + } 398 + 399 + result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); 400 + if (result) { 401 + goto err_freqfree; 402 + } 403 + 404 + /* notify BIOS that we exist */ 405 + acpi_processor_notify_smm(THIS_MODULE); 406 + 407 + printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management " 408 + "activated.\n", cpu); 409 + 410 + for (i = 0; i < data->acpi_data.state_count; i++) 411 + dprintk(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", 412 + (i == data->acpi_data.state?'*':' '), i, 413 + (u32) data->acpi_data.states[i].core_frequency, 414 + (u32) data->acpi_data.states[i].power, 415 + (u32) data->acpi_data.states[i].transition_latency, 416 + (u32) data->acpi_data.states[i].bus_master_latency, 417 + (u32) data->acpi_data.states[i].status, 418 + (u32) data->acpi_data.states[i].control); 419 + 420 + cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); 421 + 422 + /* the first call to ->target() should result in us actually 423 + * writing something to the appropriate registers. */ 424 + data->resume = 1; 425 + 426 + return (result); 427 + 428 + err_freqfree: 429 + kfree(data->freq_table); 430 + err_unreg: 431 + acpi_processor_unregister_performance(&data->acpi_data, cpu); 432 + err_free: 433 + kfree(data); 434 + acpi_io_data[cpu] = NULL; 435 + 436 + return (result); 437 + } 438 + 439 + 440 + static int 441 + acpi_cpufreq_cpu_exit ( 442 + struct cpufreq_policy *policy) 443 + { 444 + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; 445 + 446 + dprintk("acpi_cpufreq_cpu_exit\n"); 447 + 448 + if (data) { 449 + cpufreq_frequency_table_put_attr(policy->cpu); 450 + acpi_io_data[policy->cpu] = NULL; 451 + acpi_processor_unregister_performance(&data->acpi_data, 452 + policy->cpu); 453 + kfree(data); 454 + } 455 + 456 + return (0); 457 + } 458 + 459 + 460 + static struct freq_attr* acpi_cpufreq_attr[] = { 461 + &cpufreq_freq_attr_scaling_available_freqs, 462 + NULL, 463 + }; 464 + 465 + 466 + static struct cpufreq_driver acpi_cpufreq_driver = { 467 + .verify = acpi_cpufreq_verify, 468 + .target = acpi_cpufreq_target, 469 + .get = acpi_cpufreq_get, 470 + .init = acpi_cpufreq_cpu_init, 471 + .exit = acpi_cpufreq_cpu_exit, 472 + .name = "acpi-cpufreq", 473 + .owner = THIS_MODULE, 474 + .attr = acpi_cpufreq_attr, 475 + }; 476 + 477 + 478 + static int __init 479 + acpi_cpufreq_init (void) 480 + { 481 + dprintk("acpi_cpufreq_init\n"); 482 + 483 + return cpufreq_register_driver(&acpi_cpufreq_driver); 484 + } 485 + 486 + 487 + static void __exit 488 + acpi_cpufreq_exit (void) 489 + { 490 + dprintk("acpi_cpufreq_exit\n"); 491 + 492 + cpufreq_unregister_driver(&acpi_cpufreq_driver); 493 + return; 494 + } 495 + 496 + 497 + late_initcall(acpi_cpufreq_init); 498 + module_exit(acpi_cpufreq_exit); 499 +
+5
include/asm-ia64/acpi.h
··· 116 116 117 117 extern u16 ia64_acpiid_to_sapicid[]; 118 118 119 + /* 120 + * Refer Intel ACPI _PDC support document for bit definitions 121 + */ 122 + #define ACPI_PDC_EST_CAPABILITY_SMP 0x8 123 + 119 124 #endif /*__KERNEL__*/ 120 125 121 126 #endif /*_ASM_ACPI_H*/
+21
include/asm-ia64/pal.h
··· 75 75 #define PAL_CACHE_READ 259 /* read tag & data of cacheline for diagnostic testing */ 76 76 #define PAL_CACHE_WRITE 260 /* write tag & data of cacheline for diagnostic testing */ 77 77 #define PAL_VM_TR_READ 261 /* read contents of translation register */ 78 + #define PAL_GET_PSTATE 262 /* get the current P-state */ 79 + #define PAL_SET_PSTATE 263 /* set the P-state */ 78 80 79 81 #ifndef __ASSEMBLY__ 80 82 ··· 1110 1108 { 1111 1109 struct ia64_pal_retval iprv; 1112 1110 PAL_CALL_STK(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0); 1111 + return iprv.status; 1112 + } 1113 + 1114 + /* Get the current P-state information */ 1115 + static inline s64 1116 + ia64_pal_get_pstate (u64 *pstate_index) 1117 + { 1118 + struct ia64_pal_retval iprv; 1119 + PAL_CALL_STK(iprv, PAL_GET_PSTATE, 0, 0, 0); 1120 + *pstate_index = iprv.v0; 1121 + return iprv.status; 1122 + } 1123 + 1124 + /* Set the P-state */ 1125 + static inline s64 1126 + ia64_pal_set_pstate (u64 pstate_index) 1127 + { 1128 + struct ia64_pal_retval iprv; 1129 + PAL_CALL_STK(iprv, PAL_SET_PSTATE, pstate_index, 0, 0); 1113 1130 return iprv.status; 1114 1131 } 1115 1132