diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 7c584d490d6a..27ab2283937a 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -243,6 +244,28 @@ acpi_extract_package(union acpi_object *package, EXPORT_SYMBOL(acpi_extract_package); +static DEFINE_MUTEX(acpi_exclusive_eval_lock); + +/** + * acpi_evaluate_object_exclusive - Evaluate an object without interleaving + * @handle: ACPI handle of the object or its scope. + * @pathname: Path of the object relative to @handle. + * @arguments: Arguments to pass, or NULL. + * @buffer: Buffer for the return value, or NULL. + * + * Same as acpi_evaluate_object(), but serialized with other exclusive + * evaluations. Use it only for methods known to break when interleaved. + */ +acpi_status acpi_evaluate_object_exclusive(acpi_handle handle, acpi_string pathname, + struct acpi_object_list *arguments, + struct acpi_buffer *buffer) +{ + guard(mutex)(&acpi_exclusive_eval_lock); + + return acpi_evaluate_object(handle, pathname, arguments, buffer); +} +EXPORT_SYMBOL_GPL(acpi_evaluate_object_exclusive); + acpi_status acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, @@ -277,6 +300,16 @@ acpi_evaluate_integer(acpi_handle handle, EXPORT_SYMBOL(acpi_evaluate_integer); +acpi_status acpi_evaluate_integer_exclusive(acpi_handle handle, acpi_string pathname, + struct acpi_object_list *arguments, + unsigned long long *data) +{ + guard(mutex)(&acpi_exclusive_eval_lock); + + return acpi_evaluate_integer(handle, pathname, arguments, data); +} +EXPORT_SYMBOL_GPL(acpi_evaluate_integer_exclusive); + int acpi_get_local_u64_address(acpi_handle handle, u64 *addr) { acpi_status status; @@ -685,6 +718,14 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, } EXPORT_SYMBOL(acpi_execute_simple_method); +acpi_status acpi_execute_simple_method_exclusive(acpi_handle handle, char *method, u64 arg) +{ + guard(mutex)(&acpi_exclusive_eval_lock); + + return acpi_execute_simple_method(handle, method, arg); +} +EXPORT_SYMBOL_GPL(acpi_execute_simple_method_exclusive); + /** * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations * @handle: ACPI device handle diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a755b15af9db..f59b2de865e6 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -34,6 +34,12 @@ acpi_status acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, struct acpi_object_list *arguments, unsigned long long *data); +acpi_status acpi_evaluate_object_exclusive(acpi_handle handle, acpi_string pathname, + struct acpi_object_list *arguments, + struct acpi_buffer *buffer); +acpi_status acpi_evaluate_integer_exclusive(acpi_handle handle, acpi_string pathname, + struct acpi_object_list *arguments, + unsigned long long *data); bool acpi_evaluate_reference(acpi_handle handle, acpi_string pathname, struct acpi_object_list *arguments, struct acpi_handle_list *list); @@ -50,6 +56,7 @@ acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code, bool acpi_has_method(acpi_handle handle, char *name); acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, u64 arg); +acpi_status acpi_execute_simple_method_exclusive(acpi_handle handle, char *method, u64 arg); acpi_status acpi_evaluate_ej0(acpi_handle handle); acpi_status acpi_evaluate_lck(acpi_handle handle, int lock); acpi_status acpi_evaluate_reg(acpi_handle handle, u8 space_id, u32 function);