diff options
| author | Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | 2005-10-23 16:31:00 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2005-12-01 01:30:35 -0500 |
| commit | 05131ecc99ea9da7f45ba3058fe8a2c1d0ceeab8 (patch) | |
| tree | dec76975406874cf677d6391302f42a6da55ac38 | |
| parent | d2149b542382bfc206cb28485108f6470c979566 (diff) | |
[ACPI] Avoid BIOS inflicted crashes by evaluating _PDC only once
Linux invokes the AML _PDC method (Processor Driver Capabilities)
to tell the BIOS what features it can handle. While the ACPI
spec says nothing about the OS invoking _PDC multiple times,
doing so with changing bits seems to hopelessly confuse the BIOS
on multiple platforms up to and including crashing the system.
Factor out the _PDC invocation so Linux invokes it only once.
http://bugzilla.kernel.org/show_bug.cgi?id=5483
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | arch/i386/kernel/acpi/Makefile | 2 | ||||
| -rw-r--r-- | arch/i386/kernel/acpi/cstate.c | 58 | ||||
| -rw-r--r-- | arch/i386/kernel/acpi/processor.c | 75 | ||||
| -rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 67 | ||||
| -rw-r--r-- | arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 12 | ||||
| -rw-r--r-- | arch/ia64/kernel/cpufreq/Makefile | 5 | ||||
| -rw-r--r-- | arch/ia64/kernel/cpufreq/acpi-cpufreq.c | 51 | ||||
| -rw-r--r-- | arch/ia64/kernel/cpufreq/acpi-processor.c | 67 | ||||
| -rw-r--r-- | arch/x86_64/kernel/acpi/Makefile | 5 | ||||
| -rw-r--r-- | arch/x86_64/kernel/acpi/processor.c | 72 | ||||
| -rw-r--r-- | drivers/acpi/processor_core.c | 28 | ||||
| -rw-r--r-- | drivers/acpi/processor_idle.c | 2 | ||||
| -rw-r--r-- | drivers/acpi/processor_perflib.c | 2 | ||||
| -rw-r--r-- | include/acpi/pdc_intel.h | 4 | ||||
| -rw-r--r-- | include/acpi/processor.h | 22 | ||||
| -rw-r--r-- | include/asm-i386/acpi.h | 2 |
16 files changed, 243 insertions, 231 deletions
diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index 267ca48e1b6c..d51c7313cae8 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile | |||
| @@ -3,6 +3,6 @@ obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o | |||
| 3 | obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o | 3 | obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o |
| 4 | 4 | ||
| 5 | ifneq ($(CONFIG_ACPI_PROCESSOR),) | 5 | ifneq ($(CONFIG_ACPI_PROCESSOR),) |
| 6 | obj-y += cstate.o | 6 | obj-y += cstate.o processor.o |
| 7 | endif | 7 | endif |
| 8 | 8 | ||
diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c index 4c3036ba65df..25db49ef1770 100644 --- a/arch/i386/kernel/acpi/cstate.c +++ b/arch/i386/kernel/acpi/cstate.c | |||
| @@ -14,64 +14,6 @@ | |||
| 14 | #include <acpi/processor.h> | 14 | #include <acpi/processor.h> |
| 15 | #include <asm/acpi.h> | 15 | #include <asm/acpi.h> |
| 16 | 16 | ||
| 17 | static void acpi_processor_power_init_intel_pdc(struct acpi_processor_power | ||
| 18 | *pow) | ||
| 19 | { | ||
| 20 | struct acpi_object_list *obj_list; | ||
| 21 | union acpi_object *obj; | ||
| 22 | u32 *buf; | ||
| 23 | |||
| 24 | /* allocate and initialize pdc. It will be used later. */ | ||
| 25 | obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); | ||
| 26 | if (!obj_list) { | ||
| 27 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); | ||
| 32 | if (!obj) { | ||
| 33 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 34 | kfree(obj_list); | ||
| 35 | return; | ||
| 36 | } | ||
| 37 | |||
| 38 | buf = kmalloc(12, GFP_KERNEL); | ||
| 39 | if (!buf) { | ||
| 40 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 41 | kfree(obj); | ||
| 42 | kfree(obj_list); | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | buf[0] = ACPI_PDC_REVISION_ID; | ||
| 47 | buf[1] = 1; | ||
| 48 | buf[2] = ACPI_PDC_C_CAPABILITY_SMP; | ||
| 49 | |||
| 50 | obj->type = ACPI_TYPE_BUFFER; | ||
| 51 | obj->buffer.length = 12; | ||
| 52 | obj->buffer.pointer = (u8 *) buf; | ||
| 53 | obj_list->count = 1; | ||
| 54 | obj_list->pointer = obj; | ||
| 55 | pow->pdc = obj_list; | ||
| 56 | |||
| 57 | return; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* Initialize _PDC data based on the CPU vendor */ | ||
| 61 | void acpi_processor_power_init_pdc(struct acpi_processor_power *pow, | ||
| 62 | unsigned int cpu) | ||
| 63 | { | ||
| 64 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
| 65 | |||
| 66 | pow->pdc = NULL; | ||
| 67 | if (c->x86_vendor == X86_VENDOR_INTEL) | ||
| 68 | acpi_processor_power_init_intel_pdc(pow); | ||
| 69 | |||
| 70 | return; | ||
| 71 | } | ||
| 72 | |||
| 73 | EXPORT_SYMBOL(acpi_processor_power_init_pdc); | ||
| 74 | |||
| 75 | /* | 17 | /* |
| 76 | * Initialize bm_flags based on the CPU cache properties | 18 | * Initialize bm_flags based on the CPU cache properties |
| 77 | * On SMP it depends on cache configuration | 19 | * On SMP it depends on cache configuration |
diff --git a/arch/i386/kernel/acpi/processor.c b/arch/i386/kernel/acpi/processor.c new file mode 100644 index 000000000000..9f4cc02717ec --- /dev/null +++ b/arch/i386/kernel/acpi/processor.c | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* | ||
| 2 | * arch/i386/kernel/acpi/processor.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Intel Corporation | ||
| 5 | * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | ||
| 6 | * - Added _PDC for platforms with Intel CPUs | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/acpi.h> | ||
| 13 | |||
| 14 | #include <acpi/processor.h> | ||
| 15 | #include <asm/acpi.h> | ||
| 16 | |||
| 17 | static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) | ||
| 18 | { | ||
| 19 | struct acpi_object_list *obj_list; | ||
| 20 | union acpi_object *obj; | ||
| 21 | u32 *buf; | ||
| 22 | |||
| 23 | /* allocate and initialize pdc. It will be used later. */ | ||
| 24 | obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); | ||
| 25 | if (!obj_list) { | ||
| 26 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); | ||
| 31 | if (!obj) { | ||
| 32 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 33 | kfree(obj_list); | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 37 | buf = kmalloc(12, GFP_KERNEL); | ||
| 38 | if (!buf) { | ||
| 39 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 40 | kfree(obj); | ||
| 41 | kfree(obj_list); | ||
| 42 | return; | ||
| 43 | } | ||
| 44 | |||
| 45 | buf[0] = ACPI_PDC_REVISION_ID; | ||
| 46 | buf[1] = 1; | ||
| 47 | buf[2] = ACPI_PDC_C_CAPABILITY_SMP; | ||
| 48 | |||
| 49 | if (cpu_has(c, X86_FEATURE_EST)) | ||
| 50 | buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; | ||
| 51 | |||
| 52 | obj->type = ACPI_TYPE_BUFFER; | ||
| 53 | obj->buffer.length = 12; | ||
| 54 | obj->buffer.pointer = (u8 *) buf; | ||
| 55 | obj_list->count = 1; | ||
| 56 | obj_list->pointer = obj; | ||
| 57 | pr->pdc = obj_list; | ||
| 58 | |||
| 59 | return; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* Initialize _PDC data based on the CPU vendor */ | ||
| 63 | void arch_acpi_processor_init_pdc(struct acpi_processor *pr) | ||
| 64 | { | ||
| 65 | unsigned int cpu = pr->id; | ||
| 66 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
| 67 | |||
| 68 | pr->pdc = NULL; | ||
| 69 | if (c->x86_vendor == X86_VENDOR_INTEL) | ||
| 70 | init_intel_pdc(pr, c); | ||
| 71 | |||
| 72 | return; | ||
| 73 | } | ||
| 74 | |||
| 75 | EXPORT_SYMBOL(arch_acpi_processor_init_pdc); | ||
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 871366b83b3f..31ce890865d5 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
| @@ -297,68 +297,6 @@ acpi_cpufreq_guess_freq ( | |||
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | 299 | ||
| 300 | /* | ||
| 301 | * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities | ||
| 302 | * of this driver | ||
| 303 | * @perf: processor-specific acpi_io_data struct | ||
| 304 | * @cpu: CPU being initialized | ||
| 305 | * | ||
| 306 | * To avoid issues with legacy OSes, some BIOSes require to be informed of | ||
| 307 | * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC | ||
| 308 | * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in | ||
| 309 | * driver/acpi/processor.c | ||
| 310 | */ | ||
| 311 | static void | ||
| 312 | acpi_processor_cpu_init_pdc_est( | ||
| 313 | struct acpi_processor_performance *perf, | ||
| 314 | unsigned int cpu, | ||
| 315 | struct acpi_object_list *obj_list | ||
| 316 | ) | ||
| 317 | { | ||
| 318 | union acpi_object *obj; | ||
| 319 | u32 *buf; | ||
| 320 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
| 321 | dprintk("acpi_processor_cpu_init_pdc_est\n"); | ||
| 322 | |||
| 323 | if (!cpu_has(c, X86_FEATURE_EST)) | ||
| 324 | return; | ||
| 325 | |||
| 326 | /* Initialize pdc. It will be used later. */ | ||
| 327 | if (!obj_list) | ||
| 328 | return; | ||
| 329 | |||
| 330 | if (!(obj_list->count && obj_list->pointer)) | ||
| 331 | return; | ||
| 332 | |||
| 333 | obj = obj_list->pointer; | ||
| 334 | if ((obj->buffer.length == 12) && obj->buffer.pointer) { | ||
| 335 | buf = (u32 *)obj->buffer.pointer; | ||
| 336 | buf[0] = ACPI_PDC_REVISION_ID; | ||
| 337 | buf[1] = 1; | ||
| 338 | buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; | ||
| 339 | perf->pdc = obj_list; | ||
| 340 | } | ||
| 341 | return; | ||
| 342 | } | ||
| 343 | |||
| 344 | |||
| 345 | /* CPU specific PDC initialization */ | ||
| 346 | static void | ||
| 347 | acpi_processor_cpu_init_pdc( | ||
| 348 | struct acpi_processor_performance *perf, | ||
| 349 | unsigned int cpu, | ||
| 350 | struct acpi_object_list *obj_list | ||
| 351 | ) | ||
| 352 | { | ||
| 353 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
| 354 | dprintk("acpi_processor_cpu_init_pdc\n"); | ||
| 355 | perf->pdc = NULL; | ||
| 356 | if (cpu_has(c, X86_FEATURE_EST)) | ||
| 357 | acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list); | ||
| 358 | return; | ||
| 359 | } | ||
| 360 | |||
| 361 | |||
| 362 | static int | 300 | static int |
| 363 | acpi_cpufreq_cpu_init ( | 301 | acpi_cpufreq_cpu_init ( |
| 364 | struct cpufreq_policy *policy) | 302 | struct cpufreq_policy *policy) |
| @@ -373,9 +311,6 @@ acpi_cpufreq_cpu_init ( | |||
| 373 | struct acpi_object_list arg_list = {1, &arg0}; | 311 | struct acpi_object_list arg_list = {1, &arg0}; |
| 374 | 312 | ||
| 375 | dprintk("acpi_cpufreq_cpu_init\n"); | 313 | dprintk("acpi_cpufreq_cpu_init\n"); |
| 376 | /* setup arg_list for _PDC settings */ | ||
| 377 | arg0.buffer.length = 12; | ||
| 378 | arg0.buffer.pointer = (u8 *) arg0_buf; | ||
| 379 | 314 | ||
| 380 | data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); | 315 | data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); |
| 381 | if (!data) | 316 | if (!data) |
| @@ -383,9 +318,7 @@ acpi_cpufreq_cpu_init ( | |||
| 383 | 318 | ||
| 384 | acpi_io_data[cpu] = data; | 319 | acpi_io_data[cpu] = data; |
| 385 | 320 | ||
| 386 | acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list); | ||
| 387 | result = acpi_processor_register_performance(&data->acpi_data, cpu); | 321 | result = acpi_processor_register_performance(&data->acpi_data, cpu); |
| 388 | data->acpi_data.pdc = NULL; | ||
| 389 | 322 | ||
| 390 | if (result) | 323 | if (result) |
| 391 | goto err_free; | 324 | goto err_free; |
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index edb9873e27e3..d93023438c4f 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | |||
| @@ -364,22 +364,10 @@ static struct acpi_processor_performance p; | |||
| 364 | */ | 364 | */ |
| 365 | static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) | 365 | static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) |
| 366 | { | 366 | { |
| 367 | union acpi_object arg0 = {ACPI_TYPE_BUFFER}; | ||
| 368 | u32 arg0_buf[3]; | ||
| 369 | struct acpi_object_list arg_list = {1, &arg0}; | ||
| 370 | unsigned long cur_freq; | 367 | unsigned long cur_freq; |
| 371 | int result = 0, i; | 368 | int result = 0, i; |
| 372 | unsigned int cpu = policy->cpu; | 369 | unsigned int cpu = policy->cpu; |
| 373 | 370 | ||
| 374 | /* _PDC settings */ | ||
| 375 | arg0.buffer.length = 12; | ||
| 376 | arg0.buffer.pointer = (u8 *) arg0_buf; | ||
| 377 | arg0_buf[0] = ACPI_PDC_REVISION_ID; | ||
| 378 | arg0_buf[1] = 1; | ||
| 379 | arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP_MSR; | ||
| 380 | |||
| 381 | p.pdc = &arg_list; | ||
| 382 | |||
| 383 | /* register with ACPI core */ | 371 | /* register with ACPI core */ |
| 384 | if (acpi_processor_register_performance(&p, cpu)) { | 372 | if (acpi_processor_register_performance(&p, cpu)) { |
| 385 | dprintk(KERN_INFO PFX "obtaining ACPI data failed\n"); | 373 | dprintk(KERN_INFO PFX "obtaining ACPI data failed\n"); |
diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile index f748d34c02f0..642648361ed3 100644 --- a/arch/ia64/kernel/cpufreq/Makefile +++ b/arch/ia64/kernel/cpufreq/Makefile | |||
| @@ -1 +1,6 @@ | |||
| 1 | obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o | 1 | obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o |
| 2 | |||
| 3 | ifneq ($(CONFIG_ACPI_PROCESSOR),) | ||
| 4 | obj-y += acpi-processor.o | ||
| 5 | endif | ||
| 6 | |||
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index da4d5cf80a48..5a1bf815282d 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c | |||
| @@ -269,48 +269,6 @@ acpi_cpufreq_verify ( | |||
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | 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 | 272 | static int |
| 315 | acpi_cpufreq_cpu_init ( | 273 | acpi_cpufreq_cpu_init ( |
| 316 | struct cpufreq_policy *policy) | 274 | struct cpufreq_policy *policy) |
| @@ -320,14 +278,7 @@ acpi_cpufreq_cpu_init ( | |||
| 320 | struct cpufreq_acpi_io *data; | 278 | struct cpufreq_acpi_io *data; |
| 321 | unsigned int result = 0; | 279 | unsigned int result = 0; |
| 322 | 280 | ||
| 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"); | 281 | 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 | 282 | ||
| 332 | data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); | 283 | data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); |
| 333 | if (!data) | 284 | if (!data) |
| @@ -337,9 +288,7 @@ acpi_cpufreq_cpu_init ( | |||
| 337 | 288 | ||
| 338 | acpi_io_data[cpu] = data; | 289 | acpi_io_data[cpu] = data; |
| 339 | 290 | ||
| 340 | processor_init_pdc(&data->acpi_data, cpu, &arg_list); | ||
| 341 | result = acpi_processor_register_performance(&data->acpi_data, cpu); | 291 | result = acpi_processor_register_performance(&data->acpi_data, cpu); |
| 342 | data->acpi_data.pdc = NULL; | ||
| 343 | 292 | ||
| 344 | if (result) | 293 | if (result) |
| 345 | goto err_free; | 294 | goto err_free; |
diff --git a/arch/ia64/kernel/cpufreq/acpi-processor.c b/arch/ia64/kernel/cpufreq/acpi-processor.c new file mode 100644 index 000000000000..e683630c8ce2 --- /dev/null +++ b/arch/ia64/kernel/cpufreq/acpi-processor.c | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * arch/ia64/kernel/cpufreq/processor.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Intel Corporation | ||
| 5 | * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | ||
| 6 | * - Added _PDC for platforms with Intel CPUs | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/acpi.h> | ||
| 13 | |||
| 14 | #include <acpi/processor.h> | ||
| 15 | #include <asm/acpi.h> | ||
| 16 | |||
| 17 | static void init_intel_pdc(struct acpi_processor *pr) | ||
| 18 | { | ||
| 19 | struct acpi_object_list *obj_list; | ||
| 20 | union acpi_object *obj; | ||
| 21 | u32 *buf; | ||
| 22 | |||
| 23 | /* allocate and initialize pdc. It will be used later. */ | ||
| 24 | obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); | ||
| 25 | if (!obj_list) { | ||
| 26 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); | ||
| 31 | if (!obj) { | ||
| 32 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 33 | kfree(obj_list); | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 37 | buf = kmalloc(12, GFP_KERNEL); | ||
| 38 | if (!buf) { | ||
| 39 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 40 | kfree(obj); | ||
| 41 | kfree(obj_list); | ||
| 42 | return; | ||
| 43 | } | ||
| 44 | |||
| 45 | buf[0] = ACPI_PDC_REVISION_ID; | ||
| 46 | buf[1] = 1; | ||
| 47 | buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; | ||
| 48 | |||
| 49 | obj->type = ACPI_TYPE_BUFFER; | ||
| 50 | obj->buffer.length = 12; | ||
| 51 | obj->buffer.pointer = (u8 *) buf; | ||
| 52 | obj_list->count = 1; | ||
| 53 | obj_list->pointer = obj; | ||
| 54 | pr->pdc = obj_list; | ||
| 55 | |||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* Initialize _PDC data based on the CPU vendor */ | ||
| 60 | void arch_acpi_processor_init_pdc(struct acpi_processor *pr) | ||
| 61 | { | ||
| 62 | pr->pdc = NULL; | ||
| 63 | init_intel_pdc(pr); | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | |||
| 67 | EXPORT_SYMBOL(arch_acpi_processor_init_pdc); | ||
diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index 7da9ace890bd..4fe97071f297 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | obj-y := boot.o | 1 | obj-y := boot.o |
| 2 | boot-y := ../../../i386/kernel/acpi/boot.o | 2 | boot-y := ../../../i386/kernel/acpi/boot.o |
| 3 | obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o | 3 | obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o |
| 4 | |||
| 5 | ifneq ($(CONFIG_ACPI_PROCESSOR),) | ||
| 6 | obj-y += processor.o | ||
| 7 | endif | ||
| 8 | |||
diff --git a/arch/x86_64/kernel/acpi/processor.c b/arch/x86_64/kernel/acpi/processor.c new file mode 100644 index 000000000000..3bdc2baa5bb1 --- /dev/null +++ b/arch/x86_64/kernel/acpi/processor.c | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | /* | ||
| 2 | * arch/x86_64/kernel/acpi/processor.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Intel Corporation | ||
| 5 | * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | ||
| 6 | * - Added _PDC for platforms with Intel CPUs | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/acpi.h> | ||
| 13 | |||
| 14 | #include <acpi/processor.h> | ||
| 15 | #include <asm/acpi.h> | ||
| 16 | |||
| 17 | static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) | ||
| 18 | { | ||
| 19 | struct acpi_object_list *obj_list; | ||
| 20 | union acpi_object *obj; | ||
| 21 | u32 *buf; | ||
| 22 | |||
| 23 | /* allocate and initialize pdc. It will be used later. */ | ||
| 24 | obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); | ||
| 25 | if (!obj_list) { | ||
| 26 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); | ||
| 31 | if (!obj) { | ||
| 32 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 33 | kfree(obj_list); | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 37 | buf = kmalloc(12, GFP_KERNEL); | ||
| 38 | if (!buf) { | ||
| 39 | printk(KERN_ERR "Memory allocation error\n"); | ||
| 40 | kfree(obj); | ||
| 41 | kfree(obj_list); | ||
| 42 | return; | ||
| 43 | } | ||
| 44 | |||
| 45 | buf[0] = ACPI_PDC_REVISION_ID; | ||
| 46 | buf[1] = 1; | ||
| 47 | buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; | ||
| 48 | |||
| 49 | obj->type = ACPI_TYPE_BUFFER; | ||
| 50 | obj->buffer.length = 12; | ||
| 51 | obj->buffer.pointer = (u8 *) buf; | ||
| 52 | obj_list->count = 1; | ||
| 53 | obj_list->pointer = obj; | ||
| 54 | pr->pdc = obj_list; | ||
| 55 | |||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* Initialize _PDC data based on the CPU vendor */ | ||
| 60 | void arch_acpi_processor_init_pdc(struct acpi_processor *pr) | ||
| 61 | { | ||
| 62 | unsigned int cpu = pr->id; | ||
| 63 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
| 64 | |||
| 65 | pr->pdc = NULL; | ||
| 66 | if (c->x86_vendor == X86_VENDOR_INTEL && cpu_has(c, X86_FEATURE_EST)) | ||
| 67 | init_intel_pdc(pr, c); | ||
| 68 | |||
| 69 | return; | ||
| 70 | } | ||
| 71 | |||
| 72 | EXPORT_SYMBOL(arch_acpi_processor_init_pdc); | ||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 421792562642..66bbda78507a 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
| @@ -253,31 +253,21 @@ static int acpi_processor_errata(struct acpi_processor *pr) | |||
| 253 | * _PDC is required for a BIOS-OS handshake for most of the newer | 253 | * _PDC is required for a BIOS-OS handshake for most of the newer |
| 254 | * ACPI processor features. | 254 | * ACPI processor features. |
| 255 | */ | 255 | */ |
| 256 | 256 | static int acpi_processor_set_pdc(struct acpi_processor *pr) | |
| 257 | int acpi_processor_set_pdc(struct acpi_processor *pr, | ||
| 258 | struct acpi_object_list *pdc_in) | ||
| 259 | { | 257 | { |
| 258 | struct acpi_object_list *pdc_in = pr->pdc; | ||
| 260 | acpi_status status = AE_OK; | 259 | acpi_status status = AE_OK; |
| 261 | u32 arg0_buf[3]; | ||
| 262 | union acpi_object arg0 = { ACPI_TYPE_BUFFER }; | ||
| 263 | struct acpi_object_list no_object = { 1, &arg0 }; | ||
| 264 | struct acpi_object_list *pdc; | ||
| 265 | 260 | ||
| 266 | ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); | 261 | ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); |
| 267 | 262 | ||
| 268 | arg0.buffer.length = 12; | 263 | if (!pdc_in) |
| 269 | arg0.buffer.pointer = (u8 *) arg0_buf; | 264 | return_VALUE(status); |
| 270 | arg0_buf[0] = ACPI_PDC_REVISION_ID; | ||
| 271 | arg0_buf[1] = 0; | ||
| 272 | arg0_buf[2] = 0; | ||
| 273 | |||
| 274 | pdc = (pdc_in) ? pdc_in : &no_object; | ||
| 275 | 265 | ||
| 276 | status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); | 266 | status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL); |
| 277 | 267 | ||
| 278 | if ((ACPI_FAILURE(status)) && (pdc_in)) | 268 | if (ACPI_FAILURE(status)) |
| 279 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 269 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
| 280 | "Error evaluating _PDC, using legacy perf. control...\n")); | 270 | "Could not evaluate _PDC, using legacy perf. control...\n")); |
| 281 | 271 | ||
| 282 | return_VALUE(status); | 272 | return_VALUE(status); |
| 283 | } | 273 | } |
| @@ -574,6 +564,10 @@ static int acpi_processor_start(struct acpi_device *device) | |||
| 574 | "Error installing device notify handler\n")); | 564 | "Error installing device notify handler\n")); |
| 575 | } | 565 | } |
| 576 | 566 | ||
| 567 | /* _PDC call should be done before doing anything else (if reqd.). */ | ||
| 568 | arch_acpi_processor_init_pdc(pr); | ||
| 569 | acpi_processor_set_pdc(pr); | ||
| 570 | |||
| 577 | acpi_processor_power_init(pr, device); | 571 | acpi_processor_power_init(pr, device); |
| 578 | 572 | ||
| 579 | if (pr->flags.throttling) { | 573 | if (pr->flags.throttling) { |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 70d8a6ec0920..1915c377bfc6 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -1014,8 +1014,6 @@ int acpi_processor_power_init(struct acpi_processor *pr, | |||
| 1014 | } | 1014 | } |
| 1015 | } | 1015 | } |
| 1016 | 1016 | ||
| 1017 | acpi_processor_power_init_pdc(&(pr->power), pr->id); | ||
| 1018 | acpi_processor_set_pdc(pr, pr->power.pdc); | ||
| 1019 | acpi_processor_get_power_info(pr); | 1017 | acpi_processor_get_power_info(pr); |
| 1020 | 1018 | ||
| 1021 | /* | 1019 | /* |
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 22c7bb66c200..532370734c68 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
| @@ -315,8 +315,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) | |||
| 315 | if (!pr || !pr->performance || !pr->handle) | 315 | if (!pr || !pr->performance || !pr->handle) |
| 316 | return_VALUE(-EINVAL); | 316 | return_VALUE(-EINVAL); |
| 317 | 317 | ||
| 318 | acpi_processor_set_pdc(pr, pr->performance->pdc); | ||
| 319 | |||
| 320 | status = acpi_get_handle(pr->handle, "_PCT", &handle); | 318 | status = acpi_get_handle(pr->handle, "_PCT", &handle); |
| 321 | if (ACPI_FAILURE(status)) { | 319 | if (ACPI_FAILURE(status)) { |
| 322 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 320 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h index 91f4a12a99a1..3fa81d55cd0c 100644 --- a/include/acpi/pdc_intel.h +++ b/include/acpi/pdc_intel.h | |||
| @@ -15,9 +15,7 @@ | |||
| 15 | #define ACPI_PDC_C_C1_FFH (0x0100) | 15 | #define ACPI_PDC_C_C1_FFH (0x0100) |
| 16 | 16 | ||
| 17 | #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ | 17 | #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ |
| 18 | ACPI_PDC_C_C1_HALT) | 18 | ACPI_PDC_C_C1_HALT | \ |
| 19 | |||
| 20 | #define ACPI_PDC_EST_CAPABILITY_SMP_MSR (ACPI_PDC_EST_CAPABILITY_SMP | \ | ||
| 21 | ACPI_PDC_P_FFH) | 19 | ACPI_PDC_P_FFH) |
| 22 | 20 | ||
| 23 | #define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ | 21 | #define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ |
diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 7a00d5089de9..82a9b7d430ec 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h | |||
| @@ -62,9 +62,6 @@ struct acpi_processor_power { | |||
| 62 | u32 bm_activity; | 62 | u32 bm_activity; |
| 63 | int count; | 63 | int count; |
| 64 | struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; | 64 | struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; |
| 65 | |||
| 66 | /* the _PDC objects passed by the driver, if any */ | ||
| 67 | struct acpi_object_list *pdc; | ||
| 68 | }; | 65 | }; |
| 69 | 66 | ||
| 70 | /* Performance Management */ | 67 | /* Performance Management */ |
| @@ -96,8 +93,6 @@ struct acpi_processor_performance { | |||
| 96 | unsigned int state_count; | 93 | unsigned int state_count; |
| 97 | struct acpi_processor_px *states; | 94 | struct acpi_processor_px *states; |
| 98 | 95 | ||
| 99 | /* the _PDC objects passed by the driver, if any */ | ||
| 100 | struct acpi_object_list *pdc; | ||
| 101 | }; | 96 | }; |
| 102 | 97 | ||
| 103 | /* Throttling Control */ | 98 | /* Throttling Control */ |
| @@ -151,6 +146,9 @@ struct acpi_processor { | |||
| 151 | struct acpi_processor_performance *performance; | 146 | struct acpi_processor_performance *performance; |
| 152 | struct acpi_processor_throttling throttling; | 147 | struct acpi_processor_throttling throttling; |
| 153 | struct acpi_processor_limit limit; | 148 | struct acpi_processor_limit limit; |
| 149 | |||
| 150 | /* the _PDC objects for this processor, if any */ | ||
| 151 | struct acpi_object_list *pdc; | ||
| 154 | }; | 152 | }; |
| 155 | 153 | ||
| 156 | struct acpi_processor_errata { | 154 | struct acpi_processor_errata { |
| @@ -178,22 +176,12 @@ int acpi_processor_notify_smm(struct module *calling_module); | |||
| 178 | extern struct acpi_processor *processors[NR_CPUS]; | 176 | extern struct acpi_processor *processors[NR_CPUS]; |
| 179 | extern struct acpi_processor_errata errata; | 177 | extern struct acpi_processor_errata errata; |
| 180 | 178 | ||
| 181 | int acpi_processor_set_pdc(struct acpi_processor *pr, | 179 | void arch_acpi_processor_init_pdc(struct acpi_processor *pr); |
| 182 | struct acpi_object_list *pdc_in); | ||
| 183 | 180 | ||
| 184 | #ifdef ARCH_HAS_POWER_PDC_INIT | 181 | #ifdef ARCH_HAS_POWER_INIT |
| 185 | void acpi_processor_power_init_pdc(struct acpi_processor_power *pow, | ||
| 186 | unsigned int cpu); | ||
| 187 | void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, | 182 | void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, |
| 188 | unsigned int cpu); | 183 | unsigned int cpu); |
| 189 | #else | 184 | #else |
| 190 | static inline void acpi_processor_power_init_pdc(struct acpi_processor_power | ||
| 191 | *pow, unsigned int cpu) | ||
| 192 | { | ||
| 193 | pow->pdc = NULL; | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | static inline void acpi_processor_power_init_bm_check(struct | 185 | static inline void acpi_processor_power_init_bm_check(struct |
| 198 | acpi_processor_flags | 186 | acpi_processor_flags |
| 199 | *flags, unsigned int cpu) | 187 | *flags, unsigned int cpu) |
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index df4ed323aa4d..55059abf9c95 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h | |||
| @@ -179,7 +179,7 @@ extern void acpi_reserve_bootmem(void); | |||
| 179 | 179 | ||
| 180 | extern u8 x86_acpiid_to_apicid[]; | 180 | extern u8 x86_acpiid_to_apicid[]; |
| 181 | 181 | ||
| 182 | #define ARCH_HAS_POWER_PDC_INIT 1 | 182 | #define ARCH_HAS_POWER_INIT 1 |
| 183 | 183 | ||
| 184 | #endif /*__KERNEL__*/ | 184 | #endif /*__KERNEL__*/ |
| 185 | 185 | ||
