diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-09-07 04:50:08 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-09-09 20:33:49 -0400 |
commit | 72c77b7ea9ce781f4987840984a462e4456ba98e (patch) | |
tree | 5aa84ab38f1d66459b8c96223ed8b1d694e449af | |
parent | d30283057ecdf8c543ae757ae34db3d7fd2d7732 (diff) |
ACPI / EC: Cleanup first_ec/boot_ec code
In order to support full ECDT (driving the ECDT EC after probing the
namespace EC), we need to change our EC device alloc/free algorithm, ensure
not to free old boot EC before qualifying new boot EC.
This patch achieves this by cleaning up first_ec/boot_ec logic:
1. first_ec: used to perform transactions, so it is assigned in new
acpi_ec_setup() function.
2. boot_ec: used to track early EC device, so it is assigned in new
acpi_config_boot_ec() function which explictly tells the driver to save
the EC device as early EC device.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=115021
Reported-and-tested-by: Luya Tshimbalanga <luya@fedoraproject.org>
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>
-rw-r--r-- | drivers/acpi/ec.c | 96 |
1 files changed, 63 insertions, 33 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 1925589ecf66..9eab651a4502 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -184,6 +184,7 @@ static void acpi_ec_event_processor(struct work_struct *work); | |||
184 | 184 | ||
185 | struct acpi_ec *boot_ec, *first_ec; | 185 | struct acpi_ec *boot_ec, *first_ec; |
186 | EXPORT_SYMBOL(first_ec); | 186 | EXPORT_SYMBOL(first_ec); |
187 | static bool boot_ec_is_ecdt = false; | ||
187 | static struct workqueue_struct *ec_query_wq; | 188 | static struct workqueue_struct *ec_query_wq; |
188 | 189 | ||
189 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ | 190 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ |
@@ -1304,7 +1305,16 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
1304 | static acpi_status | 1305 | static acpi_status |
1305 | ec_parse_io_ports(struct acpi_resource *resource, void *context); | 1306 | ec_parse_io_ports(struct acpi_resource *resource, void *context); |
1306 | 1307 | ||
1307 | static struct acpi_ec *make_acpi_ec(void) | 1308 | static void acpi_ec_free(struct acpi_ec *ec) |
1309 | { | ||
1310 | if (first_ec == ec) | ||
1311 | first_ec = NULL; | ||
1312 | if (boot_ec == ec) | ||
1313 | boot_ec = NULL; | ||
1314 | kfree(ec); | ||
1315 | } | ||
1316 | |||
1317 | static struct acpi_ec *acpi_ec_alloc(void) | ||
1308 | { | 1318 | { |
1309 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); | 1319 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); |
1310 | 1320 | ||
@@ -1365,6 +1375,11 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
1365 | return AE_CTRL_TERMINATE; | 1375 | return AE_CTRL_TERMINATE; |
1366 | } | 1376 | } |
1367 | 1377 | ||
1378 | /* | ||
1379 | * Note: This function returns an error code only when the address space | ||
1380 | * handler is not installed, which means "not able to handle | ||
1381 | * transactions". | ||
1382 | */ | ||
1368 | static int ec_install_handlers(struct acpi_ec *ec) | 1383 | static int ec_install_handlers(struct acpi_ec *ec) |
1369 | { | 1384 | { |
1370 | acpi_status status; | 1385 | acpi_status status; |
@@ -1440,21 +1455,49 @@ static void ec_remove_handlers(struct acpi_ec *ec) | |||
1440 | } | 1455 | } |
1441 | } | 1456 | } |
1442 | 1457 | ||
1443 | static struct acpi_ec *acpi_ec_alloc(void) | 1458 | static int acpi_ec_setup(struct acpi_ec *ec) |
1444 | { | 1459 | { |
1445 | struct acpi_ec *ec; | 1460 | int ret; |
1446 | 1461 | ||
1447 | /* Check for boot EC */ | 1462 | ret = ec_install_handlers(ec); |
1448 | if (boot_ec) { | 1463 | if (ret) |
1449 | ec = boot_ec; | 1464 | return ret; |
1450 | boot_ec = NULL; | 1465 | |
1451 | ec_remove_handlers(ec); | 1466 | /* First EC capable of handling transactions */ |
1452 | if (first_ec == ec) | 1467 | if (!first_ec) { |
1453 | first_ec = NULL; | 1468 | first_ec = ec; |
1454 | } else { | 1469 | acpi_handle_info(first_ec->handle, "Used as first EC\n"); |
1455 | ec = make_acpi_ec(); | ||
1456 | } | 1470 | } |
1457 | return ec; | 1471 | |
1472 | acpi_handle_info(ec->handle, | ||
1473 | "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", | ||
1474 | ec->gpe, ec->command_addr, ec->data_addr); | ||
1475 | return ret; | ||
1476 | } | ||
1477 | |||
1478 | static int acpi_config_boot_ec(struct acpi_ec *ec, bool is_ecdt) | ||
1479 | { | ||
1480 | int ret; | ||
1481 | |||
1482 | if (boot_ec) | ||
1483 | ec_remove_handlers(boot_ec); | ||
1484 | |||
1485 | /* Unset old boot EC */ | ||
1486 | if (boot_ec != ec) | ||
1487 | acpi_ec_free(boot_ec); | ||
1488 | |||
1489 | ret = acpi_ec_setup(ec); | ||
1490 | if (ret) | ||
1491 | return ret; | ||
1492 | |||
1493 | /* Set new boot EC */ | ||
1494 | if (!boot_ec) { | ||
1495 | boot_ec = ec; | ||
1496 | boot_ec_is_ecdt = is_ecdt; | ||
1497 | acpi_handle_info(boot_ec->handle, "Used as boot %s EC\n", | ||
1498 | is_ecdt ? "ECDT" : "DSDT"); | ||
1499 | } | ||
1500 | return ret; | ||
1458 | } | 1501 | } |
1459 | 1502 | ||
1460 | static int acpi_ec_add(struct acpi_device *device) | 1503 | static int acpi_ec_add(struct acpi_device *device) |
@@ -1470,7 +1513,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
1470 | return -ENOMEM; | 1513 | return -ENOMEM; |
1471 | if (ec_parse_device(device->handle, 0, ec, NULL) != | 1514 | if (ec_parse_device(device->handle, 0, ec, NULL) != |
1472 | AE_CTRL_TERMINATE) { | 1515 | AE_CTRL_TERMINATE) { |
1473 | kfree(ec); | 1516 | acpi_ec_free(ec); |
1474 | return -EINVAL; | 1517 | return -EINVAL; |
1475 | } | 1518 | } |
1476 | 1519 | ||
@@ -1478,8 +1521,6 @@ static int acpi_ec_add(struct acpi_device *device) | |||
1478 | acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, | 1521 | acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, |
1479 | acpi_ec_register_query_methods, NULL, ec, NULL); | 1522 | acpi_ec_register_query_methods, NULL, ec, NULL); |
1480 | 1523 | ||
1481 | if (!first_ec) | ||
1482 | first_ec = ec; | ||
1483 | device->driver_data = ec; | 1524 | device->driver_data = ec; |
1484 | 1525 | ||
1485 | ret = !!request_region(ec->data_addr, 1, "EC data"); | 1526 | ret = !!request_region(ec->data_addr, 1, "EC data"); |
@@ -1487,10 +1528,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
1487 | ret = !!request_region(ec->command_addr, 1, "EC cmd"); | 1528 | ret = !!request_region(ec->command_addr, 1, "EC cmd"); |
1488 | WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); | 1529 | WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); |
1489 | 1530 | ||
1490 | pr_info("GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", | 1531 | ret = acpi_config_boot_ec(ec, false); |
1491 | ec->gpe, ec->command_addr, ec->data_addr); | ||
1492 | |||
1493 | ret = ec_install_handlers(ec); | ||
1494 | 1532 | ||
1495 | /* Reprobe devices depending on the EC */ | 1533 | /* Reprobe devices depending on the EC */ |
1496 | acpi_walk_dep_device_list(ec->handle); | 1534 | acpi_walk_dep_device_list(ec->handle); |
@@ -1513,9 +1551,7 @@ static int acpi_ec_remove(struct acpi_device *device) | |||
1513 | release_region(ec->data_addr, 1); | 1551 | release_region(ec->data_addr, 1); |
1514 | release_region(ec->command_addr, 1); | 1552 | release_region(ec->command_addr, 1); |
1515 | device->driver_data = NULL; | 1553 | device->driver_data = NULL; |
1516 | if (ec == first_ec) | 1554 | acpi_ec_free(ec); |
1517 | first_ec = NULL; | ||
1518 | kfree(ec); | ||
1519 | return 0; | 1555 | return 0; |
1520 | } | 1556 | } |
1521 | 1557 | ||
@@ -1567,13 +1603,10 @@ int __init acpi_ec_dsdt_probe(void) | |||
1567 | ret = -ENODEV; | 1603 | ret = -ENODEV; |
1568 | goto error; | 1604 | goto error; |
1569 | } | 1605 | } |
1570 | ret = ec_install_handlers(ec); | 1606 | ret = acpi_config_boot_ec(ec, false); |
1571 | |||
1572 | error: | 1607 | error: |
1573 | if (ret) | 1608 | if (ret) |
1574 | kfree(ec); | 1609 | acpi_ec_free(ec); |
1575 | else | ||
1576 | first_ec = boot_ec = ec; | ||
1577 | return ret; | 1610 | return ret; |
1578 | } | 1611 | } |
1579 | 1612 | ||
@@ -1671,7 +1704,6 @@ int __init acpi_ec_ecdt_probe(void) | |||
1671 | goto error; | 1704 | goto error; |
1672 | } | 1705 | } |
1673 | 1706 | ||
1674 | pr_info("EC description table is found, configuring boot EC\n"); | ||
1675 | if (EC_FLAGS_CORRECT_ECDT) { | 1707 | if (EC_FLAGS_CORRECT_ECDT) { |
1676 | ec->command_addr = ecdt_ptr->data.address; | 1708 | ec->command_addr = ecdt_ptr->data.address; |
1677 | ec->data_addr = ecdt_ptr->control.address; | 1709 | ec->data_addr = ecdt_ptr->control.address; |
@@ -1681,12 +1713,10 @@ int __init acpi_ec_ecdt_probe(void) | |||
1681 | } | 1713 | } |
1682 | ec->gpe = ecdt_ptr->gpe; | 1714 | ec->gpe = ecdt_ptr->gpe; |
1683 | ec->handle = ACPI_ROOT_OBJECT; | 1715 | ec->handle = ACPI_ROOT_OBJECT; |
1684 | ret = ec_install_handlers(ec); | 1716 | ret = acpi_config_boot_ec(ec, true); |
1685 | error: | 1717 | error: |
1686 | if (ret) | 1718 | if (ret) |
1687 | kfree(ec); | 1719 | acpi_ec_free(ec); |
1688 | else | ||
1689 | first_ec = boot_ec = ec; | ||
1690 | return ret; | 1720 | return ret; |
1691 | } | 1721 | } |
1692 | 1722 | ||