processor_core.c 4.8 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * Copyright (C) 2005 Intel Corporation
 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
 *
 *	Alex Chiang <achiang@hp.com>
 *	- Unified x86/ia64 implementations
 *	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
 *	- Added _PDC for platforms with Intel CPUs
 */
A
Alex Chiang 已提交
10 11 12 13 14 15 16 17 18
#include <linux/dmi.h>

#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>

#include "internal.h"

#define PREFIX			"ACPI: "
#define _COMPONENT		ACPI_PROCESSOR_COMPONENT
19
ACPI_MODULE_NAME("processor_core");
A
Alex Chiang 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

static int set_no_mwait(const struct dmi_system_id *id)
{
	printk(KERN_NOTICE PREFIX "%s detected - "
		"disabling mwait for CPU C-states\n", id->ident);
	idle_nomwait = 1;
	return 0;
}

static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
	{
	set_no_mwait, "IFL91 board", {
	DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
	DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
	DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
	DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
	{
	set_no_mwait, "Extensa 5220", {
	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
	DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
	DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
	DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
	{},
};

45 46 47 48 49 50 51
static void acpi_set_pdc_bits(u32 *buf)
{
	buf[0] = ACPI_PDC_REVISION_ID;
	buf[1] = 1;

	/* Enable coordination with firmware's _TSD info */
	buf[2] = ACPI_PDC_SMP_T_SWCOORD;
52 53 54

	/* Twiddle arch-specific bits needed for _PDC */
	arch_acpi_set_pdc_bits(buf);
55 56
}

57
static struct acpi_object_list *acpi_processor_alloc_pdc(void)
58 59 60 61 62 63 64 65 66
{
	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");
67
		return NULL;
68 69 70 71 72 73
	}

	obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
	if (!obj) {
		printk(KERN_ERR "Memory allocation error\n");
		kfree(obj_list);
74
		return NULL;
75 76 77 78 79 80 81
	}

	buf = kmalloc(12, GFP_KERNEL);
	if (!buf) {
		printk(KERN_ERR "Memory allocation error\n");
		kfree(obj);
		kfree(obj_list);
82
		return NULL;
83 84
	}

85 86
	acpi_set_pdc_bits(buf);

87 88 89 90 91 92
	obj->type = ACPI_TYPE_BUFFER;
	obj->buffer.length = 12;
	obj->buffer.pointer = (u8 *) buf;
	obj_list->count = 1;
	obj_list->pointer = obj;

93
	return obj_list;
94 95
}

A
Alex Chiang 已提交
96 97 98 99
/*
 * _PDC is required for a BIOS-OS handshake for most of the newer
 * ACPI processor features.
 */
100 101
static int
acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
A
Alex Chiang 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
{
	acpi_status status = AE_OK;

	if (idle_nomwait) {
		/*
		 * If mwait is disabled for CPU C-states, the C2C3_FFH access
		 * mode will be disabled in the parameter of _PDC object.
		 * Of course C1_FFH access mode will also be disabled.
		 */
		union acpi_object *obj;
		u32 *buffer = NULL;

		obj = pdc_in->pointer;
		buffer = (u32 *)(obj->buffer.pointer);
		buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);

	}
119
	status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
A
Alex Chiang 已提交
120 121 122 123 124 125 126 127

	if (ACPI_FAILURE(status))
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
		    "Could not evaluate _PDC, using legacy perf. control.\n"));

	return status;
}

128 129
static int early_pdc_done;

130
void acpi_processor_set_pdc(acpi_handle handle)
A
Alex Chiang 已提交
131
{
132 133
	struct acpi_object_list *obj_list;

134 135 136
	if (arch_has_acpi_pdc() == false)
		return;

137 138 139
	if (early_pdc_done)
		return;

140 141 142 143
	obj_list = acpi_processor_alloc_pdc();
	if (!obj_list)
		return;

144
	acpi_processor_eval_pdc(handle, obj_list);
145 146 147 148

	kfree(obj_list->pointer->buffer.pointer);
	kfree(obj_list->pointer);
	kfree(obj_list);
A
Alex Chiang 已提交
149 150 151
}
EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);

152 153 154 155 156 157 158
static int early_pdc_optin;
static int set_early_pdc_optin(const struct dmi_system_id *id)
{
	early_pdc_optin = 1;
	return 0;
}

159 160 161 162 163 164 165
static int param_early_pdc_optin(char *s)
{
	early_pdc_optin = 1;
	return 1;
}
__setup("acpi_early_pdc_eval", param_early_pdc_optin);

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
static struct dmi_system_id __cpuinitdata early_pdc_optin_table[] = {
	{
	set_early_pdc_optin, "HP Envy", {
	DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"),
	DMI_MATCH(DMI_PRODUCT_NAME, "HP Envy") }, NULL},
	{
	set_early_pdc_optin, "HP Pavilion dv6", {
	DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"),
	DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6") }, NULL},
	{
	set_early_pdc_optin, "HP Pavilion dv7", {
	DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"),
	DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7") }, NULL},
	{},
};

A
Alex Chiang 已提交
182 183 184
static acpi_status
early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
{
185
	acpi_processor_set_pdc(handle);
A
Alex Chiang 已提交
186 187 188
	return AE_OK;
}

189
void __init acpi_early_processor_set_pdc(void)
A
Alex Chiang 已提交
190 191 192 193 194 195 196
{
	/*
	 * Check whether the system is DMI table. If yes, OSPM
	 * should not use mwait for CPU-states.
	 */
	dmi_check_system(processor_idle_dmi_table);

197 198 199 200 201 202 203
	/*
	 * Allow systems to opt-in to early _PDC evaluation.
	 */
	dmi_check_system(early_pdc_optin_table);
	if (!early_pdc_optin)
		return;

A
Alex Chiang 已提交
204 205 206
	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
			    ACPI_UINT32_MAX,
			    early_init_pdc, NULL, NULL, NULL);
207 208

	early_pdc_done = 1;
A
Alex Chiang 已提交
209
}