[go: nahoru, domu]

processor_pdc.c revision 47817254b8637b56730aec26eed2c337d3938bb5
1/*
2 * Copyright (C) 2005 Intel Corporation
3 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
4 *
5 *	Alex Chiang <achiang@hp.com>
6 *	- Unified x86/ia64 implementations
7 *	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
8 *	- Added _PDC for platforms with Intel CPUs
9 */
10#include <linux/dmi.h>
11
12#include <acpi/acpi_drivers.h>
13#include <acpi/processor.h>
14
15#include "internal.h"
16
17#define PREFIX			"ACPI: "
18#define _COMPONENT		ACPI_PROCESSOR_COMPONENT
19ACPI_MODULE_NAME("processor_pdc");
20
21static int set_no_mwait(const struct dmi_system_id *id)
22{
23	printk(KERN_NOTICE PREFIX "%s detected - "
24		"disabling mwait for CPU C-states\n", id->ident);
25	idle_nomwait = 1;
26	return 0;
27}
28
29static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
30	{
31	set_no_mwait, "IFL91 board", {
32	DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
33	DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
34	DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
35	DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
36	{
37	set_no_mwait, "Extensa 5220", {
38	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
39	DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
40	DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
41	DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
42	{},
43};
44
45static void acpi_set_pdc_bits(u32 *buf)
46{
47	buf[0] = ACPI_PDC_REVISION_ID;
48	buf[1] = 1;
49
50	/* Enable coordination with firmware's _TSD info */
51	buf[2] = ACPI_PDC_SMP_T_SWCOORD;
52
53	/* Twiddle arch-specific bits needed for _PDC */
54	arch_acpi_set_pdc_bits(buf);
55}
56
57static void acpi_processor_init_pdc(struct acpi_processor *pr)
58{
59	struct acpi_object_list *obj_list;
60	union acpi_object *obj;
61	u32 *buf;
62
63	pr->pdc = NULL;
64
65	/* allocate and initialize pdc. It will be used later. */
66	obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
67	if (!obj_list) {
68		printk(KERN_ERR "Memory allocation error\n");
69		return;
70	}
71
72	obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
73	if (!obj) {
74		printk(KERN_ERR "Memory allocation error\n");
75		kfree(obj_list);
76		return;
77	}
78
79	buf = kmalloc(12, GFP_KERNEL);
80	if (!buf) {
81		printk(KERN_ERR "Memory allocation error\n");
82		kfree(obj);
83		kfree(obj_list);
84		return;
85	}
86
87	acpi_set_pdc_bits(buf);
88
89	obj->type = ACPI_TYPE_BUFFER;
90	obj->buffer.length = 12;
91	obj->buffer.pointer = (u8 *) buf;
92	obj_list->count = 1;
93	obj_list->pointer = obj;
94	pr->pdc = obj_list;
95
96	return;
97}
98
99/*
100 * _PDC is required for a BIOS-OS handshake for most of the newer
101 * ACPI processor features.
102 */
103static int acpi_processor_eval_pdc(struct acpi_processor *pr)
104{
105	struct acpi_object_list *pdc_in = pr->pdc;
106	acpi_status status = AE_OK;
107
108	if (!pdc_in)
109		return status;
110	if (idle_nomwait) {
111		/*
112		 * If mwait is disabled for CPU C-states, the C2C3_FFH access
113		 * mode will be disabled in the parameter of _PDC object.
114		 * Of course C1_FFH access mode will also be disabled.
115		 */
116		union acpi_object *obj;
117		u32 *buffer = NULL;
118
119		obj = pdc_in->pointer;
120		buffer = (u32 *)(obj->buffer.pointer);
121		buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
122
123	}
124	status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
125
126	if (ACPI_FAILURE(status))
127		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
128		    "Could not evaluate _PDC, using legacy perf. control.\n"));
129
130	return status;
131}
132
133static void acpi_processor_cleanup_pdc(struct acpi_processor *pr)
134{
135	if (pr->pdc) {
136		kfree(pr->pdc->pointer->buffer.pointer);
137		kfree(pr->pdc->pointer);
138		kfree(pr->pdc);
139		pr->pdc = NULL;
140	}
141}
142
143void acpi_processor_set_pdc(struct acpi_processor *pr)
144{
145	if (arch_has_acpi_pdc() == false)
146		return;
147
148	acpi_processor_init_pdc(pr);
149	acpi_processor_eval_pdc(pr);
150	acpi_processor_cleanup_pdc(pr);
151}
152EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);
153
154static acpi_status
155early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
156{
157	struct acpi_processor pr;
158
159	pr.handle = handle;
160
161	/* x86 implementation looks at pr.id to determine some
162	 * CPU capabilites. We can just hard code to 0 since we're
163	 * assuming the CPUs in the system are homogenous and all
164	 * have the same capabilities.
165	 */
166	pr.id = 0;
167
168	acpi_processor_set_pdc(&pr);
169
170	return AE_OK;
171}
172
173void acpi_early_processor_set_pdc(void)
174{
175	/*
176	 * Check whether the system is DMI table. If yes, OSPM
177	 * should not use mwait for CPU-states.
178	 */
179	dmi_check_system(processor_idle_dmi_table);
180
181	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
182			    ACPI_UINT32_MAX,
183			    early_init_pdc, NULL, NULL, NULL);
184}
185