ACPI: Unbundle execution of _REG methods From: Alexey Starikovskiy It is too early to run _REG method during the initialization of EC space handler from ECDT. ACPI specification declares that _REG execution should be postponed to after all _INI methods are evaluted, thus _REG method execution is unbundled from installing of space handlers, and for EC ECDT init case moved to later stage. Signed-off-by: Alexey Starikovskiy --- drivers/acpi/ec.c | 26 +++++++++++++----- drivers/acpi/events/evxfregn.c | 57 ++++++++++++++++++++++++++++++++++++---- include/acpi/acpixf.h | 8 ++++++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index caf873c..a7c962b 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -129,7 +129,8 @@ static struct acpi_ec { struct mutex lock; wait_queue_head_t wait; struct list_head list; - u8 handlers_installed; + u8 handlers_installed:1; + u8 reg_executed:1; } *boot_ec, *first_ec; /* -------------------------------------------------------------------------- @@ -895,6 +896,12 @@ static int acpi_ec_start(struct acpi_device *device) ret = ec_install_handlers(ec); + if (!ret && !ec->reg_executed && + ACPI_FAILURE(acpi_execute_reg_methods(ec->handle, + ACPI_ADR_SPACE_EC))) + return -ENODEV; + ec->reg_executed = 1; + /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); return ret; @@ -915,13 +922,18 @@ static int acpi_ec_stop(struct acpi_device *device, int type) int __init acpi_boot_ec_enable(void) { - if (!boot_ec || boot_ec->handlers_installed) - return 0; - if (!ec_install_handlers(boot_ec)) { - first_ec = boot_ec; + if (!boot_ec) return 0; - } - return -EFAULT; + if (!boot_ec->handlers_installed && ec_install_handlers(boot_ec)) + return -EFAULT; + + if (!boot_ec->reg_executed && + ACPI_FAILURE(acpi_execute_reg_methods(boot_ec->handle, + ACPI_ADR_SPACE_EC))) + return -EFAULT; + boot_ec->reg_executed = 1; + first_ec = boot_ec; + return 0; } int __init acpi_ec_ecdt_probe(void) diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 7bf09c5..7cc1c78 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -65,10 +65,10 @@ ACPI_MODULE_NAME("evxfregn") * ******************************************************************************/ acpi_status -acpi_install_address_space_handler(acpi_handle device, - acpi_adr_space_type space_id, - acpi_adr_space_handler handler, - acpi_adr_space_setup setup, void *context) +acpi_install_address_space_handler_noreg(acpi_handle device, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, void *context) { struct acpi_namespace_node *node; acpi_status status; @@ -103,15 +103,60 @@ acpi_install_address_space_handler(acpi_handle device, goto unlock_and_exit; } - /* Run all _REG methods for this address space */ + unlock_and_exit: + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler_noreg) + +acpi_status acpi_execute_reg_methods(acpi_handle device, + acpi_adr_space_type space_id) +{ + struct acpi_namespace_node *node; + acpi_status status; + if (!device) { + return AE_BAD_PARAMETER; + } + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Convert and validate the device handle */ + + node = acpi_ns_map_handle_to_node(device); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Run all _REG methods for this address space */ status = acpi_ev_execute_reg_methods(node, space_id); - unlock_and_exit: + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods) + +acpi_status +acpi_install_address_space_handler(acpi_handle device, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup,void *context) +{ + acpi_status status; + status = acpi_install_address_space_handler_noreg(device, space_id, + handler, setup, + context); + if (ACPI_FAILURE(status)) + return status; + status = acpi_execute_reg_methods(device, space_id); + return status; +} + ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler) /******************************************************************************* diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index d970f7f..fbb6769 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -211,6 +211,14 @@ acpi_install_address_space_handler(acpi_handle device, acpi_adr_space_type space_id, acpi_adr_space_handler handler, acpi_adr_space_setup setup, void *context); +acpi_status +acpi_install_address_space_handler_noreg(acpi_handle device, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, + void *context); +acpi_status acpi_execute_reg_methods(acpi_handle device, + acpi_adr_space_type space_id); acpi_status acpi_remove_address_space_handler(acpi_handle device,