xref: /openbmc/linux/drivers/acpi/acpica/utmutex.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /*******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: utmutex - local mutex support
595b482a8SLen Brown  *
695b482a8SLen Brown  ******************************************************************************/
795b482a8SLen Brown 
895b482a8SLen Brown #include <acpi/acpi.h>
9e2f7a777SLen Brown #include "accommon.h"
1095b482a8SLen Brown 
1195b482a8SLen Brown #define _COMPONENT          ACPI_UTILITIES
1295b482a8SLen Brown ACPI_MODULE_NAME("utmutex")
1395b482a8SLen Brown 
1495b482a8SLen Brown /* Local prototypes */
1595b482a8SLen Brown static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id);
1695b482a8SLen Brown 
172147d3f0SBob Moore static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
1895b482a8SLen Brown 
1995b482a8SLen Brown /*******************************************************************************
2095b482a8SLen Brown  *
2195b482a8SLen Brown  * FUNCTION:    acpi_ut_mutex_initialize
2295b482a8SLen Brown  *
2395b482a8SLen Brown  * PARAMETERS:  None.
2495b482a8SLen Brown  *
2595b482a8SLen Brown  * RETURN:      Status
2695b482a8SLen Brown  *
278a335a23SBob Moore  * DESCRIPTION: Create the system mutex objects. This includes mutexes,
288a335a23SBob Moore  *              spin locks, and reader/writer locks.
2995b482a8SLen Brown  *
3095b482a8SLen Brown  ******************************************************************************/
3195b482a8SLen Brown 
acpi_ut_mutex_initialize(void)3295b482a8SLen Brown acpi_status acpi_ut_mutex_initialize(void)
3395b482a8SLen Brown {
3495b482a8SLen Brown 	u32 i;
3595b482a8SLen Brown 	acpi_status status;
3695b482a8SLen Brown 
3795b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ut_mutex_initialize);
3895b482a8SLen Brown 
398a335a23SBob Moore 	/* Create each of the predefined mutex objects */
408a335a23SBob Moore 
4195b482a8SLen Brown 	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
4295b482a8SLen Brown 		status = acpi_ut_create_mutex(i);
4395b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
4495b482a8SLen Brown 			return_ACPI_STATUS(status);
4595b482a8SLen Brown 		}
4695b482a8SLen Brown 	}
4795b482a8SLen Brown 
4858892c96SBob Moore 	/* Create the spinlocks for use at interrupt level or for speed */
4995b482a8SLen Brown 
503854c8e3SLin Ming 	status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
513854c8e3SLin Ming 	if (ACPI_FAILURE (status)) {
523854c8e3SLin Ming 		return_ACPI_STATUS (status);
533854c8e3SLin Ming 	}
543854c8e3SLin Ming 
55*c57c0ad4SSteven Rostedt 	status = acpi_os_create_raw_lock(&acpi_gbl_hardware_lock);
563854c8e3SLin Ming 	if (ACPI_FAILURE (status)) {
573854c8e3SLin Ming 		return_ACPI_STATUS (status);
583854c8e3SLin Ming 	}
593854c8e3SLin Ming 
6058892c96SBob Moore 	status = acpi_os_create_lock(&acpi_gbl_reference_count_lock);
6158892c96SBob Moore 	if (ACPI_FAILURE(status)) {
6258892c96SBob Moore 		return_ACPI_STATUS(status);
6358892c96SBob Moore 	}
6458892c96SBob Moore 
65b0ed7a91SLin Ming 	/* Mutex for _OSI support */
6658892c96SBob Moore 
67b0ed7a91SLin Ming 	status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
68b0ed7a91SLin Ming 	if (ACPI_FAILURE(status)) {
69b0ed7a91SLin Ming 		return_ACPI_STATUS(status);
70b0ed7a91SLin Ming 	}
71b0ed7a91SLin Ming 
728a335a23SBob Moore 	/* Create the reader/writer lock for namespace access */
738a335a23SBob Moore 
748a335a23SBob Moore 	status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
75cd64bbf8SBob Moore 	if (ACPI_FAILURE(status)) {
76cd64bbf8SBob Moore 		return_ACPI_STATUS(status);
77cd64bbf8SBob Moore 	}
78cd64bbf8SBob Moore 
7995b482a8SLen Brown 	return_ACPI_STATUS(status);
8095b482a8SLen Brown }
8195b482a8SLen Brown 
8295b482a8SLen Brown /*******************************************************************************
8395b482a8SLen Brown  *
8495b482a8SLen Brown  * FUNCTION:    acpi_ut_mutex_terminate
8595b482a8SLen Brown  *
8695b482a8SLen Brown  * PARAMETERS:  None.
8795b482a8SLen Brown  *
8895b482a8SLen Brown  * RETURN:      None.
8995b482a8SLen Brown  *
908a335a23SBob Moore  * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
918a335a23SBob Moore  *              spin locks, and reader/writer locks.
9295b482a8SLen Brown  *
9395b482a8SLen Brown  ******************************************************************************/
9495b482a8SLen Brown 
acpi_ut_mutex_terminate(void)9595b482a8SLen Brown void acpi_ut_mutex_terminate(void)
9695b482a8SLen Brown {
9795b482a8SLen Brown 	u32 i;
9895b482a8SLen Brown 
9995b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ut_mutex_terminate);
10095b482a8SLen Brown 
1018a335a23SBob Moore 	/* Delete each predefined mutex object */
1028a335a23SBob Moore 
10395b482a8SLen Brown 	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
1042147d3f0SBob Moore 		acpi_ut_delete_mutex(i);
10595b482a8SLen Brown 	}
10695b482a8SLen Brown 
107b0ed7a91SLin Ming 	acpi_os_delete_mutex(acpi_gbl_osi_mutex);
108b0ed7a91SLin Ming 
10995b482a8SLen Brown 	/* Delete the spinlocks */
11095b482a8SLen Brown 
11195b482a8SLen Brown 	acpi_os_delete_lock(acpi_gbl_gpe_lock);
112*c57c0ad4SSteven Rostedt 	acpi_os_delete_raw_lock(acpi_gbl_hardware_lock);
11358892c96SBob Moore 	acpi_os_delete_lock(acpi_gbl_reference_count_lock);
1148a335a23SBob Moore 
1158a335a23SBob Moore 	/* Delete the reader/writer lock */
1168a335a23SBob Moore 
1178a335a23SBob Moore 	acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock);
11895b482a8SLen Brown 	return_VOID;
11995b482a8SLen Brown }
12095b482a8SLen Brown 
12195b482a8SLen Brown /*******************************************************************************
12295b482a8SLen Brown  *
12395b482a8SLen Brown  * FUNCTION:    acpi_ut_create_mutex
12495b482a8SLen Brown  *
125ba494beeSBob Moore  * PARAMETERS:  mutex_ID        - ID of the mutex to be created
12695b482a8SLen Brown  *
12795b482a8SLen Brown  * RETURN:      Status
12895b482a8SLen Brown  *
12995b482a8SLen Brown  * DESCRIPTION: Create a mutex object.
13095b482a8SLen Brown  *
13195b482a8SLen Brown  ******************************************************************************/
13295b482a8SLen Brown 
acpi_ut_create_mutex(acpi_mutex_handle mutex_id)13395b482a8SLen Brown static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
13495b482a8SLen Brown {
13595b482a8SLen Brown 	acpi_status status = AE_OK;
13695b482a8SLen Brown 
13795b482a8SLen Brown 	ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id);
13895b482a8SLen Brown 
13995b482a8SLen Brown 	if (!acpi_gbl_mutex_info[mutex_id].mutex) {
14095b482a8SLen Brown 		status =
14195b482a8SLen Brown 		    acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex);
14295b482a8SLen Brown 		acpi_gbl_mutex_info[mutex_id].thread_id =
14395b482a8SLen Brown 		    ACPI_MUTEX_NOT_ACQUIRED;
14495b482a8SLen Brown 		acpi_gbl_mutex_info[mutex_id].use_count = 0;
14595b482a8SLen Brown 	}
14695b482a8SLen Brown 
14795b482a8SLen Brown 	return_ACPI_STATUS(status);
14895b482a8SLen Brown }
14995b482a8SLen Brown 
15095b482a8SLen Brown /*******************************************************************************
15195b482a8SLen Brown  *
15295b482a8SLen Brown  * FUNCTION:    acpi_ut_delete_mutex
15395b482a8SLen Brown  *
154ba494beeSBob Moore  * PARAMETERS:  mutex_ID        - ID of the mutex to be deleted
15595b482a8SLen Brown  *
15695b482a8SLen Brown  * RETURN:      Status
15795b482a8SLen Brown  *
15895b482a8SLen Brown  * DESCRIPTION: Delete a mutex object.
15995b482a8SLen Brown  *
16095b482a8SLen Brown  ******************************************************************************/
16195b482a8SLen Brown 
acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)1622147d3f0SBob Moore static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
16395b482a8SLen Brown {
16495b482a8SLen Brown 
16595b482a8SLen Brown 	ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
16695b482a8SLen Brown 
16795b482a8SLen Brown 	acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
16895b482a8SLen Brown 
16995b482a8SLen Brown 	acpi_gbl_mutex_info[mutex_id].mutex = NULL;
17095b482a8SLen Brown 	acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
17168aafc35SBob Moore 
17268aafc35SBob Moore 	return_VOID;
17395b482a8SLen Brown }
17495b482a8SLen Brown 
17595b482a8SLen Brown /*******************************************************************************
17695b482a8SLen Brown  *
17795b482a8SLen Brown  * FUNCTION:    acpi_ut_acquire_mutex
17895b482a8SLen Brown  *
179ba494beeSBob Moore  * PARAMETERS:  mutex_ID        - ID of the mutex to be acquired
18095b482a8SLen Brown  *
18195b482a8SLen Brown  * RETURN:      Status
18295b482a8SLen Brown  *
18395b482a8SLen Brown  * DESCRIPTION: Acquire a mutex object.
18495b482a8SLen Brown  *
18595b482a8SLen Brown  ******************************************************************************/
18695b482a8SLen Brown 
acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)18795b482a8SLen Brown acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
18895b482a8SLen Brown {
18995b482a8SLen Brown 	acpi_status status;
19095b482a8SLen Brown 	acpi_thread_id this_thread_id;
19195b482a8SLen Brown 
19295b482a8SLen Brown 	ACPI_FUNCTION_NAME(ut_acquire_mutex);
19395b482a8SLen Brown 
19495b482a8SLen Brown 	if (mutex_id > ACPI_MAX_MUTEX) {
19595b482a8SLen Brown 		return (AE_BAD_PARAMETER);
19695b482a8SLen Brown 	}
19795b482a8SLen Brown 
19895b482a8SLen Brown 	this_thread_id = acpi_os_get_thread_id();
19995b482a8SLen Brown 
20095b482a8SLen Brown #ifdef ACPI_MUTEX_DEBUG
20195b482a8SLen Brown 	{
20295b482a8SLen Brown 		u32 i;
20395b482a8SLen Brown 		/*
20495b482a8SLen Brown 		 * Mutex debug code, for internal debugging only.
20595b482a8SLen Brown 		 *
20695b482a8SLen Brown 		 * Deadlock prevention. Check if this thread owns any mutexes of value
20795b482a8SLen Brown 		 * greater than or equal to this one. If so, the thread has violated
20895b482a8SLen Brown 		 * the mutex ordering rule. This indicates a coding error somewhere in
20995b482a8SLen Brown 		 * the ACPI subsystem code.
21095b482a8SLen Brown 		 */
21195b482a8SLen Brown 		for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
21295b482a8SLen Brown 			if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
21395b482a8SLen Brown 				if (i == mutex_id) {
21495b482a8SLen Brown 					ACPI_ERROR((AE_INFO,
21528eb3fcfSLin Ming 						    "Mutex [%s] already acquired by this thread [%u]",
21695b482a8SLen Brown 						    acpi_ut_get_mutex_name
21795b482a8SLen Brown 						    (mutex_id),
21828eb3fcfSLin Ming 						    (u32)this_thread_id));
21995b482a8SLen Brown 
22095b482a8SLen Brown 					return (AE_ALREADY_ACQUIRED);
22195b482a8SLen Brown 				}
22295b482a8SLen Brown 
22395b482a8SLen Brown 				ACPI_ERROR((AE_INFO,
22428eb3fcfSLin Ming 					    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
22528eb3fcfSLin Ming 					    (u32)this_thread_id,
22695b482a8SLen Brown 					    acpi_ut_get_mutex_name(i),
22795b482a8SLen Brown 					    acpi_ut_get_mutex_name(mutex_id)));
22895b482a8SLen Brown 
22995b482a8SLen Brown 				return (AE_ACQUIRE_DEADLOCK);
23095b482a8SLen Brown 			}
23195b482a8SLen Brown 		}
23295b482a8SLen Brown 	}
23395b482a8SLen Brown #endif
23495b482a8SLen Brown 
23595b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
23628eb3fcfSLin Ming 			  "Thread %u attempting to acquire Mutex [%s]\n",
23728eb3fcfSLin Ming 			  (u32)this_thread_id,
23895b482a8SLen Brown 			  acpi_ut_get_mutex_name(mutex_id)));
23995b482a8SLen Brown 
2401fad8738SBob Moore 	status =
2411fad8738SBob Moore 	    acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
24295b482a8SLen Brown 				  ACPI_WAIT_FOREVER);
24395b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
24495b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
24528eb3fcfSLin Ming 				  "Thread %u acquired Mutex [%s]\n",
24628eb3fcfSLin Ming 				  (u32)this_thread_id,
24795b482a8SLen Brown 				  acpi_ut_get_mutex_name(mutex_id)));
24895b482a8SLen Brown 
24995b482a8SLen Brown 		acpi_gbl_mutex_info[mutex_id].use_count++;
25095b482a8SLen Brown 		acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
25195b482a8SLen Brown 	} else {
25295b482a8SLen Brown 		ACPI_EXCEPTION((AE_INFO, status,
253692aa0cfSBob Moore 				"Thread %u could not acquire Mutex [%s] (0x%X)",
254692aa0cfSBob Moore 				(u32)this_thread_id,
255692aa0cfSBob Moore 				acpi_ut_get_mutex_name(mutex_id), mutex_id));
25695b482a8SLen Brown 	}
25795b482a8SLen Brown 
25895b482a8SLen Brown 	return (status);
25995b482a8SLen Brown }
26095b482a8SLen Brown 
26195b482a8SLen Brown /*******************************************************************************
26295b482a8SLen Brown  *
26395b482a8SLen Brown  * FUNCTION:    acpi_ut_release_mutex
26495b482a8SLen Brown  *
265ba494beeSBob Moore  * PARAMETERS:  mutex_ID        - ID of the mutex to be released
26695b482a8SLen Brown  *
26795b482a8SLen Brown  * RETURN:      Status
26895b482a8SLen Brown  *
26995b482a8SLen Brown  * DESCRIPTION: Release a mutex object.
27095b482a8SLen Brown  *
27195b482a8SLen Brown  ******************************************************************************/
27295b482a8SLen Brown 
acpi_ut_release_mutex(acpi_mutex_handle mutex_id)27395b482a8SLen Brown acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
27495b482a8SLen Brown {
27595b482a8SLen Brown 	ACPI_FUNCTION_NAME(ut_release_mutex);
27695b482a8SLen Brown 
27728eb3fcfSLin Ming 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
27842f52843SBob Moore 			  (u32)acpi_os_get_thread_id(),
27995b482a8SLen Brown 			  acpi_ut_get_mutex_name(mutex_id)));
28095b482a8SLen Brown 
28195b482a8SLen Brown 	if (mutex_id > ACPI_MAX_MUTEX) {
28295b482a8SLen Brown 		return (AE_BAD_PARAMETER);
28395b482a8SLen Brown 	}
28495b482a8SLen Brown 
28595b482a8SLen Brown 	/*
28695b482a8SLen Brown 	 * Mutex must be acquired in order to release it!
28795b482a8SLen Brown 	 */
28895b482a8SLen Brown 	if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) {
28995b482a8SLen Brown 		ACPI_ERROR((AE_INFO,
290692aa0cfSBob Moore 			    "Mutex [%s] (0x%X) is not acquired, cannot release",
291692aa0cfSBob Moore 			    acpi_ut_get_mutex_name(mutex_id), mutex_id));
29295b482a8SLen Brown 
29395b482a8SLen Brown 		return (AE_NOT_ACQUIRED);
29495b482a8SLen Brown 	}
29595b482a8SLen Brown #ifdef ACPI_MUTEX_DEBUG
29695b482a8SLen Brown 	{
29795b482a8SLen Brown 		u32 i;
29895b482a8SLen Brown 		/*
29995b482a8SLen Brown 		 * Mutex debug code, for internal debugging only.
30095b482a8SLen Brown 		 *
30195b482a8SLen Brown 		 * Deadlock prevention. Check if this thread owns any mutexes of value
30295b482a8SLen Brown 		 * greater than this one. If so, the thread has violated the mutex
30395b482a8SLen Brown 		 * ordering rule. This indicates a coding error somewhere in
30495b482a8SLen Brown 		 * the ACPI subsystem code.
30595b482a8SLen Brown 		 */
30695b482a8SLen Brown 		for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
30742f52843SBob Moore 			if (acpi_gbl_mutex_info[i].thread_id ==
30842f52843SBob Moore 			    acpi_os_get_thread_id()) {
30995b482a8SLen Brown 				if (i == mutex_id) {
31095b482a8SLen Brown 					continue;
31195b482a8SLen Brown 				}
31295b482a8SLen Brown 
31395b482a8SLen Brown 				ACPI_ERROR((AE_INFO,
31495b482a8SLen Brown 					    "Invalid release order: owns [%s], releasing [%s]",
31595b482a8SLen Brown 					    acpi_ut_get_mutex_name(i),
31695b482a8SLen Brown 					    acpi_ut_get_mutex_name(mutex_id)));
31795b482a8SLen Brown 
31895b482a8SLen Brown 				return (AE_RELEASE_DEADLOCK);
31995b482a8SLen Brown 			}
32095b482a8SLen Brown 		}
32195b482a8SLen Brown 	}
32295b482a8SLen Brown #endif
32395b482a8SLen Brown 
32495b482a8SLen Brown 	/* Mark unlocked FIRST */
32595b482a8SLen Brown 
32695b482a8SLen Brown 	acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
32795b482a8SLen Brown 
32895b482a8SLen Brown 	acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
32995b482a8SLen Brown 	return (AE_OK);
33095b482a8SLen Brown }
331