Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba886cd4 authored by Bob Moore's avatar Bob Moore Committed by Len Brown
Browse files

ACPICA: Update for mutiple global lock acquisitions by same thread



Allows AcpiAcquireGlobalLock external interface to be called
multiple times by the
 same thread. Allows use of AML fields that require the global
 lock while the running AML is already holding the global lock.

Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarAlexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent f654ecbf
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -232,9 +232,9 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
		 * recursive call.
		 */
		if (!walk_state ||
		    !obj_desc->method.mutex->mutex.owner_thread ||
		    (walk_state->thread !=
		     obj_desc->method.mutex->mutex.owner_thread)) {
		    !obj_desc->method.mutex->mutex.thread_id ||
		    (walk_state->thread->thread_id !=
		     obj_desc->method.mutex->mutex.thread_id)) {
			/*
			 * Acquire the method mutex. This releases the interpreter if we
			 * block (and reacquires it before it returns)
@@ -254,8 +254,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
				    original_sync_level =
				    walk_state->thread->current_sync_level;

				obj_desc->method.mutex->mutex.owner_thread =
				    walk_state->thread;
				obj_desc->method.mutex->mutex.thread_id =
				    walk_state->thread->thread_id;
				walk_state->thread->current_sync_level =
				    obj_desc->method.sync_level;
			} else {
@@ -569,7 +569,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,

			acpi_os_release_mutex(method_desc->method.mutex->mutex.
					      os_mutex);
			method_desc->method.mutex->mutex.owner_thread = NULL;
			method_desc->method.mutex->mutex.thread_id = 0;
		}
	}

+6 −5
Original line number Diff line number Diff line
@@ -439,7 +439,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
	 * Only one thread can acquire the GL at a time, the global_lock_mutex
	 * enforces this. This interface releases the interpreter if we must wait.
	 */
	status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, 0);
	status = acpi_ex_system_wait_mutex(
			acpi_gbl_global_lock_mutex->mutex.os_mutex, 0);
	if (status == AE_TIME) {
		if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) {
			acpi_ev_global_lock_acquired++;
@@ -448,8 +449,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
	}

	if (ACPI_FAILURE(status)) {
		status =
		    acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex,
		status = acpi_ex_system_wait_mutex(
				acpi_gbl_global_lock_mutex->mutex.os_mutex,
				timeout);
	}
	if (ACPI_FAILURE(status)) {
@@ -555,7 +556,7 @@ acpi_status acpi_ev_release_global_lock(void)
	/* Release the local GL mutex */
	acpi_ev_global_lock_thread_id = NULL;
	acpi_ev_global_lock_acquired = 0;
	acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
	acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
	return_ACPI_STATUS(status);
}

+22 −4
Original line number Diff line number Diff line
@@ -758,6 +758,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
 *
 * DESCRIPTION: Acquire the ACPI Global Lock
 *
 * Note: Allows callers with the same thread ID to acquire the global lock
 * multiple times. In other words, externally, the behavior of the global lock
 * is identical to an AML mutex. On the first acquire, a new handle is
 * returned. On any subsequent calls to acquire by the same thread, the same
 * handle is returned.
 *
 ******************************************************************************/
acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
{
@@ -770,14 +776,26 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
	/* Must lock interpreter to prevent race conditions */

	acpi_ex_enter_interpreter();
	status = acpi_ev_acquire_global_lock(timeout);
	acpi_ex_exit_interpreter();

	status = acpi_ex_acquire_mutex_object(timeout,
					      acpi_gbl_global_lock_mutex,
					      acpi_os_get_thread_id());

	if (ACPI_SUCCESS(status)) {
		/*
		 * If this was the first acquisition of the Global Lock by this thread,
		 * create a new handle. Otherwise, return the existing handle.
		 */
		if (acpi_gbl_global_lock_mutex->mutex.acquisition_depth == 1) {
			acpi_gbl_global_lock_handle++;
		}

		/* Return the global lock handle */

		*handle = acpi_gbl_global_lock_handle;
	}

	acpi_ex_exit_interpreter();
	return (status);
}

@@ -802,7 +820,7 @@ acpi_status acpi_release_global_lock(u32 handle)
		return (AE_NOT_ACQUIRED);
	}

	status = acpi_ev_release_global_lock();
	status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
	return (status);
}

+8 −16
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
	union acpi_operand_object *buffer_desc;
	acpi_size length;
	void *buffer;
	u8 locked;

	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);

@@ -111,9 +110,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,

		/* Lock entire transaction if requested */

		locked =
		    acpi_ex_acquire_global_lock(obj_desc->common_field.
						field_flags);
		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

		/*
		 * Perform the read.
@@ -125,7 +122,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
							     buffer.pointer),
					       ACPI_READ | (obj_desc->field.
							    attribute << 16));
		acpi_ex_release_global_lock(locked);
		acpi_ex_release_global_lock();
		goto exit;
	}

@@ -175,13 +172,12 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,

	/* Lock entire transaction if requested */

	locked =
	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

	/* Read from the field */

	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
	acpi_ex_release_global_lock(locked);
	acpi_ex_release_global_lock();

      exit:
	if (ACPI_FAILURE(status)) {
@@ -217,7 +213,6 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
	u32 required_length;
	void *buffer;
	void *new_buffer;
	u8 locked;
	union acpi_operand_object *buffer_desc;

	ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -278,9 +273,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,

		/* Lock entire transaction if requested */

		locked =
		    acpi_ex_acquire_global_lock(obj_desc->common_field.
						field_flags);
		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

		/*
		 * Perform the write (returns status and perhaps data in the
@@ -291,7 +284,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
					       (acpi_integer *) buffer,
					       ACPI_WRITE | (obj_desc->field.
							     attribute << 16));
		acpi_ex_release_global_lock(locked);
		acpi_ex_release_global_lock();

		*result_desc = buffer_desc;
		return_ACPI_STATUS(status);
@@ -366,13 +359,12 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,

	/* Lock entire transaction if requested */

	locked =
	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

	/* Write to the field */

	status = acpi_ex_insert_into_field(obj_desc, buffer, length);
	acpi_ex_release_global_lock(locked);
	acpi_ex_release_global_lock();

	/* Free temporary buffer if we used one */

+126 −68
Original line number Diff line number Diff line
@@ -124,6 +124,66 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
	thread->acquired_mutex_list = obj_desc;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_acquire_mutex_object
 *
 * PARAMETERS:  time_desc           - Timeout in milliseconds
 *              obj_desc            - Mutex object
 *              Thread              - Current thread state
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Acquire an AML mutex, low-level interface
 *
 ******************************************************************************/

acpi_status
acpi_ex_acquire_mutex_object(u16 timeout,
			     union acpi_operand_object *obj_desc,
			     acpi_thread_id thread_id)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc);

	/* Support for multiple acquires by the owning thread */

	if (obj_desc->mutex.thread_id == thread_id) {
		/*
		 * The mutex is already owned by this thread, just increment the
		 * acquisition depth
		 */
		obj_desc->mutex.acquisition_depth++;
		return_ACPI_STATUS(AE_OK);
	}

	/* Acquire the mutex, wait if necessary. Special case for Global Lock */

	if (obj_desc == acpi_gbl_global_lock_mutex) {
		status = acpi_ev_acquire_global_lock(timeout);
	} else {
		status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
						   timeout);
	}

	if (ACPI_FAILURE(status)) {

		/* Includes failure from a timeout on time_desc */

		return_ACPI_STATUS(status);
	}

	/* Have the mutex: update mutex and save the sync_level */

	obj_desc->mutex.thread_id = thread_id;
	obj_desc->mutex.acquisition_depth = 1;
	obj_desc->mutex.original_sync_level = 0;
	obj_desc->mutex.owner_thread = NULL;	/* Used only for AML Acquire() */

	return_ACPI_STATUS(AE_OK);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_acquire_mutex
@@ -161,7 +221,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
	}

	/*
	 * Current Sync must be less than or equal to the sync level of the
	 * Current Sync level must be less than or equal to the sync level of the
	 * mutex. This mechanism provides some deadlock prevention
	 */
	if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
@@ -172,51 +232,70 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
		return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
	}

	/* Support for multiple acquires by the owning thread */
	status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value,
					      obj_desc,
					      walk_state->thread->thread_id);
	if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) {
		obj_desc->mutex.owner_thread = walk_state->thread;
		obj_desc->mutex.original_sync_level =
		    walk_state->thread->current_sync_level;
		walk_state->thread->current_sync_level =
		    obj_desc->mutex.sync_level;

	if (obj_desc->mutex.owner_thread) {
		if (obj_desc->mutex.owner_thread->thread_id ==
		    walk_state->thread->thread_id) {
			/*
			 * The mutex is already owned by this thread, just increment the
			 * acquisition depth
			 */
			obj_desc->mutex.acquisition_depth++;
			return_ACPI_STATUS(AE_OK);
		/* Link the mutex to the current thread for force-unlock at method exit */

		acpi_ex_link_mutex(obj_desc, walk_state->thread);
	}

	return_ACPI_STATUS(status);
}

	/* Acquire the mutex, wait if necessary. Special case for Global Lock */
/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_release_mutex_object
 *
 * PARAMETERS:  obj_desc            - The object descriptor for this op
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Release a previously acquired Mutex, low level interface.
 *
 ******************************************************************************/

	if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
		status =
		    acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
	} else {
		status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
						   (u16) time_desc->integer.
						   value);
	}
acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
{
	acpi_status status = AE_OK;

	if (ACPI_FAILURE(status)) {
	ACPI_FUNCTION_TRACE(ex_release_mutex_object);

		/* Includes failure from a timeout on time_desc */
	/* Match multiple Acquires with multiple Releases */

		return_ACPI_STATUS(status);
	obj_desc->mutex.acquisition_depth--;
	if (obj_desc->mutex.acquisition_depth != 0) {

		/* Just decrement the depth and return */

		return_ACPI_STATUS(AE_OK);
	}

	/* Have the mutex: update mutex and walk info and save the sync_level */
	if (obj_desc->mutex.owner_thread) {

	obj_desc->mutex.owner_thread = walk_state->thread;
	obj_desc->mutex.acquisition_depth = 1;
	obj_desc->mutex.original_sync_level =
	    walk_state->thread->current_sync_level;
		/* Unlink the mutex from the owner's list */

	walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
		acpi_ex_unlink_mutex(obj_desc);
		obj_desc->mutex.owner_thread = NULL;
	}

	/* Link the mutex to the current thread for force-unlock at method exit */
	/* Release the mutex, special case for Global Lock */

	acpi_ex_link_mutex(obj_desc, walk_state->thread);
	return_ACPI_STATUS(AE_OK);
	if (obj_desc == acpi_gbl_global_lock_mutex) {
		status = acpi_ev_release_global_lock();
	} else {
		acpi_os_release_mutex(obj_desc->mutex.os_mutex);
	}

	obj_desc->mutex.thread_id = 0;
	return_ACPI_STATUS(status);
}

/*******************************************************************************
@@ -253,22 +332,13 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
		return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
	}

	/* Sanity check: we must have a valid thread ID */

	if (!walk_state->thread) {
		ACPI_ERROR((AE_INFO,
			    "Cannot release Mutex [%4.4s], null thread info",
			    acpi_ut_get_node_name(obj_desc->mutex.node)));
		return_ACPI_STATUS(AE_AML_INTERNAL);
	}

	/*
	 * The Mutex is owned, but this thread must be the owner.
	 * Special case for Global Lock, any thread can release
	 */
	if ((obj_desc->mutex.owner_thread->thread_id !=
	     walk_state->thread->thread_id)
	    && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
	    && (obj_desc != acpi_gbl_global_lock_mutex)) {
		ACPI_ERROR((AE_INFO,
			    "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
			    (unsigned long)walk_state->thread->thread_id,
@@ -278,6 +348,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
		return_ACPI_STATUS(AE_AML_NOT_OWNER);
	}

	/* Sanity check: we must have a valid thread ID */

	if (!walk_state->thread) {
		ACPI_ERROR((AE_INFO,
			    "Cannot release Mutex [%4.4s], null thread info",
			    acpi_ut_get_node_name(obj_desc->mutex.node)));
		return_ACPI_STATUS(AE_AML_INTERNAL);
	}

	/*
	 * The sync level of the mutex must be less than or equal to the current
	 * sync level
@@ -289,34 +368,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
		return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
	}

	/* Match multiple Acquires with multiple Releases */

	obj_desc->mutex.acquisition_depth--;
	if (obj_desc->mutex.acquisition_depth != 0) {

		/* Just decrement the depth and return */

		return_ACPI_STATUS(AE_OK);
	}

	/* Unlink the mutex from the owner's list */

	acpi_ex_unlink_mutex(obj_desc);

	/* Release the mutex, special case for Global Lock */
	status = acpi_ex_release_mutex_object(obj_desc);

	if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
		status = acpi_ev_release_global_lock();
	} else {
		acpi_os_release_mutex(obj_desc->mutex.os_mutex);
	}

	/* Update the mutex and restore sync_level */
	/* Restore sync_level */

	obj_desc->mutex.owner_thread = NULL;
	walk_state->thread->current_sync_level =
	    obj_desc->mutex.original_sync_level;

	return_ACPI_STATUS(status);
}

@@ -357,7 +414,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)

		/* Release the mutex, special case for Global Lock */

		if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
		if (obj_desc == acpi_gbl_global_lock_mutex) {

			/* Ignore errors */

@@ -369,6 +426,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
		/* Mark mutex unowned */

		obj_desc->mutex.owner_thread = NULL;
		obj_desc->mutex.thread_id = 0;

		/* Update Thread sync_level (Last mutex is the important one) */

Loading