[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>
This commit is contained in:
parent
d2149b5423
commit
05131ecc99
|
@ -3,6 +3,6 @@ obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
|
||||||
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
|
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
|
||||||
|
|
||||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||||
obj-y += cstate.o
|
obj-y += cstate.o processor.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -14,64 +14,6 @@
|
||||||
#include <acpi/processor.h>
|
#include <acpi/processor.h>
|
||||||
#include <asm/acpi.h>
|
#include <asm/acpi.h>
|
||||||
|
|
||||||
static void acpi_processor_power_init_intel_pdc(struct acpi_processor_power
|
|
||||||
*pow)
|
|
||||||
{
|
|
||||||
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_C_CAPABILITY_SMP;
|
|
||||||
|
|
||||||
obj->type = ACPI_TYPE_BUFFER;
|
|
||||||
obj->buffer.length = 12;
|
|
||||||
obj->buffer.pointer = (u8 *) buf;
|
|
||||||
obj_list->count = 1;
|
|
||||||
obj_list->pointer = obj;
|
|
||||||
pow->pdc = obj_list;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize _PDC data based on the CPU vendor */
|
|
||||||
void acpi_processor_power_init_pdc(struct acpi_processor_power *pow,
|
|
||||||
unsigned int cpu)
|
|
||||||
{
|
|
||||||
struct cpuinfo_x86 *c = cpu_data + cpu;
|
|
||||||
|
|
||||||
pow->pdc = NULL;
|
|
||||||
if (c->x86_vendor == X86_VENDOR_INTEL)
|
|
||||||
acpi_processor_power_init_intel_pdc(pow);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(acpi_processor_power_init_pdc);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize bm_flags based on the CPU cache properties
|
* Initialize bm_flags based on the CPU cache properties
|
||||||
* On SMP it depends on cache configuration
|
* On SMP it depends on cache configuration
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* arch/i386/kernel/acpi/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 cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
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_C_CAPABILITY_SMP;
|
||||||
|
|
||||||
|
if (cpu_has(c, X86_FEATURE_EST))
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
unsigned int cpu = pr->id;
|
||||||
|
struct cpuinfo_x86 *c = cpu_data + cpu;
|
||||||
|
|
||||||
|
pr->pdc = NULL;
|
||||||
|
if (c->x86_vendor == X86_VENDOR_INTEL)
|
||||||
|
init_intel_pdc(pr, c);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
|
|
@ -297,68 +297,6 @@ acpi_cpufreq_guess_freq (
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* acpi_processor_cpu_init_pdc_est - 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, for Enhanced Speedstep. Actual call to _PDC is done in
|
|
||||||
* driver/acpi/processor.c
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
acpi_processor_cpu_init_pdc_est(
|
|
||||||
struct acpi_processor_performance *perf,
|
|
||||||
unsigned int cpu,
|
|
||||||
struct acpi_object_list *obj_list
|
|
||||||
)
|
|
||||||
{
|
|
||||||
union acpi_object *obj;
|
|
||||||
u32 *buf;
|
|
||||||
struct cpuinfo_x86 *c = cpu_data + cpu;
|
|
||||||
dprintk("acpi_processor_cpu_init_pdc_est\n");
|
|
||||||
|
|
||||||
if (!cpu_has(c, X86_FEATURE_EST))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* CPU specific PDC initialization */
|
|
||||||
static void
|
|
||||||
acpi_processor_cpu_init_pdc(
|
|
||||||
struct acpi_processor_performance *perf,
|
|
||||||
unsigned int cpu,
|
|
||||||
struct acpi_object_list *obj_list
|
|
||||||
)
|
|
||||||
{
|
|
||||||
struct cpuinfo_x86 *c = cpu_data + cpu;
|
|
||||||
dprintk("acpi_processor_cpu_init_pdc\n");
|
|
||||||
perf->pdc = NULL;
|
|
||||||
if (cpu_has(c, X86_FEATURE_EST))
|
|
||||||
acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
acpi_cpufreq_cpu_init (
|
acpi_cpufreq_cpu_init (
|
||||||
struct cpufreq_policy *policy)
|
struct cpufreq_policy *policy)
|
||||||
|
@ -373,9 +311,6 @@ acpi_cpufreq_cpu_init (
|
||||||
struct acpi_object_list arg_list = {1, &arg0};
|
struct acpi_object_list arg_list = {1, &arg0};
|
||||||
|
|
||||||
dprintk("acpi_cpufreq_cpu_init\n");
|
dprintk("acpi_cpufreq_cpu_init\n");
|
||||||
/* setup arg_list for _PDC settings */
|
|
||||||
arg0.buffer.length = 12;
|
|
||||||
arg0.buffer.pointer = (u8 *) arg0_buf;
|
|
||||||
|
|
||||||
data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
|
data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
@ -383,9 +318,7 @@ acpi_cpufreq_cpu_init (
|
||||||
|
|
||||||
acpi_io_data[cpu] = data;
|
acpi_io_data[cpu] = data;
|
||||||
|
|
||||||
acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list);
|
|
||||||
result = acpi_processor_register_performance(&data->acpi_data, cpu);
|
result = acpi_processor_register_performance(&data->acpi_data, cpu);
|
||||||
data->acpi_data.pdc = NULL;
|
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
|
|
@ -364,22 +364,10 @@ static struct acpi_processor_performance p;
|
||||||
*/
|
*/
|
||||||
static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
|
static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
union acpi_object arg0 = {ACPI_TYPE_BUFFER};
|
|
||||||
u32 arg0_buf[3];
|
|
||||||
struct acpi_object_list arg_list = {1, &arg0};
|
|
||||||
unsigned long cur_freq;
|
unsigned long cur_freq;
|
||||||
int result = 0, i;
|
int result = 0, i;
|
||||||
unsigned int cpu = policy->cpu;
|
unsigned int cpu = policy->cpu;
|
||||||
|
|
||||||
/* _PDC settings */
|
|
||||||
arg0.buffer.length = 12;
|
|
||||||
arg0.buffer.pointer = (u8 *) arg0_buf;
|
|
||||||
arg0_buf[0] = ACPI_PDC_REVISION_ID;
|
|
||||||
arg0_buf[1] = 1;
|
|
||||||
arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP_MSR;
|
|
||||||
|
|
||||||
p.pdc = &arg_list;
|
|
||||||
|
|
||||||
/* register with ACPI core */
|
/* register with ACPI core */
|
||||||
if (acpi_processor_register_performance(&p, cpu)) {
|
if (acpi_processor_register_performance(&p, cpu)) {
|
||||||
dprintk(KERN_INFO PFX "obtaining ACPI data failed\n");
|
dprintk(KERN_INFO PFX "obtaining ACPI data failed\n");
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
|
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||||
|
obj-y += acpi-processor.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
|
@ -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
|
static int
|
||||||
acpi_cpufreq_cpu_init (
|
acpi_cpufreq_cpu_init (
|
||||||
struct cpufreq_policy *policy)
|
struct cpufreq_policy *policy)
|
||||||
|
@ -320,14 +278,7 @@ acpi_cpufreq_cpu_init (
|
||||||
struct cpufreq_acpi_io *data;
|
struct cpufreq_acpi_io *data;
|
||||||
unsigned int result = 0;
|
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");
|
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);
|
data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
@ -337,9 +288,7 @@ acpi_cpufreq_cpu_init (
|
||||||
|
|
||||||
acpi_io_data[cpu] = data;
|
acpi_io_data[cpu] = data;
|
||||||
|
|
||||||
processor_init_pdc(&data->acpi_data, cpu, &arg_list);
|
|
||||||
result = acpi_processor_register_performance(&data->acpi_data, cpu);
|
result = acpi_processor_register_performance(&data->acpi_data, cpu);
|
||||||
data->acpi_data.pdc = NULL;
|
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
|
|
@ -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);
|
|
@ -1,3 +1,8 @@
|
||||||
obj-y := boot.o
|
obj-y := boot.o
|
||||||
boot-y := ../../../i386/kernel/acpi/boot.o
|
boot-y := ../../../i386/kernel/acpi/boot.o
|
||||||
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
|
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||||
|
obj-y += processor.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* arch/x86_64/kernel/acpi/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 cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
unsigned int cpu = pr->id;
|
||||||
|
struct cpuinfo_x86 *c = cpu_data + cpu;
|
||||||
|
|
||||||
|
pr->pdc = NULL;
|
||||||
|
if (c->x86_vendor == X86_VENDOR_INTEL && cpu_has(c, X86_FEATURE_EST))
|
||||||
|
init_intel_pdc(pr, c);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
|
|
@ -253,31 +253,21 @@ static int acpi_processor_errata(struct acpi_processor *pr)
|
||||||
* _PDC is required for a BIOS-OS handshake for most of the newer
|
* _PDC is required for a BIOS-OS handshake for most of the newer
|
||||||
* ACPI processor features.
|
* ACPI processor features.
|
||||||
*/
|
*/
|
||||||
|
static int acpi_processor_set_pdc(struct acpi_processor *pr)
|
||||||
int acpi_processor_set_pdc(struct acpi_processor *pr,
|
|
||||||
struct acpi_object_list *pdc_in)
|
|
||||||
{
|
{
|
||||||
|
struct acpi_object_list *pdc_in = pr->pdc;
|
||||||
acpi_status status = AE_OK;
|
acpi_status status = AE_OK;
|
||||||
u32 arg0_buf[3];
|
|
||||||
union acpi_object arg0 = { ACPI_TYPE_BUFFER };
|
|
||||||
struct acpi_object_list no_object = { 1, &arg0 };
|
|
||||||
struct acpi_object_list *pdc;
|
|
||||||
|
|
||||||
ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
|
ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
|
||||||
|
|
||||||
arg0.buffer.length = 12;
|
if (!pdc_in)
|
||||||
arg0.buffer.pointer = (u8 *) arg0_buf;
|
return_VALUE(status);
|
||||||
arg0_buf[0] = ACPI_PDC_REVISION_ID;
|
|
||||||
arg0_buf[1] = 0;
|
|
||||||
arg0_buf[2] = 0;
|
|
||||||
|
|
||||||
pdc = (pdc_in) ? pdc_in : &no_object;
|
status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
|
||||||
|
|
||||||
status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL);
|
if (ACPI_FAILURE(status))
|
||||||
|
|
||||||
if ((ACPI_FAILURE(status)) && (pdc_in))
|
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||||
"Error evaluating _PDC, using legacy perf. control...\n"));
|
"Could not evaluate _PDC, using legacy perf. control...\n"));
|
||||||
|
|
||||||
return_VALUE(status);
|
return_VALUE(status);
|
||||||
}
|
}
|
||||||
|
@ -574,6 +564,10 @@ static int acpi_processor_start(struct acpi_device *device)
|
||||||
"Error installing device notify handler\n"));
|
"Error installing device notify handler\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* _PDC call should be done before doing anything else (if reqd.). */
|
||||||
|
arch_acpi_processor_init_pdc(pr);
|
||||||
|
acpi_processor_set_pdc(pr);
|
||||||
|
|
||||||
acpi_processor_power_init(pr, device);
|
acpi_processor_power_init(pr, device);
|
||||||
|
|
||||||
if (pr->flags.throttling) {
|
if (pr->flags.throttling) {
|
||||||
|
|
|
@ -1014,8 +1014,6 @@ int acpi_processor_power_init(struct acpi_processor *pr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_processor_power_init_pdc(&(pr->power), pr->id);
|
|
||||||
acpi_processor_set_pdc(pr, pr->power.pdc);
|
|
||||||
acpi_processor_get_power_info(pr);
|
acpi_processor_get_power_info(pr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -315,8 +315,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
|
||||||
if (!pr || !pr->performance || !pr->handle)
|
if (!pr || !pr->performance || !pr->handle)
|
||||||
return_VALUE(-EINVAL);
|
return_VALUE(-EINVAL);
|
||||||
|
|
||||||
acpi_processor_set_pdc(pr, pr->performance->pdc);
|
|
||||||
|
|
||||||
status = acpi_get_handle(pr->handle, "_PCT", &handle);
|
status = acpi_get_handle(pr->handle, "_PCT", &handle);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
#define ACPI_PDC_C_C1_FFH (0x0100)
|
#define ACPI_PDC_C_C1_FFH (0x0100)
|
||||||
|
|
||||||
#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
|
#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
|
||||||
ACPI_PDC_C_C1_HALT)
|
ACPI_PDC_C_C1_HALT | \
|
||||||
|
|
||||||
#define ACPI_PDC_EST_CAPABILITY_SMP_MSR (ACPI_PDC_EST_CAPABILITY_SMP | \
|
|
||||||
ACPI_PDC_P_FFH)
|
ACPI_PDC_P_FFH)
|
||||||
|
|
||||||
#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
|
#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
|
||||||
|
|
|
@ -62,9 +62,6 @@ struct acpi_processor_power {
|
||||||
u32 bm_activity;
|
u32 bm_activity;
|
||||||
int count;
|
int count;
|
||||||
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
|
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
|
||||||
|
|
||||||
/* the _PDC objects passed by the driver, if any */
|
|
||||||
struct acpi_object_list *pdc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Performance Management */
|
/* Performance Management */
|
||||||
|
@ -96,8 +93,6 @@ struct acpi_processor_performance {
|
||||||
unsigned int state_count;
|
unsigned int state_count;
|
||||||
struct acpi_processor_px *states;
|
struct acpi_processor_px *states;
|
||||||
|
|
||||||
/* the _PDC objects passed by the driver, if any */
|
|
||||||
struct acpi_object_list *pdc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Throttling Control */
|
/* Throttling Control */
|
||||||
|
@ -151,6 +146,9 @@ struct acpi_processor {
|
||||||
struct acpi_processor_performance *performance;
|
struct acpi_processor_performance *performance;
|
||||||
struct acpi_processor_throttling throttling;
|
struct acpi_processor_throttling throttling;
|
||||||
struct acpi_processor_limit limit;
|
struct acpi_processor_limit limit;
|
||||||
|
|
||||||
|
/* the _PDC objects for this processor, if any */
|
||||||
|
struct acpi_object_list *pdc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_processor_errata {
|
struct acpi_processor_errata {
|
||||||
|
@ -178,22 +176,12 @@ int acpi_processor_notify_smm(struct module *calling_module);
|
||||||
extern struct acpi_processor *processors[NR_CPUS];
|
extern struct acpi_processor *processors[NR_CPUS];
|
||||||
extern struct acpi_processor_errata errata;
|
extern struct acpi_processor_errata errata;
|
||||||
|
|
||||||
int acpi_processor_set_pdc(struct acpi_processor *pr,
|
void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
|
||||||
struct acpi_object_list *pdc_in);
|
|
||||||
|
|
||||||
#ifdef ARCH_HAS_POWER_PDC_INIT
|
#ifdef ARCH_HAS_POWER_INIT
|
||||||
void acpi_processor_power_init_pdc(struct acpi_processor_power *pow,
|
|
||||||
unsigned int cpu);
|
|
||||||
void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
||||||
unsigned int cpu);
|
unsigned int cpu);
|
||||||
#else
|
#else
|
||||||
static inline void acpi_processor_power_init_pdc(struct acpi_processor_power
|
|
||||||
*pow, unsigned int cpu)
|
|
||||||
{
|
|
||||||
pow->pdc = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void acpi_processor_power_init_bm_check(struct
|
static inline void acpi_processor_power_init_bm_check(struct
|
||||||
acpi_processor_flags
|
acpi_processor_flags
|
||||||
*flags, unsigned int cpu)
|
*flags, unsigned int cpu)
|
||||||
|
|
|
@ -179,7 +179,7 @@ extern void acpi_reserve_bootmem(void);
|
||||||
|
|
||||||
extern u8 x86_acpiid_to_apicid[];
|
extern u8 x86_acpiid_to_apicid[];
|
||||||
|
|
||||||
#define ARCH_HAS_POWER_PDC_INIT 1
|
#define ARCH_HAS_POWER_INIT 1
|
||||||
|
|
||||||
#endif /*__KERNEL__*/
|
#endif /*__KERNEL__*/
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue