mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	[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
					
				
					 16 changed files with 243 additions and 231 deletions
				
			
		| 
						 | 
				
			
			@ -3,6 +3,6 @@ obj-$(CONFIG_X86_IO_APIC)	+= earlyquirk.o
 | 
			
		|||
obj-$(CONFIG_ACPI_SLEEP)	+= sleep.o wakeup.o
 | 
			
		||||
 | 
			
		||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
 | 
			
		||||
obj-y				+= cstate.o
 | 
			
		||||
obj-y				+= cstate.o processor.o
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,64 +14,6 @@
 | 
			
		|||
#include <acpi/processor.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
 | 
			
		||||
 * On SMP it depends on cache configuration
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										75
									
								
								arch/i386/kernel/acpi/processor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								arch/i386/kernel/acpi/processor.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
acpi_cpufreq_cpu_init (
 | 
			
		||||
	struct cpufreq_policy   *policy)
 | 
			
		||||
| 
						 | 
				
			
			@ -373,9 +311,6 @@ acpi_cpufreq_cpu_init (
 | 
			
		|||
	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 = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
 | 
			
		||||
	if (!data)
 | 
			
		||||
| 
						 | 
				
			
			@ -383,9 +318,7 @@ acpi_cpufreq_cpu_init (
 | 
			
		|||
 | 
			
		||||
	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);
 | 
			
		||||
	data->acpi_data.pdc = NULL;
 | 
			
		||||
 | 
			
		||||
	if (result)
 | 
			
		||||
		goto err_free;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -364,22 +364,10 @@ static struct acpi_processor_performance p;
 | 
			
		|||
 */
 | 
			
		||||
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;
 | 
			
		||||
	int				result = 0, i;
 | 
			
		||||
	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 */
 | 
			
		||||
	if (acpi_processor_register_performance(&p, cpu)) {
 | 
			
		||||
		dprintk(KERN_INFO PFX "obtaining ACPI data failed\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,6 @@
 | 
			
		|||
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
 | 
			
		||||
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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										67
									
								
								arch/ia64/kernel/cpufreq/acpi-processor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								arch/ia64/kernel/cpufreq/acpi-processor.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
boot-y			:= ../../../i386/kernel/acpi/boot.o
 | 
			
		||||
obj-$(CONFIG_ACPI_SLEEP)	+= sleep.o wakeup.o
 | 
			
		||||
 | 
			
		||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
 | 
			
		||||
obj-y			+= processor.o
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										72
									
								
								arch/x86_64/kernel/acpi/processor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								arch/x86_64/kernel/acpi/processor.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
 * ACPI processor features.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int acpi_processor_set_pdc(struct acpi_processor *pr,
 | 
			
		||||
			   struct acpi_object_list *pdc_in)
 | 
			
		||||
static int acpi_processor_set_pdc(struct acpi_processor *pr)
 | 
			
		||||
{
 | 
			
		||||
	struct acpi_object_list *pdc_in = pr->pdc;
 | 
			
		||||
	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");
 | 
			
		||||
 | 
			
		||||
	arg0.buffer.length = 12;
 | 
			
		||||
	arg0.buffer.pointer = (u8 *) arg0_buf;
 | 
			
		||||
	arg0_buf[0] = ACPI_PDC_REVISION_ID;
 | 
			
		||||
	arg0_buf[1] = 0;
 | 
			
		||||
	arg0_buf[2] = 0;
 | 
			
		||||
	if (!pdc_in)
 | 
			
		||||
		return_VALUE(status);
 | 
			
		||||
 | 
			
		||||
	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)) && (pdc_in))
 | 
			
		||||
	if (ACPI_FAILURE(status))
 | 
			
		||||
		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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -574,6 +564,10 @@ static int acpi_processor_start(struct acpi_device *device)
 | 
			
		|||
				  "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);
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -315,8 +315,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
 | 
			
		|||
	if (!pr || !pr->performance || !pr->handle)
 | 
			
		||||
		return_VALUE(-EINVAL);
 | 
			
		||||
 | 
			
		||||
	acpi_processor_set_pdc(pr, pr->performance->pdc);
 | 
			
		||||
 | 
			
		||||
	status = acpi_get_handle(pr->handle, "_PCT", &handle);
 | 
			
		||||
	if (ACPI_FAILURE(status)) {
 | 
			
		||||
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,9 +15,7 @@
 | 
			
		|||
#define ACPI_PDC_C_C1_FFH		(0x0100)
 | 
			
		||||
 | 
			
		||||
#define ACPI_PDC_EST_CAPABILITY_SMP	(ACPI_PDC_SMP_C1PT | \
 | 
			
		||||
					 ACPI_PDC_C_C1_HALT)
 | 
			
		||||
 | 
			
		||||
#define ACPI_PDC_EST_CAPABILITY_SMP_MSR	(ACPI_PDC_EST_CAPABILITY_SMP | \
 | 
			
		||||
					 ACPI_PDC_C_C1_HALT | \
 | 
			
		||||
					 ACPI_PDC_P_FFH)
 | 
			
		||||
 | 
			
		||||
#define ACPI_PDC_C_CAPABILITY_SMP	(ACPI_PDC_SMP_C2C3 | \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,9 +62,6 @@ struct acpi_processor_power {
 | 
			
		|||
	u32 bm_activity;
 | 
			
		||||
	int count;
 | 
			
		||||
	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 */
 | 
			
		||||
| 
						 | 
				
			
			@ -96,8 +93,6 @@ struct acpi_processor_performance {
 | 
			
		|||
	unsigned int state_count;
 | 
			
		||||
	struct acpi_processor_px *states;
 | 
			
		||||
 | 
			
		||||
	/* the _PDC objects passed by the driver, if any */
 | 
			
		||||
	struct acpi_object_list *pdc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Throttling Control */
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +146,9 @@ struct acpi_processor {
 | 
			
		|||
	struct acpi_processor_performance *performance;
 | 
			
		||||
	struct acpi_processor_throttling throttling;
 | 
			
		||||
	struct acpi_processor_limit limit;
 | 
			
		||||
 | 
			
		||||
	/* the _PDC objects for this processor, if any */
 | 
			
		||||
	struct acpi_object_list *pdc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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_errata errata;
 | 
			
		||||
 | 
			
		||||
int acpi_processor_set_pdc(struct acpi_processor *pr,
 | 
			
		||||
			   struct acpi_object_list *pdc_in);
 | 
			
		||||
void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
 | 
			
		||||
 | 
			
		||||
#ifdef ARCH_HAS_POWER_PDC_INIT
 | 
			
		||||
void acpi_processor_power_init_pdc(struct acpi_processor_power *pow,
 | 
			
		||||
				   unsigned int cpu);
 | 
			
		||||
#ifdef ARCH_HAS_POWER_INIT
 | 
			
		||||
void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
 | 
			
		||||
					unsigned int cpu);
 | 
			
		||||
#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
 | 
			
		||||
						      acpi_processor_flags
 | 
			
		||||
						      *flags, unsigned int cpu)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,7 +179,7 @@ extern void acpi_reserve_bootmem(void);
 | 
			
		|||
 | 
			
		||||
extern u8 x86_acpiid_to_apicid[];
 | 
			
		||||
 | 
			
		||||
#define ARCH_HAS_POWER_PDC_INIT	1
 | 
			
		||||
#define ARCH_HAS_POWER_INIT	1
 | 
			
		||||
 | 
			
		||||
#endif /*__KERNEL__*/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue