summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-09-07 04:50:27 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-09-09 20:33:50 -0400
commit97cb159fd91d00f8d7d1adeb075503dc0d946bff (patch)
tree75952cf8e88ada30839ccca69337b14ef8346b6d /drivers/acpi
parent2a5708409e4e05446eb1a89ecb48641d6fd5d5a9 (diff)
ACPI / EC: Fix issues related to boot_ec
There are issues related to the boot_ec: 1. If acpi_ec_remove() is invoked, boot_ec will also be freed, this is not expected as the boot_ec could be enumerated via ECDT. 2. Address space handler installation/unstallation lead to unexpected _REG evaluations. This patch adds acpi_is_boot_ec() check to be used to fix the above issues. However, since acpi_ec_remove() actually won't be invoked, this patch doesn't handle the reference counting of "struct acpi_ec", it only ensures the correctness of the boot_ec destruction during the boot. Link: https://bugzilla.kernel.org/show_bug.cgi?id=153511 Reported-and-tested-by: Jonh Henderson <jw.hendy@gmail.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/ec.c63
1 files changed, 49 insertions, 14 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2ae9194cc630..680531062160 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1536,6 +1536,37 @@ static int acpi_config_boot_ec(struct acpi_ec *ec, acpi_handle handle,
1536 return ret; 1536 return ret;
1537} 1537}
1538 1538
1539static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle)
1540{
1541 struct acpi_table_ecdt *ecdt_ptr;
1542 acpi_status status;
1543 acpi_handle handle;
1544
1545 status = acpi_get_table(ACPI_SIG_ECDT, 1,
1546 (struct acpi_table_header **)&ecdt_ptr);
1547 if (ACPI_FAILURE(status))
1548 return false;
1549
1550 status = acpi_get_handle(NULL, ecdt_ptr->id, &handle);
1551 if (ACPI_FAILURE(status))
1552 return false;
1553
1554 *phandle = handle;
1555 return true;
1556}
1557
1558static bool acpi_is_boot_ec(struct acpi_ec *ec)
1559{
1560 if (!boot_ec)
1561 return false;
1562 if (ec->handle == boot_ec->handle &&
1563 ec->gpe == boot_ec->gpe &&
1564 ec->command_addr == boot_ec->command_addr &&
1565 ec->data_addr == boot_ec->data_addr)
1566 return true;
1567 return false;
1568}
1569
1539static int acpi_ec_add(struct acpi_device *device) 1570static int acpi_ec_add(struct acpi_device *device)
1540{ 1571{
1541 struct acpi_ec *ec = NULL; 1572 struct acpi_ec *ec = NULL;
@@ -1553,7 +1584,14 @@ static int acpi_ec_add(struct acpi_device *device)
1553 goto err_alloc; 1584 goto err_alloc;
1554 } 1585 }
1555 1586
1556 ret = acpi_config_boot_ec(ec, device->handle, true, false); 1587 if (acpi_is_boot_ec(ec)) {
1588 boot_ec_is_ecdt = false;
1589 acpi_handle_debug(ec->handle, "duplicated.\n");
1590 acpi_ec_free(ec);
1591 ec = boot_ec;
1592 ret = acpi_config_boot_ec(ec, ec->handle, true, false);
1593 } else
1594 ret = acpi_ec_setup(ec, true);
1557 if (ret) 1595 if (ret)
1558 goto err_query; 1596 goto err_query;
1559 1597
@@ -1566,12 +1604,15 @@ static int acpi_ec_add(struct acpi_device *device)
1566 1604
1567 /* Reprobe devices depending on the EC */ 1605 /* Reprobe devices depending on the EC */
1568 acpi_walk_dep_device_list(ec->handle); 1606 acpi_walk_dep_device_list(ec->handle);
1607 acpi_handle_debug(ec->handle, "enumerated.\n");
1569 return 0; 1608 return 0;
1570 1609
1571err_query: 1610err_query:
1572 acpi_ec_remove_query_handlers(ec, true, 0); 1611 if (ec != boot_ec)
1612 acpi_ec_remove_query_handlers(ec, true, 0);
1573err_alloc: 1613err_alloc:
1574 acpi_ec_free(ec); 1614 if (ec != boot_ec)
1615 acpi_ec_free(ec);
1575 return ret; 1616 return ret;
1576} 1617}
1577 1618
@@ -1583,11 +1624,13 @@ static int acpi_ec_remove(struct acpi_device *device)
1583 return -EINVAL; 1624 return -EINVAL;
1584 1625
1585 ec = acpi_driver_data(device); 1626 ec = acpi_driver_data(device);
1586 ec_remove_handlers(ec);
1587 release_region(ec->data_addr, 1); 1627 release_region(ec->data_addr, 1);
1588 release_region(ec->command_addr, 1); 1628 release_region(ec->command_addr, 1);
1589 device->driver_data = NULL; 1629 device->driver_data = NULL;
1590 acpi_ec_free(ec); 1630 if (ec != boot_ec) {
1631 ec_remove_handlers(ec);
1632 acpi_ec_free(ec);
1633 }
1591 return 0; 1634 return 0;
1592} 1635}
1593 1636
@@ -1659,8 +1702,6 @@ error:
1659 */ 1702 */
1660int __init acpi_ec_ecdt_start(void) 1703int __init acpi_ec_ecdt_start(void)
1661{ 1704{
1662 struct acpi_table_ecdt *ecdt_ptr;
1663 acpi_status status;
1664 acpi_handle handle; 1705 acpi_handle handle;
1665 1706
1666 if (!boot_ec) 1707 if (!boot_ec)
@@ -1672,17 +1713,11 @@ int __init acpi_ec_ecdt_start(void)
1672 if (!boot_ec_is_ecdt) 1713 if (!boot_ec_is_ecdt)
1673 return -ENODEV; 1714 return -ENODEV;
1674 1715
1675 status = acpi_get_table(ACPI_SIG_ECDT, 1,
1676 (struct acpi_table_header **)&ecdt_ptr);
1677 if (ACPI_FAILURE(status))
1678 return -ENODEV;
1679
1680 /* 1716 /*
1681 * At this point, the namespace and the GPE is initialized, so 1717 * At this point, the namespace and the GPE is initialized, so
1682 * start to find the namespace objects and handle the events. 1718 * start to find the namespace objects and handle the events.
1683 */ 1719 */
1684 status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); 1720 if (!acpi_ec_ecdt_get_handle(&handle))
1685 if (ACPI_FAILURE(status))
1686 return -ENODEV; 1721 return -ENODEV;
1687 return acpi_config_boot_ec(boot_ec, handle, true, true); 1722 return acpi_config_boot_ec(boot_ec, handle, true, true);
1688} 1723}