>From 6f2fac0ffcd7fd61036baa0798ab171496cff50f Mon Sep 17 00:00:00 2001 From: Zhang Rui <rui.zhang@xxxxxxxxx> Date: Fri, 4 Jan 2019 14:35:52 +0800 Subject: [PATCH] ACPI/ACPICA: Run EC _REG explicitly for ECDT commit d737f333b211 ("ACPI: probe ECDT before loading AML tables regardless of module-level code flag") probes ECDT before loading the AML tables. This is the right thing to do according to the ACPI Spec, but unfortunately, it breaks the current kernel EC/ECDT support, and makes many devices, including battery, lid, etc, fails to work on a variety of platforms. This is because: 1. Probing ECDT requires installing EC address space handler 2. EC _REG can not be evaluated at the time when probing ECDT because AML tables have not been loaded yet. 3. Many devices fail to work because EC _REG is not evaluated. To fix this, a solution is proposed in this patch to evaluate EC _REG explicitly in ACPICA, if ECDT has been probed. Fixes: d737f333b211 ("ACPI: probe ECDT before loading AML tables regardless of module-level code flag") BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199981 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=201351 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=200011 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=200141 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=201679 Signed-off-by: Zhang Rui <rui.zhang@xxxxxxxxx> --- drivers/acpi/acpica/acevents.h | 4 ++-- drivers/acpi/acpica/evhandler.c | 21 ++++++++++++++------- drivers/acpi/acpica/evregion.c | 10 ++++++++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index b412aa9..2f43ab0 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -155,8 +155,8 @@ union acpi_operand_object *acpi_ev_find_region_handler(acpi_adr_space_type *handler_obj); u8 -acpi_ev_has_default_handler(struct acpi_namespace_node *node, - acpi_adr_space_type space_id); +acpi_ev_has_handler(struct acpi_namespace_node *node, + acpi_adr_space_type space_id, bool default_handler); acpi_status acpi_ev_install_region_handlers(void); diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 4ed1e67..c6d61fd 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -102,21 +102,22 @@ acpi_status acpi_ev_install_region_handlers(void) /******************************************************************************* * - * FUNCTION: acpi_ev_has_default_handler + * FUNCTION: acpi_ev_has_handler * * PARAMETERS: node - Namespace node for the device * space_id - The address space ID + * default_handler - check for default handler * - * RETURN: TRUE if default handler is installed, FALSE otherwise + * RETURN: TRUE if handler is installed, FALSE otherwise * - * DESCRIPTION: Check if the default handler is installed for the requested + * DESCRIPTION: Check if the handler is installed for the requested * space ID. * ******************************************************************************/ u8 -acpi_ev_has_default_handler(struct acpi_namespace_node *node, - acpi_adr_space_type space_id) +acpi_ev_has_handler(struct acpi_namespace_node *node, + acpi_adr_space_type space_id, bool default_handler) { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; @@ -131,8 +132,14 @@ acpi_ev_has_default_handler(struct acpi_namespace_node *node, while (handler_obj) { if (handler_obj->address_space.space_id == space_id) { - if (handler_obj->address_space.handler_flags & - ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { + if (default_handler && + (handler_obj->address_space.handler_flags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + return (TRUE); + } + if (!default_handler && + !(handler_obj->address_space.handler_flags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { return (TRUE); } } diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 49decca..2b04cf5 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -60,15 +60,21 @@ acpi_status acpi_ev_initialize_op_regions(void) * default, the _REG methods will have already been run (when the * handler was installed) */ - if (acpi_ev_has_default_handler(acpi_gbl_root_node, + if (acpi_ev_has_handler(acpi_gbl_root_node, acpi_gbl_default_address_spaces - [i])) { + [i], true)) { acpi_ev_execute_reg_methods(acpi_gbl_root_node, acpi_gbl_default_address_spaces [i], ACPI_REG_CONNECT); } } + /* Run _REG methods for EC Operation Region if ECDT has been probed */ + if (acpi_ev_has_handler(acpi_gbl_root_node, ACPI_ADR_SPACE_EC, false)) + acpi_ev_execute_reg_methods(acpi_gbl_root_node, + ACPI_ADR_SPACE_EC, + ACPI_REG_CONNECT); + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); } -- 2.7.4