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>

authored by Alexey Starikovskiy and committed by Len Brown c6cb0e87 235c4a59

+30 -44
+30 -44
drivers/acpi/ec.c
··· 120 120 spinlock_t curr_lock; 121 121 } *boot_ec, *first_ec; 122 122 123 - /* 124 - * Some Asus system have exchanged ECDT data/command IO addresses. 125 - */ 126 - static 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 - 134 - static 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 124 Transaction Management 150 125 -------------------------------------------------------------------------- */ ··· 958 983 int __init acpi_ec_ecdt_probe(void) 959 984 { 960 985 acpi_status status; 986 + struct acpi_ec *saved_ec = NULL; 961 987 struct acpi_table_ecdt *ecdt_ptr; 962 - acpi_handle dummy; 963 988 964 989 boot_ec = make_acpi_ec(); 965 990 if (!boot_ec) ··· 973 998 pr_info(PREFIX "EC description table is found, configuring boot EC\n"); 974 999 boot_ec->command_addr = ecdt_ptr->control.address; 975 1000 boot_ec->data_addr = ecdt_ptr->data.address; 976 - if (dmi_check_system(ec_dmi_table)) { 977 - /* 978 - * If the board falls into ec_dmi_table, it means 979 - * that ECDT table gives the incorrect command/status 980 - * & data I/O address. Just fix it. 981 - */ 982 - boot_ec->data_addr = ecdt_ptr->control.address; 983 - boot_ec->command_addr = ecdt_ptr->data.address; 984 - } 985 1001 boot_ec->gpe = ecdt_ptr->gpe; 986 1002 boot_ec->handle = ACPI_ROOT_OBJECT; 987 1003 acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); 988 - /* Add some basic check against completely broken table */ 989 - if (boot_ec->data_addr != boot_ec->command_addr) 1004 + /* Don't trust ECDT, which comes from ASUSTek */ 1005 + if (!dmi_name_in_vendors("ASUS")) 990 1006 goto install; 1007 + saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); 1008 + if (!saved_ec) 1009 + return -ENOMEM; 1010 + memcpy(&saved_ec, boot_ec, sizeof(saved_ec)); 991 1011 /* fall through */ 992 1012 } 993 1013 /* This workaround is needed only on some broken machines, ··· 993 1023 /* Check that acpi_get_devices actually find something */ 994 1024 if (ACPI_FAILURE(status) || !boot_ec->handle) 995 1025 goto error; 996 - /* We really need to limit this workaround, the only ASUS, 997 - * which needs it, has fake EC._INI method, so use it as flag. 998 - * Keep boot_ec struct as it will be needed soon. 999 - */ 1000 - if (!dmi_name_in_vendors("ASUS") || 1001 - ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy))) 1002 - return -ENODEV; 1026 + if (saved_ec) { 1027 + /* try to find good ECDT from ASUSTek */ 1028 + if (saved_ec->command_addr != boot_ec->command_addr || 1029 + saved_ec->data_addr != boot_ec->data_addr || 1030 + saved_ec->gpe != boot_ec->gpe || 1031 + saved_ec->handle != boot_ec->handle) 1032 + pr_info(PREFIX "ASUSTek keeps feeding us with broken " 1033 + "ECDT tables, which are very hard to workaround. " 1034 + "Trying to use DSDT EC info instead. Please send " 1035 + "output of acpidump to linux-acpi@vger.kernel.org\n"); 1036 + kfree(saved_ec); 1037 + saved_ec = NULL; 1038 + } else { 1039 + /* We really need to limit this workaround, the only ASUS, 1040 + * which needs it, has fake EC._INI method, so use it as flag. 1041 + * Keep boot_ec struct as it will be needed soon. 1042 + */ 1043 + acpi_handle dummy; 1044 + if (!dmi_name_in_vendors("ASUS") || 1045 + ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", 1046 + &dummy))) 1047 + return -ENODEV; 1048 + } 1003 1049 install: 1004 1050 if (!ec_install_handlers(boot_ec)) { 1005 1051 first_ec = boot_ec;