aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-03-23 22:42:53 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-04-08 21:06:44 -0400
commit59f0aa9480cfef9173a648cec4537addc5f3ad94 (patch)
tree5dbb5cbb55e26ef50a2b858a37fd9c789d3c1a98
parent0e1affe41bdd7b1bef64c007d260e142bcaef220 (diff)
ACPI 2.0 / ECDT: Remove early namespace reference from EC
All operation region accesses are allowed by AML interpreter when AML is executed, so actually BIOSen are responsible to avoid the operation region accesses in AML before OSPM has prepared an operation region driver. This is done via _REG control method. So AML code normally sets a global named object REGC to 1 when _REG(3, 1) is evaluated. Then what is ECDT? Quoting from ACPI spec 6.0, 5.2.15 Embedded Controller Boot Resources Table (ECDT): "The presence of this table allows OSPM to provide Embedded Controller operation region space access before the namespace has been evaluated." Spec also suggests a compatible mean to indicate the early EC access availability: Device (EC) { Name (REGC, Ones) Method (_REG, 2) { If (LEqual (Arg0, 3)) { Store (Arg1, REGC) } } Method (ECAV) { If (LEqual (REGC, Ones)) { If (LGreaterEqual (_REV, 2)) { Return (One) } Else { Return (Zero) } } Else { Return (REGC) } } } In this way, it allows EC accesses to happen before EC._REG(3, 1) is invoked. But ECAV is not the only way practical BIOSen using to indicate the early EC access availibility, the known variations include: 1. Setting REGC to One in \_SB._INI when _REV >= 2. Since \_SB._INI is the first control method evaluated by OSPM during the enumeration, this allows EC accesses to happen for the entire enumeration process before the namespace EC is enumerated. 2. Initialize REGC to One by default, this even allows EC accesses to happen during the table loading. Linux is now broken around ECDT support during the long term bug fixing work because it has merged many wrong ECDT bug fixes (see details below). Linux currently uses namespace EC's settings instead of ECDT settings when ECDT is detected. This apparently will result in namespace walk and _CRS/_GPE/_REG evaluations. Such stuffs could only happen after namespace is ready, while ECDT is purposely to be used before namespace is ready. The wrong bug fixing story is: 1. Link 1: At Linux ACPI early stages, "no _Lxx/_Exx/_Qxx evaluation can happen before the namespace is ready" are not ensured by ACPICA core and Linux. This is currently ensured by deferred enabling of GPE and defered registering of EC query methods (acpi_ec_register_query_methods). 2. Link 2: Reporters reported buggy ECDTs, expecting quirks for the platform. Originally, the quirk is simple, only doing things with ECDT. Bug 9399 and 12461 are platforms (Asus L4R, Asus M6R, MSI MS-171F) reported to have wrong ECDT IO port addresses, the port addresses are reversed. Bug 11880 is a platform (Asus X50GL) reported to have 0 valued port addresses, we can see that all EC accesses are protected by ECAV on this platform, so actually no early EC accesses is required by this platform. 3. Link 3: But when the bug fixing developer was requested to provide a handy and non-quirk bug fix, he tried to use correct EC settings from namespace and broke the spec purpose. We can even see that the developer was suffered from many regrssions. One interesting one is 14086, where the actual root cause obviously should be: _REG is evaluated too early. But unfortunately, the bug is fixed in a totally wrong way. So everything goes wrong from these commits: Commit: c6cb0e878446c79f42e7833d7bb69ed6bfbb381f Subject: ACPI: EC: Don't trust ECDT tables from ASUS Commit: a5032bfdd9c80e0231a6324661e123818eb46ecd Subject: ACPI: EC: Always parse EC device This patch reverts Linux behavior to simple ECDT quirk support in order to stop early _CRS/_GPE/_REG evaluations. For Bug 9399, 12461, since it is reported that the platforms require early EC accesses, this patch restores the simple ECDT quirks for them. For Bug 11880, since it is not reported that the platform requires early EC accesses and its ACPI tables contain correct ECAV, we choose an ECDT enumeration failure for this platform. Link 1: https://bugzilla.kernel.org/show_bug.cgi?id=9916 http://bugzilla.kernel.org/show_bug.cgi?id=10100 https://lkml.org/lkml/2008/2/25/282 Link 2: https://bugzilla.kernel.org/show_bug.cgi?id=9399 https://bugzilla.kernel.org/show_bug.cgi?id=12461 https://bugzilla.kernel.org/show_bug.cgi?id=11880 Link 3: https://bugzilla.kernel.org/show_bug.cgi?id=11884 https://bugzilla.kernel.org/show_bug.cgi?id=14081 https://bugzilla.kernel.org/show_bug.cgi?id=14086 https://bugzilla.kernel.org/show_bug.cgi?id=14446 Link 4: https://bugzilla.kernel.org/show_bug.cgi?id=112911 Signed-off-by: Lv Zheng <lv.zheng@intel.com> Tested-by: Chris Bainbridge <chris.bainbridge@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/ec.c145
1 files changed, 54 insertions, 91 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b8f474b78bc7..0e70181f150c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -175,10 +175,9 @@ static void acpi_ec_event_processor(struct work_struct *work);
175struct acpi_ec *boot_ec, *first_ec; 175struct acpi_ec *boot_ec, *first_ec;
176EXPORT_SYMBOL(first_ec); 176EXPORT_SYMBOL(first_ec);
177 177
178static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
179static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
180static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ 178static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
181static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ 179static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
180static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
182 181
183/* -------------------------------------------------------------------------- 182/* --------------------------------------------------------------------------
184 * Logging/Debugging 183 * Logging/Debugging
@@ -1358,11 +1357,12 @@ static int acpi_ec_add(struct acpi_device *device)
1358 strcpy(acpi_device_class(device), ACPI_EC_CLASS); 1357 strcpy(acpi_device_class(device), ACPI_EC_CLASS);
1359 1358
1360 /* Check for boot EC */ 1359 /* Check for boot EC */
1361 if (boot_ec && 1360 if (boot_ec) {
1362 (boot_ec->handle == device->handle ||
1363 boot_ec->handle == ACPI_ROOT_OBJECT)) {
1364 ec = boot_ec; 1361 ec = boot_ec;
1365 boot_ec = NULL; 1362 boot_ec = NULL;
1363 ec_remove_handlers(ec);
1364 if (first_ec == ec)
1365 first_ec = NULL;
1366 } else { 1366 } else {
1367 ec = make_acpi_ec(); 1367 ec = make_acpi_ec();
1368 if (!ec) 1368 if (!ec)
@@ -1462,20 +1462,6 @@ static const struct acpi_device_id ec_device_ids[] = {
1462 {"", 0}, 1462 {"", 0},
1463}; 1463};
1464 1464
1465/* Some BIOS do not survive early DSDT scan, skip it */
1466static int ec_skip_dsdt_scan(const struct dmi_system_id *id)
1467{
1468 EC_FLAGS_SKIP_DSDT_SCAN = 1;
1469 return 0;
1470}
1471
1472/* ASUStek often supplies us with broken ECDT, validate it */
1473static int ec_validate_ecdt(const struct dmi_system_id *id)
1474{
1475 EC_FLAGS_VALIDATE_ECDT = 1;
1476 return 0;
1477}
1478
1479#if 0 1465#if 0
1480/* 1466/*
1481 * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not 1467 * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not
@@ -1517,30 +1503,29 @@ static int ec_clear_on_resume(const struct dmi_system_id *id)
1517 return 0; 1503 return 0;
1518} 1504}
1519 1505
1506static int ec_correct_ecdt(const struct dmi_system_id *id)
1507{
1508 pr_debug("Detected system needing ECDT address correction.\n");
1509 EC_FLAGS_CORRECT_ECDT = 1;
1510 return 0;
1511}
1512
1520static struct dmi_system_id ec_dmi_table[] __initdata = { 1513static struct dmi_system_id ec_dmi_table[] __initdata = {
1521 { 1514 {
1522 ec_skip_dsdt_scan, "Compal JFL92", { 1515 ec_correct_ecdt, "Asus L4R", {
1523 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), 1516 DMI_MATCH(DMI_BIOS_VERSION, "1008.006"),
1524 DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL}, 1517 DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),
1518 DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL},
1519 {
1520 ec_correct_ecdt, "Asus M6R", {
1521 DMI_MATCH(DMI_BIOS_VERSION, "0207"),
1522 DMI_MATCH(DMI_PRODUCT_NAME, "M6R"),
1523 DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL},
1525 { 1524 {
1526 ec_validate_ecdt, "MSI MS-171F", { 1525 ec_correct_ecdt, "MSI MS-171F", {
1527 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), 1526 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
1528 DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, 1527 DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
1529 { 1528 {
1530 ec_validate_ecdt, "ASUS hardware", {
1531 DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
1532 {
1533 ec_validate_ecdt, "ASUS hardware", {
1534 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL},
1535 {
1536 ec_skip_dsdt_scan, "HP Folio 13", {
1537 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1538 DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
1539 {
1540 ec_validate_ecdt, "ASUS hardware", {
1541 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
1542 DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
1543 {
1544 ec_clear_on_resume, "Samsung hardware", { 1529 ec_clear_on_resume, "Samsung hardware", {
1545 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, 1530 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
1546 {}, 1531 {},
@@ -1548,8 +1533,8 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
1548 1533
1549int __init acpi_ec_ecdt_probe(void) 1534int __init acpi_ec_ecdt_probe(void)
1550{ 1535{
1536 int ret = 0;
1551 acpi_status status; 1537 acpi_status status;
1552 struct acpi_ec *saved_ec = NULL;
1553 struct acpi_table_ecdt *ecdt_ptr; 1538 struct acpi_table_ecdt *ecdt_ptr;
1554 1539
1555 boot_ec = make_acpi_ec(); 1540 boot_ec = make_acpi_ec();
@@ -1561,67 +1546,45 @@ int __init acpi_ec_ecdt_probe(void)
1561 dmi_check_system(ec_dmi_table); 1546 dmi_check_system(ec_dmi_table);
1562 status = acpi_get_table(ACPI_SIG_ECDT, 1, 1547 status = acpi_get_table(ACPI_SIG_ECDT, 1,
1563 (struct acpi_table_header **)&ecdt_ptr); 1548 (struct acpi_table_header **)&ecdt_ptr);
1564 if (ACPI_SUCCESS(status)) { 1549 if (ACPI_FAILURE(status)) {
1565 pr_info("EC description table is found, configuring boot EC\n"); 1550 ret = -ENODEV;
1566 boot_ec->command_addr = ecdt_ptr->control.address; 1551 goto error;
1567 boot_ec->data_addr = ecdt_ptr->data.address;
1568 boot_ec->gpe = ecdt_ptr->gpe;
1569 boot_ec->handle = ACPI_ROOT_OBJECT;
1570 acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id,
1571 &boot_ec->handle);
1572 /* Don't trust ECDT, which comes from ASUSTek */
1573 if (!EC_FLAGS_VALIDATE_ECDT)
1574 goto install;
1575 saved_ec = kmemdup(boot_ec, sizeof(struct acpi_ec), GFP_KERNEL);
1576 if (!saved_ec)
1577 return -ENOMEM;
1578 /* fall through */
1579 } 1552 }
1580 1553
1581 if (EC_FLAGS_SKIP_DSDT_SCAN) { 1554 if (!ecdt_ptr->control.address || !ecdt_ptr->data.address) {
1582 kfree(saved_ec); 1555 /*
1583 return -ENODEV; 1556 * Asus X50GL:
1557 * https://bugzilla.kernel.org/show_bug.cgi?id=11880
1558 */
1559 ret = -ENODEV;
1560 goto error;
1584 } 1561 }
1585 1562
1586 /* This workaround is needed only on some broken machines, 1563 pr_info("EC description table is found, configuring boot EC\n");
1587 * which require early EC, but fail to provide ECDT */ 1564 if (EC_FLAGS_CORRECT_ECDT) {
1588 pr_debug("Look up EC in DSDT\n"); 1565 /*
1589 status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, 1566 * Asus L4R, Asus M6R
1590 boot_ec, NULL); 1567 * https://bugzilla.kernel.org/show_bug.cgi?id=9399
1591 /* Check that acpi_get_devices actually find something */ 1568 * MSI MS-171F
1592 if (ACPI_FAILURE(status) || !boot_ec->handle) 1569 * https://bugzilla.kernel.org/show_bug.cgi?id=12461
1593 goto error; 1570 */
1594 if (saved_ec) { 1571 boot_ec->command_addr = ecdt_ptr->data.address;
1595 /* try to find good ECDT from ASUSTek */ 1572 boot_ec->data_addr = ecdt_ptr->control.address;
1596 if (saved_ec->command_addr != boot_ec->command_addr ||
1597 saved_ec->data_addr != boot_ec->data_addr ||
1598 saved_ec->gpe != boot_ec->gpe ||
1599 saved_ec->handle != boot_ec->handle)
1600 pr_info("ASUSTek keeps feeding us with broken "
1601 "ECDT tables, which are very hard to workaround. "
1602 "Trying to use DSDT EC info instead. Please send "
1603 "output of acpidump to linux-acpi@vger.kernel.org\n");
1604 kfree(saved_ec);
1605 saved_ec = NULL;
1606 } else { 1573 } else {
1607 /* We really need to limit this workaround, the only ASUS, 1574 boot_ec->command_addr = ecdt_ptr->control.address;
1608 * which needs it, has fake EC._INI method, so use it as flag. 1575 boot_ec->data_addr = ecdt_ptr->data.address;
1609 * Keep boot_ec struct as it will be needed soon.
1610 */
1611 if (!dmi_name_in_vendors("ASUS") ||
1612 !acpi_has_method(boot_ec->handle, "_INI"))
1613 return -ENODEV;
1614 } 1576 }
1615install: 1577 boot_ec->gpe = ecdt_ptr->gpe;
1616 if (!ec_install_handlers(boot_ec)) { 1578 boot_ec->handle = ACPI_ROOT_OBJECT;
1579 ret = ec_install_handlers(boot_ec);
1580 if (!ret)
1617 first_ec = boot_ec; 1581 first_ec = boot_ec;
1618 return 0;
1619 }
1620error: 1582error:
1621 kfree(boot_ec); 1583 if (ret) {
1622 kfree(saved_ec); 1584 kfree(boot_ec);
1623 boot_ec = NULL; 1585 boot_ec = NULL;
1624 return -ENODEV; 1586 }
1587 return ret;
1625} 1588}
1626 1589
1627static int param_set_event_clearing(const char *val, struct kernel_param *kp) 1590static int param_set_event_clearing(const char *val, struct kernel_param *kp)