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 /arch/ia64/kernel | |
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>
Diffstat (limited to 'arch/ia64/kernel')
-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 |
3 files changed, 72 insertions, 51 deletions
diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile index f748d34c02f..642648361ed 100644 --- a/arch/ia64/kernel/cpufreq/Makefile +++ b/arch/ia64/kernel/cpufreq/Makefile @@ -1 +1,6 @@ obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += acpi-processor.o +endif + diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index da4d5cf80a4..5a1bf815282 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c @@ -269,48 +269,6 @@ acpi_cpufreq_verify ( } -/* - * processor_init_pdc - let BIOS know about the SMP capabilities - * of this driver - * @perf: processor-specific acpi_io_data struct - * @cpu: CPU being initialized - * - * To avoid issues with legacy OSes, some BIOSes require to be informed of - * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC - * accordingly. Actual call to _PDC is done in driver/acpi/processor.c - */ -static void -processor_init_pdc ( - struct acpi_processor_performance *perf, - unsigned int cpu, - struct acpi_object_list *obj_list - ) -{ - union acpi_object *obj; - u32 *buf; - - dprintk("processor_init_pdc\n"); - - perf->pdc = NULL; - /* Initialize pdc. It will be used later. */ - if (!obj_list) - return; - - if (!(obj_list->count && obj_list->pointer)) - return; - - obj = obj_list->pointer; - if ((obj->buffer.length == 12) && obj->buffer.pointer) { - buf = (u32 *)obj->buffer.pointer; - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; - perf->pdc = obj_list; - } - return; -} - - static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -320,14 +278,7 @@ acpi_cpufreq_cpu_init ( struct cpufreq_acpi_io *data; unsigned int result = 0; - union acpi_object arg0 = {ACPI_TYPE_BUFFER}; - u32 arg0_buf[3]; - struct acpi_object_list arg_list = {1, &arg0}; - dprintk("acpi_cpufreq_cpu_init\n"); - /* setup arg_list for _PDC settings */ - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -337,9 +288,7 @@ acpi_cpufreq_cpu_init ( acpi_io_data[cpu] = data; - processor_init_pdc(&data->acpi_data, cpu, &arg_list); result = acpi_processor_register_performance(&data->acpi_data, cpu); - data->acpi_data.pdc = NULL; if (result) 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 00000000000..e683630c8ce --- /dev/null +++ b/arch/ia64/kernel/cpufreq/acpi-processor.c @@ -0,0 +1,67 @@ +/* + * arch/ia64/kernel/cpufreq/processor.c + * + * Copyright (C) 2005 Intel Corporation + * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> + * - Added _PDC for platforms with Intel CPUs + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/acpi.h> + +#include <acpi/processor.h> +#include <asm/acpi.h> + +static void init_intel_pdc(struct acpi_processor *pr) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) { + printk(KERN_ERR "Memory allocation error\n"); + return; + } + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj_list); + return; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj); + kfree(obj_list); + return; + } + + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + pr->pdc = obj_list; + + return; +} + +/* Initialize _PDC data based on the CPU vendor */ +void arch_acpi_processor_init_pdc(struct acpi_processor *pr) +{ + pr->pdc = NULL; + init_intel_pdc(pr); + return; +} + +EXPORT_SYMBOL(arch_acpi_processor_init_pdc); |