diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-07-08 04:25:05 +0300 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-07-08 22:44:12 +0300 |
commit | fa5b4a509d7bbba5d45c8ea177bddfd0b618876a (patch) | |
tree | 530ec2195a8df480e5e2f197cf21d61cf3143951 /drivers/acpi/ec.c | |
parent | a99cde438de0c4c0cecc1d1af1a55a75b10bfdef (diff) | |
download | linux-fa5b4a509d7bbba5d45c8ea177bddfd0b618876a.tar.xz |
ACPI / EC: Fix code ordering issue in ec_remove_handlers()
There is an order issue in ec_remove_handlers() that acpi_ec_stop()
is called before removing the operation region handler. That is
incorrect, because the operation region handler removal triggers
_REG(DISCONNECT) which may result in new EC transactions to carry
out.
That existing issue has been triggered by the following commit:
Commit: dcf15cbded656a12335bc4151f3f75f10080a375
Subject: ACPI / EC: Fix a boot EC regresion by restoring boot EC
which changed the driver to call ec_remove_handlers() after invoking
_REG(CONNECT), so the issue has become visible.
Fixes: dcf15cbded65 (ACPI / EC: Fix a boot EC regresion by restoring boot EC)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=102421
Reported-and-tested-by: Wolfram Sang <wsa@the-dreams.de>
Reported-by: Nicholas <nkudriavtsev@gmail.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
[ rjw: Changelog ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 73c76d646064..290d6f5be44b 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1331,8 +1331,6 @@ static int ec_install_handlers(struct acpi_ec *ec) static void ec_remove_handlers(struct acpi_ec *ec) { - acpi_ec_stop(ec, false); - if (test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) @@ -1340,6 +1338,19 @@ static void ec_remove_handlers(struct acpi_ec *ec) clear_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags); } + /* + * Stops handling the EC transactions after removing the operation + * region handler. This is required because _REG(DISCONNECT) + * invoked during the removal can result in new EC transactions. + * + * Flushes the EC requests and thus disables the GPE before + * removing the GPE handler. This is required by the current ACPICA + * GPE core. ACPICA GPE core will automatically disable a GPE when + * it is indicated but there is no way to handle it. So the drivers + * must disable the GPEs prior to removing the GPE handlers. + */ + acpi_ec_stop(ec, false); + if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) { if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler))) |