aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <astarikovskiy@suse.de>2009-01-13 18:57:53 -0500
committerLen Brown <len.brown@intel.com>2009-01-16 14:03:32 -0500
commitc6cb0e878446c79f42e7833d7bb69ed6bfbb381f (patch)
treef1d585a339837e030e51df6b567998515dfcbd06 /drivers/acpi/ec.c
parent235c4a59278eb07e61d909f1f0c233733034a8b3 (diff)
ACPI: EC: Don't trust ECDT tables from ASUS
http://bugzilla.kernel.org/show_bug.cgi?id=9399 http://bugzilla.kernel.org/show_bug.cgi?id=11880 Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c74
1 files changed, 30 insertions, 44 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e0794264b9f7..a2b82c90a683 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -120,31 +120,6 @@ static struct acpi_ec {
120 spinlock_t curr_lock; 120 spinlock_t curr_lock;
121} *boot_ec, *first_ec; 121} *boot_ec, *first_ec;
122 122
123/*
124 * Some Asus system have exchanged ECDT data/command IO addresses.
125 */
126static int print_ecdt_error(const struct dmi_system_id *id)
127{
128 printk(KERN_NOTICE PREFIX "%s detected - "
129 "ECDT has exchanged control/data I/O address\n",
130 id->ident);
131 return 0;
132}
133
134static struct dmi_system_id __cpuinitdata ec_dmi_table[] = {
135 {
136 print_ecdt_error, "Asus L4R", {
137 DMI_MATCH(DMI_BIOS_VERSION, "1008.006"),
138 DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),
139 DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL},
140 {
141 print_ecdt_error, "Asus M6R", {
142 DMI_MATCH(DMI_BIOS_VERSION, "0207"),
143 DMI_MATCH(DMI_PRODUCT_NAME, "M6R"),
144 DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL},
145 {},
146};
147
148/* -------------------------------------------------------------------------- 123/* --------------------------------------------------------------------------
149 Transaction Management 124 Transaction Management
150 -------------------------------------------------------------------------- */ 125 -------------------------------------------------------------------------- */
@@ -983,8 +958,8 @@ static const struct acpi_device_id ec_device_ids[] = {
983int __init acpi_ec_ecdt_probe(void) 958int __init acpi_ec_ecdt_probe(void)
984{ 959{
985 acpi_status status; 960 acpi_status status;
961 struct acpi_ec *saved_ec = NULL;
986 struct acpi_table_ecdt *ecdt_ptr; 962 struct acpi_table_ecdt *ecdt_ptr;
987 acpi_handle dummy;
988 963
989 boot_ec = make_acpi_ec(); 964 boot_ec = make_acpi_ec();
990 if (!boot_ec) 965 if (!boot_ec)
@@ -998,21 +973,16 @@ int __init acpi_ec_ecdt_probe(void)
998 pr_info(PREFIX "EC description table is found, configuring boot EC\n"); 973 pr_info(PREFIX "EC description table is found, configuring boot EC\n");
999 boot_ec->command_addr = ecdt_ptr->control.address; 974 boot_ec->command_addr = ecdt_ptr->control.address;
1000 boot_ec->data_addr = ecdt_ptr->data.address; 975 boot_ec->data_addr = ecdt_ptr->data.address;
1001 if (dmi_check_system(ec_dmi_table)) {
1002 /*
1003 * If the board falls into ec_dmi_table, it means
1004 * that ECDT table gives the incorrect command/status
1005 * & data I/O address. Just fix it.
1006 */
1007 boot_ec->data_addr = ecdt_ptr->control.address;
1008 boot_ec->command_addr = ecdt_ptr->data.address;
1009 }
1010 boot_ec->gpe = ecdt_ptr->gpe; 976 boot_ec->gpe = ecdt_ptr->gpe;
1011 boot_ec->handle = ACPI_ROOT_OBJECT; 977 boot_ec->handle = ACPI_ROOT_OBJECT;
1012 acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); 978 acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
1013 /* Add some basic check against completely broken table */ 979 /* Don't trust ECDT, which comes from ASUSTek */
1014 if (boot_ec->data_addr != boot_ec->command_addr) 980 if (!dmi_name_in_vendors("ASUS"))
1015 goto install; 981 goto install;
982 saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
983 if (!saved_ec)
984 return -ENOMEM;
985 memcpy(&saved_ec, boot_ec, sizeof(saved_ec));
1016 /* fall through */ 986 /* fall through */
1017 } 987 }
1018 /* This workaround is needed only on some broken machines, 988 /* This workaround is needed only on some broken machines,
@@ -1023,13 +993,29 @@ int __init acpi_ec_ecdt_probe(void)
1023 /* Check that acpi_get_devices actually find something */ 993 /* Check that acpi_get_devices actually find something */
1024 if (ACPI_FAILURE(status) || !boot_ec->handle) 994 if (ACPI_FAILURE(status) || !boot_ec->handle)
1025 goto error; 995 goto error;
1026 /* We really need to limit this workaround, the only ASUS, 996 if (saved_ec) {
1027 * which needs it, has fake EC._INI method, so use it as flag. 997 /* try to find good ECDT from ASUSTek */
1028 * Keep boot_ec struct as it will be needed soon. 998 if (saved_ec->command_addr != boot_ec->command_addr ||
1029 */ 999 saved_ec->data_addr != boot_ec->data_addr ||
1030 if (!dmi_name_in_vendors("ASUS") || 1000 saved_ec->gpe != boot_ec->gpe ||
1031 ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy))) 1001 saved_ec->handle != boot_ec->handle)
1032 return -ENODEV; 1002 pr_info(PREFIX "ASUSTek keeps feeding us with broken "
1003 "ECDT tables, which are very hard to workaround. "
1004 "Trying to use DSDT EC info instead. Please send "
1005 "output of acpidump to linux-acpi@vger.kernel.org\n");
1006 kfree(saved_ec);
1007 saved_ec = NULL;
1008 } else {
1009 /* We really need to limit this workaround, the only ASUS,
1010 * which needs it, has fake EC._INI method, so use it as flag.
1011 * Keep boot_ec struct as it will be needed soon.
1012 */
1013 acpi_handle dummy;
1014 if (!dmi_name_in_vendors("ASUS") ||
1015 ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
1016 &dummy)))
1017 return -ENODEV;
1018 }
1033install: 1019install:
1034 if (!ec_install_handlers(boot_ec)) { 1020 if (!ec_install_handlers(boot_ec)) {
1035 first_ec = boot_ec; 1021 first_ec = boot_ec;