aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2009-12-20 14:19:09 -0500
committerLen Brown <len.brown@intel.com>2009-12-22 03:24:08 -0500
commit78f1699659963fff97975df44db6d5dbe7218e55 (patch)
tree929291454d6d86a523c9b3881eb8cc40d65a11fc
parent55639353a0035052d9ea6cfe4dde0ac7fcbb2c9f (diff)
ACPI: processor: call _PDC early
We discovered that at least one machine (HP Envy), methods in the DSDT attempt to call external methods defined in a dynamically loaded SSDT. Unfortunately, the DSDT methods we are trying to call are part of the EC initialization, which happens very early, and the the dynamic SSDT is only loaded when a processor _PDC method runs much later. This results in namespace lookup errors for the (as of yet) undefined methods. Since Windows doesn't have any issues with this machine, we take it as a hint that they must be evaluating _PDC much earlier than we are. Thus, the proper thing for Linux to do should be to match the Windows implementation more closely. Provide a mechanism to call _PDC before we enable the EC. Doing so loads the dynamic tables, and allows the EC to be enabled correctly. The ACPI processor driver will still evaluate _PDC in its .add() method to cover the hotplug case. Resolves: http://bugzilla.kernel.org/show_bug.cgi?id=14824 Cc: ming.m.lin@intel.com Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/processor_core.c69
-rw-r--r--drivers/acpi/processor_pdc.c108
-rw-r--r--include/acpi/processor.h3
6 files changed, 115 insertions, 69 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index c7b10b4298e9..66cc3f36a954 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -32,6 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
32# 32#
33acpi-y += bus.o glue.o 33acpi-y += bus.o glue.o
34acpi-y += scan.o 34acpi-y += scan.o
35acpi-y += processor_pdc.o
35acpi-y += ec.o 36acpi-y += ec.o
36acpi-$(CONFIG_ACPI_DOCK) += dock.o 37acpi-$(CONFIG_ACPI_DOCK) += dock.o
37acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o 38acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 65f7e335f122..0bdf24a6fd01 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -888,6 +888,8 @@ static int __init acpi_bus_init(void)
888 goto error1; 888 goto error1;
889 } 889 }
890 890
891 acpi_early_processor_set_pdc();
892
891 /* 893 /*
892 * Maybe EC region is required at bus_scan/acpi_get_devices. So it 894 * Maybe EC region is required at bus_scan/acpi_get_devices. So it
893 * is necessary to enable it as early as possible. 895 * is necessary to enable it as early as possible.
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 074cf8682d52..cb28e0502acc 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -43,6 +43,7 @@ int acpi_power_transition(struct acpi_device *device, int state);
43extern int acpi_power_nocheck; 43extern int acpi_power_nocheck;
44 44
45int acpi_wakeup_device_init(void); 45int acpi_wakeup_device_init(void);
46void acpi_early_processor_set_pdc(void);
46 47
47/* -------------------------------------------------------------------------- 48/* --------------------------------------------------------------------------
48 Embedded Controller 49 Embedded Controller
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 41731236f9a1..a19a4ff962ea 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -124,29 +124,6 @@ static const struct file_operations acpi_processor_info_fops = {
124 124
125DEFINE_PER_CPU(struct acpi_processor *, processors); 125DEFINE_PER_CPU(struct acpi_processor *, processors);
126struct acpi_processor_errata errata __read_mostly; 126struct acpi_processor_errata errata __read_mostly;
127static int set_no_mwait(const struct dmi_system_id *id)
128{
129 printk(KERN_NOTICE PREFIX "%s detected - "
130 "disabling mwait for CPU C-states\n", id->ident);
131 idle_nomwait = 1;
132 return 0;
133}
134
135static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
136 {
137 set_no_mwait, "IFL91 board", {
138 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
139 DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
140 DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
141 DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
142 {
143 set_no_mwait, "Extensa 5220", {
144 DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
145 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
146 DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
147 DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
148 {},
149};
150 127
151/* -------------------------------------------------------------------------- 128/* --------------------------------------------------------------------------
152 Errata Handling 129 Errata Handling
@@ -277,45 +254,6 @@ static int acpi_processor_errata(struct acpi_processor *pr)
277} 254}
278 255
279/* -------------------------------------------------------------------------- 256/* --------------------------------------------------------------------------
280 Common ACPI processor functions
281 -------------------------------------------------------------------------- */
282
283/*
284 * _PDC is required for a BIOS-OS handshake for most of the newer
285 * ACPI processor features.
286 */
287static int acpi_processor_set_pdc(struct acpi_processor *pr)
288{
289 struct acpi_object_list *pdc_in = pr->pdc;
290 acpi_status status = AE_OK;
291
292
293 if (!pdc_in)
294 return status;
295 if (idle_nomwait) {
296 /*
297 * If mwait is disabled for CPU C-states, the C2C3_FFH access
298 * mode will be disabled in the parameter of _PDC object.
299 * Of course C1_FFH access mode will also be disabled.
300 */
301 union acpi_object *obj;
302 u32 *buffer = NULL;
303
304 obj = pdc_in->pointer;
305 buffer = (u32 *)(obj->buffer.pointer);
306 buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
307
308 }
309 status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
310
311 if (ACPI_FAILURE(status))
312 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
313 "Could not evaluate _PDC, using legacy perf. control...\n"));
314
315 return status;
316}
317
318/* --------------------------------------------------------------------------
319 FS Interface (/proc) 257 FS Interface (/proc)
320 -------------------------------------------------------------------------- */ 258 -------------------------------------------------------------------------- */
321 259
@@ -825,9 +763,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
825 } 763 }
826 764
827 /* _PDC call should be done before doing anything else (if reqd.). */ 765 /* _PDC call should be done before doing anything else (if reqd.). */
828 arch_acpi_processor_init_pdc(pr);
829 acpi_processor_set_pdc(pr); 766 acpi_processor_set_pdc(pr);
830 arch_acpi_processor_cleanup_pdc(pr);
831 767
832#ifdef CONFIG_CPU_FREQ 768#ifdef CONFIG_CPU_FREQ
833 acpi_processor_ppc_has_changed(pr, 0); 769 acpi_processor_ppc_has_changed(pr, 0);
@@ -1145,11 +1081,6 @@ static int __init acpi_processor_init(void)
1145 if (!acpi_processor_dir) 1081 if (!acpi_processor_dir)
1146 return -ENOMEM; 1082 return -ENOMEM;
1147#endif 1083#endif
1148 /*
1149 * Check whether the system is DMI table. If yes, OSPM
1150 * should not use mwait for CPU-states.
1151 */
1152 dmi_check_system(processor_idle_dmi_table);
1153 result = cpuidle_register_driver(&acpi_idle_driver); 1084 result = cpuidle_register_driver(&acpi_idle_driver);
1154 if (result < 0) 1085 if (result < 0)
1155 goto out_proc; 1086 goto out_proc;
diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c
new file mode 100644
index 000000000000..b416c32dda04
--- /dev/null
+++ b/drivers/acpi/processor_pdc.c
@@ -0,0 +1,108 @@
1#include <linux/dmi.h>
2
3#include <acpi/acpi_drivers.h>
4#include <acpi/processor.h>
5
6#include "internal.h"
7
8#define PREFIX "ACPI: "
9#define _COMPONENT ACPI_PROCESSOR_COMPONENT
10ACPI_MODULE_NAME("processor_pdc");
11
12static int set_no_mwait(const struct dmi_system_id *id)
13{
14 printk(KERN_NOTICE PREFIX "%s detected - "
15 "disabling mwait for CPU C-states\n", id->ident);
16 idle_nomwait = 1;
17 return 0;
18}
19
20static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
21 {
22 set_no_mwait, "IFL91 board", {
23 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
24 DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
25 DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
26 DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
27 {
28 set_no_mwait, "Extensa 5220", {
29 DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
30 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
31 DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
32 DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
33 {},
34};
35
36/*
37 * _PDC is required for a BIOS-OS handshake for most of the newer
38 * ACPI processor features.
39 */
40static int acpi_processor_eval_pdc(struct acpi_processor *pr)
41{
42 struct acpi_object_list *pdc_in = pr->pdc;
43 acpi_status status = AE_OK;
44
45 if (!pdc_in)
46 return status;
47 if (idle_nomwait) {
48 /*
49 * If mwait is disabled for CPU C-states, the C2C3_FFH access
50 * mode will be disabled in the parameter of _PDC object.
51 * Of course C1_FFH access mode will also be disabled.
52 */
53 union acpi_object *obj;
54 u32 *buffer = NULL;
55
56 obj = pdc_in->pointer;
57 buffer = (u32 *)(obj->buffer.pointer);
58 buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
59
60 }
61 status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
62
63 if (ACPI_FAILURE(status))
64 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
65 "Could not evaluate _PDC, using legacy perf. control.\n"));
66
67 return status;
68}
69
70void acpi_processor_set_pdc(struct acpi_processor *pr)
71{
72 arch_acpi_processor_init_pdc(pr);
73 acpi_processor_eval_pdc(pr);
74 arch_acpi_processor_cleanup_pdc(pr);
75}
76EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);
77
78static acpi_status
79early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
80{
81 struct acpi_processor pr;
82
83 pr.handle = handle;
84
85 /* x86 implementation looks at pr.id to determine some
86 * CPU capabilites. We can just hard code to 0 since we're
87 * assuming the CPUs in the system are homogenous and all
88 * have the same capabilities.
89 */
90 pr.id = 0;
91
92 acpi_processor_set_pdc(&pr);
93
94 return AE_OK;
95}
96
97void acpi_early_processor_set_pdc(void)
98{
99 /*
100 * Check whether the system is DMI table. If yes, OSPM
101 * should not use mwait for CPU-states.
102 */
103 dmi_check_system(processor_idle_dmi_table);
104
105 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
106 ACPI_UINT32_MAX,
107 early_init_pdc, NULL, NULL, NULL);
108}
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 29245c6b5c0e..a1b748a7a766 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -325,6 +325,9 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
325 325
326#endif /* CONFIG_CPU_FREQ */ 326#endif /* CONFIG_CPU_FREQ */
327 327
328/* in processor_pdc.c */
329void acpi_processor_set_pdc(struct acpi_processor *pr);
330
328/* in processor_throttling.c */ 331/* in processor_throttling.c */
329int acpi_processor_tstate_has_changed(struct acpi_processor *pr); 332int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
330int acpi_processor_get_throttling_info(struct acpi_processor *pr); 333int acpi_processor_get_throttling_info(struct acpi_processor *pr);