Commit 628af439 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -284,6 +284,7 @@ struct acpi_object_addr_handler {
	acpi_adr_space_handler handler;
	struct acpi_namespace_node *node;	/* Parent device */
	void *context;
	acpi_mutex context_mutex;
	acpi_adr_space_setup setup;
	union acpi_operand_object *region_list;	/* Regions using this handler */
	union acpi_operand_object *next;
+7 −0
Original line number Diff line number Diff line
@@ -489,6 +489,13 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node,

	/* 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.handler_flags = flags;
	handler_obj->address_space.region_list = NULL;
+43 −26
Original line number Diff line number Diff line
@@ -112,6 +112,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
	union acpi_operand_object *region_obj2;
	void *region_context = NULL;
	struct acpi_connection_info *context;
	acpi_mutex context_mutex;
	u8 context_locked;
	acpi_physical_address address;

	ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
@@ -136,6 +138,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
	}

	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.
@@ -204,6 +208,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
	handler = handler_desc->address_space.handler;
	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:
	 * 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,
	 *   2) Length of the above buffer
	 *   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
	 * are defined as follows:
	 *   1) Address is the pin number index of the field (bit offset from
	 *      the previous Connection)
	 *   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) {

		/* Get the Connection (resource_template) buffer */

		context->connection = field_obj->field.resource_buffer;
		context->length = field_obj->field.resource_length;
		context->access_length = field_obj->field.access_length;
		status =
		    acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
		if (ACPI_FAILURE(status)) {
			goto re_enter_interpreter;
		}
	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
	    context && field_obj) {

		context_locked = TRUE;

		/* Get the Connection (resource_template) buffer */

		context->connection = field_obj->field.resource_buffer;
		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) {
			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 &
	      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();
	}

	/* Call the handler */
@@ -261,6 +273,10 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
	status = handler(function, address, bit_width, value, context,
			 region_obj2->extra.region_context);

	if (context_locked) {
		acpi_os_release_mutex(context_mutex);
	}

	if (ACPI_FAILURE(status)) {
		ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
				acpi_ut_get_region_name(region_obj->region.
@@ -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 &
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
		/*
+2 −0
Original line number Diff line number Diff line
@@ -201,6 +201,8 @@ acpi_remove_address_space_handler(acpi_handle device,

			/* Now we can delete the handler object */

			acpi_os_release_mutex(handler_obj->address_space.
					      context_mutex);
			acpi_ut_remove_reference(handler_obj);
			goto unlock_and_exit;
		}