162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: utmutex - local mutex support
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci ******************************************************************************/
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <acpi/acpi.h>
962306a36Sopenharmony_ci#include "accommon.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define _COMPONENT          ACPI_UTILITIES
1262306a36Sopenharmony_ciACPI_MODULE_NAME("utmutex")
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* Local prototypes */
1562306a36Sopenharmony_cistatic acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id);
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*******************************************************************************
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * FUNCTION:    acpi_ut_mutex_initialize
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * PARAMETERS:  None.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * RETURN:      Status
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * DESCRIPTION: Create the system mutex objects. This includes mutexes,
2862306a36Sopenharmony_ci *              spin locks, and reader/writer locks.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci ******************************************************************************/
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciacpi_status acpi_ut_mutex_initialize(void)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	u32 i;
3562306a36Sopenharmony_ci	acpi_status status;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_mutex_initialize);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* Create each of the predefined mutex objects */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
4262306a36Sopenharmony_ci		status = acpi_ut_create_mutex(i);
4362306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
4462306a36Sopenharmony_ci			return_ACPI_STATUS(status);
4562306a36Sopenharmony_ci		}
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/* Create the spinlocks for use at interrupt level or for speed */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
5162306a36Sopenharmony_ci	if (ACPI_FAILURE (status)) {
5262306a36Sopenharmony_ci		return_ACPI_STATUS (status);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	status = acpi_os_create_raw_lock(&acpi_gbl_hardware_lock);
5662306a36Sopenharmony_ci	if (ACPI_FAILURE (status)) {
5762306a36Sopenharmony_ci		return_ACPI_STATUS (status);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	status = acpi_os_create_lock(&acpi_gbl_reference_count_lock);
6162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
6262306a36Sopenharmony_ci		return_ACPI_STATUS(status);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* Mutex for _OSI support */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
6862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
6962306a36Sopenharmony_ci		return_ACPI_STATUS(status);
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Create the reader/writer lock for namespace access */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
7562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
7662306a36Sopenharmony_ci		return_ACPI_STATUS(status);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return_ACPI_STATUS(status);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*******************************************************************************
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * FUNCTION:    acpi_ut_mutex_terminate
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * PARAMETERS:  None.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * RETURN:      None.
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
9162306a36Sopenharmony_ci *              spin locks, and reader/writer locks.
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci ******************************************************************************/
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_civoid acpi_ut_mutex_terminate(void)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	u32 i;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_mutex_terminate);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Delete each predefined mutex object */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
10462306a36Sopenharmony_ci		acpi_ut_delete_mutex(i);
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	acpi_os_delete_mutex(acpi_gbl_osi_mutex);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Delete the spinlocks */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	acpi_os_delete_lock(acpi_gbl_gpe_lock);
11262306a36Sopenharmony_ci	acpi_os_delete_raw_lock(acpi_gbl_hardware_lock);
11362306a36Sopenharmony_ci	acpi_os_delete_lock(acpi_gbl_reference_count_lock);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Delete the reader/writer lock */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock);
11862306a36Sopenharmony_ci	return_VOID;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*******************************************************************************
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * FUNCTION:    acpi_ut_create_mutex
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * PARAMETERS:  mutex_ID        - ID of the mutex to be created
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * RETURN:      Status
12862306a36Sopenharmony_ci *
12962306a36Sopenharmony_ci * DESCRIPTION: Create a mutex object.
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci ******************************************************************************/
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	acpi_status status = AE_OK;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (!acpi_gbl_mutex_info[mutex_id].mutex) {
14062306a36Sopenharmony_ci		status =
14162306a36Sopenharmony_ci		    acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex);
14262306a36Sopenharmony_ci		acpi_gbl_mutex_info[mutex_id].thread_id =
14362306a36Sopenharmony_ci		    ACPI_MUTEX_NOT_ACQUIRED;
14462306a36Sopenharmony_ci		acpi_gbl_mutex_info[mutex_id].use_count = 0;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return_ACPI_STATUS(status);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*******************************************************************************
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * FUNCTION:    acpi_ut_delete_mutex
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * PARAMETERS:  mutex_ID        - ID of the mutex to be deleted
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * RETURN:      Status
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * DESCRIPTION: Delete a mutex object.
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci ******************************************************************************/
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	acpi_gbl_mutex_info[mutex_id].mutex = NULL;
17062306a36Sopenharmony_ci	acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return_VOID;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*******************************************************************************
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * FUNCTION:    acpi_ut_acquire_mutex
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * PARAMETERS:  mutex_ID        - ID of the mutex to be acquired
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * RETURN:      Status
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * DESCRIPTION: Acquire a mutex object.
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci ******************************************************************************/
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciacpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	acpi_status status;
19062306a36Sopenharmony_ci	acpi_thread_id this_thread_id;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ut_acquire_mutex);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (mutex_id > ACPI_MAX_MUTEX) {
19562306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	this_thread_id = acpi_os_get_thread_id();
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#ifdef ACPI_MUTEX_DEBUG
20162306a36Sopenharmony_ci	{
20262306a36Sopenharmony_ci		u32 i;
20362306a36Sopenharmony_ci		/*
20462306a36Sopenharmony_ci		 * Mutex debug code, for internal debugging only.
20562306a36Sopenharmony_ci		 *
20662306a36Sopenharmony_ci		 * Deadlock prevention. Check if this thread owns any mutexes of value
20762306a36Sopenharmony_ci		 * greater than or equal to this one. If so, the thread has violated
20862306a36Sopenharmony_ci		 * the mutex ordering rule. This indicates a coding error somewhere in
20962306a36Sopenharmony_ci		 * the ACPI subsystem code.
21062306a36Sopenharmony_ci		 */
21162306a36Sopenharmony_ci		for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
21262306a36Sopenharmony_ci			if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
21362306a36Sopenharmony_ci				if (i == mutex_id) {
21462306a36Sopenharmony_ci					ACPI_ERROR((AE_INFO,
21562306a36Sopenharmony_ci						    "Mutex [%s] already acquired by this thread [%u]",
21662306a36Sopenharmony_ci						    acpi_ut_get_mutex_name
21762306a36Sopenharmony_ci						    (mutex_id),
21862306a36Sopenharmony_ci						    (u32)this_thread_id));
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci					return (AE_ALREADY_ACQUIRED);
22162306a36Sopenharmony_ci				}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci				ACPI_ERROR((AE_INFO,
22462306a36Sopenharmony_ci					    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
22562306a36Sopenharmony_ci					    (u32)this_thread_id,
22662306a36Sopenharmony_ci					    acpi_ut_get_mutex_name(i),
22762306a36Sopenharmony_ci					    acpi_ut_get_mutex_name(mutex_id)));
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci				return (AE_ACQUIRE_DEADLOCK);
23062306a36Sopenharmony_ci			}
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci#endif
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
23662306a36Sopenharmony_ci			  "Thread %u attempting to acquire Mutex [%s]\n",
23762306a36Sopenharmony_ci			  (u32)this_thread_id,
23862306a36Sopenharmony_ci			  acpi_ut_get_mutex_name(mutex_id)));
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	status =
24162306a36Sopenharmony_ci	    acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
24262306a36Sopenharmony_ci				  ACPI_WAIT_FOREVER);
24362306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
24462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
24562306a36Sopenharmony_ci				  "Thread %u acquired Mutex [%s]\n",
24662306a36Sopenharmony_ci				  (u32)this_thread_id,
24762306a36Sopenharmony_ci				  acpi_ut_get_mutex_name(mutex_id)));
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		acpi_gbl_mutex_info[mutex_id].use_count++;
25062306a36Sopenharmony_ci		acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
25162306a36Sopenharmony_ci	} else {
25262306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
25362306a36Sopenharmony_ci				"Thread %u could not acquire Mutex [%s] (0x%X)",
25462306a36Sopenharmony_ci				(u32)this_thread_id,
25562306a36Sopenharmony_ci				acpi_ut_get_mutex_name(mutex_id), mutex_id));
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return (status);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/*******************************************************************************
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci * FUNCTION:    acpi_ut_release_mutex
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * PARAMETERS:  mutex_ID        - ID of the mutex to be released
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * RETURN:      Status
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci * DESCRIPTION: Release a mutex object.
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci ******************************************************************************/
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ciacpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ut_release_mutex);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
27862306a36Sopenharmony_ci			  (u32)acpi_os_get_thread_id(),
27962306a36Sopenharmony_ci			  acpi_ut_get_mutex_name(mutex_id)));
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (mutex_id > ACPI_MAX_MUTEX) {
28262306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/*
28662306a36Sopenharmony_ci	 * Mutex must be acquired in order to release it!
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci	if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) {
28962306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
29062306a36Sopenharmony_ci			    "Mutex [%s] (0x%X) is not acquired, cannot release",
29162306a36Sopenharmony_ci			    acpi_ut_get_mutex_name(mutex_id), mutex_id));
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		return (AE_NOT_ACQUIRED);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci#ifdef ACPI_MUTEX_DEBUG
29662306a36Sopenharmony_ci	{
29762306a36Sopenharmony_ci		u32 i;
29862306a36Sopenharmony_ci		/*
29962306a36Sopenharmony_ci		 * Mutex debug code, for internal debugging only.
30062306a36Sopenharmony_ci		 *
30162306a36Sopenharmony_ci		 * Deadlock prevention. Check if this thread owns any mutexes of value
30262306a36Sopenharmony_ci		 * greater than this one. If so, the thread has violated the mutex
30362306a36Sopenharmony_ci		 * ordering rule. This indicates a coding error somewhere in
30462306a36Sopenharmony_ci		 * the ACPI subsystem code.
30562306a36Sopenharmony_ci		 */
30662306a36Sopenharmony_ci		for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
30762306a36Sopenharmony_ci			if (acpi_gbl_mutex_info[i].thread_id ==
30862306a36Sopenharmony_ci			    acpi_os_get_thread_id()) {
30962306a36Sopenharmony_ci				if (i == mutex_id) {
31062306a36Sopenharmony_ci					continue;
31162306a36Sopenharmony_ci				}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci				ACPI_ERROR((AE_INFO,
31462306a36Sopenharmony_ci					    "Invalid release order: owns [%s], releasing [%s]",
31562306a36Sopenharmony_ci					    acpi_ut_get_mutex_name(i),
31662306a36Sopenharmony_ci					    acpi_ut_get_mutex_name(mutex_id)));
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci				return (AE_RELEASE_DEADLOCK);
31962306a36Sopenharmony_ci			}
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci#endif
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Mark unlocked FIRST */
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
32962306a36Sopenharmony_ci	return (AE_OK);
33062306a36Sopenharmony_ci}
331