Commit 628af439 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'acpi-5.12-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more ACPI updates from Rafael Wysocki:
 "Fix race condition in generic_serial_bus (I2C) and GPIO Operation
  Region handling in ACPICA and reduce some related code duplication
  (Hans de Goede)"

* tag 'acpi-5.12-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPICA: Remove some code duplication from acpi_ev_address_space_dispatch
  ACPICA: Fix race in generic_serial_bus (I2C) and GPIO op_region parameter handling
parents 005d3bd9 833a18d0
...@@ -284,6 +284,7 @@ struct acpi_object_addr_handler { ...@@ -284,6 +284,7 @@ struct acpi_object_addr_handler {
acpi_adr_space_handler handler; acpi_adr_space_handler handler;
struct acpi_namespace_node *node; /* Parent device */ struct acpi_namespace_node *node; /* Parent device */
void *context; void *context;
acpi_mutex context_mutex;
acpi_adr_space_setup setup; acpi_adr_space_setup setup;
union acpi_operand_object *region_list; /* Regions using this handler */ union acpi_operand_object *region_list; /* Regions using this handler */
union acpi_operand_object *next; union acpi_operand_object *next;
......
...@@ -489,6 +489,13 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node, ...@@ -489,6 +489,13 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node,
/* Init handler obj */ /* Init handler obj */
status =
acpi_os_create_mutex(&handler_obj->address_space.context_mutex);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(handler_obj);
goto unlock_and_exit;
}
handler_obj->address_space.space_id = (u8)space_id; handler_obj->address_space.space_id = (u8)space_id;
handler_obj->address_space.handler_flags = flags; handler_obj->address_space.handler_flags = flags;
handler_obj->address_space.region_list = NULL; handler_obj->address_space.region_list = NULL;
......
...@@ -112,6 +112,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -112,6 +112,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
union acpi_operand_object *region_obj2; union acpi_operand_object *region_obj2;
void *region_context = NULL; void *region_context = NULL;
struct acpi_connection_info *context; struct acpi_connection_info *context;
acpi_mutex context_mutex;
u8 context_locked;
acpi_physical_address address; acpi_physical_address address;
ACPI_FUNCTION_TRACE(ev_address_space_dispatch); ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
...@@ -136,6 +138,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -136,6 +138,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
} }
context = handler_desc->address_space.context; context = handler_desc->address_space.context;
context_mutex = handler_desc->address_space.context_mutex;
context_locked = FALSE;
/* /*
* It may be the case that the region has never been initialized. * It may be the case that the region has never been initialized.
...@@ -204,6 +208,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -204,6 +208,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
handler = handler_desc->address_space.handler; handler = handler_desc->address_space.handler;
address = (region_obj->region.address + region_offset); address = (region_obj->region.address + region_offset);
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.handler->address_space, handler,
ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(region_obj->region.
space_id)));
if (!(handler_desc->address_space.handler_flags &
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
/*
* For handlers other than the default (supplied) handlers, we must
* exit the interpreter because the handler *might* block -- we don't
* know what it will do, so we can't hold the lock on the interpreter.
*/
acpi_ex_exit_interpreter();
}
/* /*
* Special handling for generic_serial_bus and general_purpose_io: * Special handling for generic_serial_bus and general_purpose_io:
* There are three extra parameters that must be passed to the * There are three extra parameters that must be passed to the
...@@ -212,48 +233,39 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -212,48 +233,39 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* 2) Length of the above buffer * 2) Length of the above buffer
* 3) Actual access length from the access_as() op * 3) Actual access length from the access_as() op
* *
* Since we pass these extra parameters via the context, which is
* shared between threads, we must lock the context to avoid these
* parameters being changed from another thread before the handler
* has completed running.
*
* In addition, for general_purpose_io, the Address and bit_width fields * In addition, for general_purpose_io, the Address and bit_width fields
* are defined as follows: * are defined as follows:
* 1) Address is the pin number index of the field (bit offset from * 1) Address is the pin number index of the field (bit offset from
* the previous Connection) * the previous Connection)
* 2) bit_width is the actual bit length of the field (number of pins) * 2) bit_width is the actual bit length of the field (number of pins)
*/ */
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS ||
region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
context && field_obj) { context && field_obj) {
/* Get the Connection (resource_template) buffer */ status =
acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
goto re_enter_interpreter;
}
context->connection = field_obj->field.resource_buffer; context_locked = TRUE;
context->length = field_obj->field.resource_length;
context->access_length = field_obj->field.access_length;
}
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
context && field_obj) {
/* Get the Connection (resource_template) buffer */ /* Get the Connection (resource_template) buffer */
context->connection = field_obj->field.resource_buffer; context->connection = field_obj->field.resource_buffer;
context->length = field_obj->field.resource_length; context->length = field_obj->field.resource_length;
context->access_length = field_obj->field.access_length; context->access_length = field_obj->field.access_length;
address = field_obj->field.pin_number_index;
bit_width = field_obj->field.bit_length;
}
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.handler->address_space, handler,
ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(region_obj->region.
space_id)));
if (!(handler_desc->address_space.handler_flags & if (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) {
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { address = field_obj->field.pin_number_index;
/* bit_width = field_obj->field.bit_length;
* For handlers other than the default (supplied) handlers, we must }
* exit the interpreter because the handler *might* block -- we don't
* know what it will do, so we can't hold the lock on the interpreter.
*/
acpi_ex_exit_interpreter();
} }
/* Call the handler */ /* Call the handler */
...@@ -261,6 +273,10 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -261,6 +273,10 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
status = handler(function, address, bit_width, value, context, status = handler(function, address, bit_width, value, context,
region_obj2->extra.region_context); region_obj2->extra.region_context);
if (context_locked) {
acpi_os_release_mutex(context_mutex);
}
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
acpi_ut_get_region_name(region_obj->region. acpi_ut_get_region_name(region_obj->region.
...@@ -277,6 +293,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -277,6 +293,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
} }
} }
re_enter_interpreter:
if (!(handler_desc->address_space.handler_flags & if (!(handler_desc->address_space.handler_flags &
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
/* /*
......
...@@ -201,6 +201,8 @@ acpi_remove_address_space_handler(acpi_handle device, ...@@ -201,6 +201,8 @@ acpi_remove_address_space_handler(acpi_handle device,
/* Now we can delete the handler object */ /* Now we can delete the handler object */
acpi_os_release_mutex(handler_obj->address_space.
context_mutex);
acpi_ut_remove_reference(handler_obj); acpi_ut_remove_reference(handler_obj);
goto unlock_and_exit; goto unlock_and_exit;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment