| // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 | |
| /******************************************************************************* | |
| * | |
| * Module Name: utmutex - local mutex support | |
| * | |
| ******************************************************************************/ | |
| #include <acpi/acpi.h> | |
| #include "accommon.h" | |
| #define _COMPONENT ACPI_UTILITIES | |
| ACPI_MODULE_NAME("utmutex") | |
| /* Local prototypes */ | |
| static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id); | |
| static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id); | |
| /******************************************************************************* | |
| * | |
| * FUNCTION: acpi_ut_mutex_initialize | |
| * | |
| * PARAMETERS: None. | |
| * | |
| * RETURN: Status | |
| * | |
| * DESCRIPTION: Create the system mutex objects. This includes mutexes, | |
| * spin locks, and reader/writer locks. | |
| * | |
| ******************************************************************************/ | |
| acpi_status acpi_ut_mutex_initialize(void) | |
| { | |
| u32 i; | |
| acpi_status status; | |
| ACPI_FUNCTION_TRACE(ut_mutex_initialize); | |
| /* Create each of the predefined mutex objects */ | |
| for (i = 0; i < ACPI_NUM_MUTEX; i++) { | |
| status = acpi_ut_create_mutex(i); | |
| if (ACPI_FAILURE(status)) { | |
| return_ACPI_STATUS(status); | |
| } | |
| } | |
| /* Create the spinlocks for use at interrupt level or for speed */ | |
| status = acpi_os_create_lock (&acpi_gbl_gpe_lock); | |
| if (ACPI_FAILURE (status)) { | |
| return_ACPI_STATUS (status); | |
| } | |
| status = acpi_os_create_raw_lock(&acpi_gbl_hardware_lock); | |
| if (ACPI_FAILURE (status)) { | |
| return_ACPI_STATUS (status); | |
| } | |
| status = acpi_os_create_lock(&acpi_gbl_reference_count_lock); | |
| if (ACPI_FAILURE(status)) { | |
| return_ACPI_STATUS(status); | |
| } | |
| /* Mutex for _OSI support */ | |
| status = acpi_os_create_mutex(&acpi_gbl_osi_mutex); | |
| if (ACPI_FAILURE(status)) { | |
| return_ACPI_STATUS(status); | |
| } | |
| /* Create the reader/writer lock for namespace access */ | |
| status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock); | |
| if (ACPI_FAILURE(status)) { | |
| return_ACPI_STATUS(status); | |
| } | |
| return_ACPI_STATUS(status); | |
| } | |
| /******************************************************************************* | |
| * | |
| * FUNCTION: acpi_ut_mutex_terminate | |
| * | |
| * PARAMETERS: None. | |
| * | |
| * RETURN: None. | |
| * | |
| * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes, | |
| * spin locks, and reader/writer locks. | |
| * | |
| ******************************************************************************/ | |
| void acpi_ut_mutex_terminate(void) | |
| { | |
| u32 i; | |
| ACPI_FUNCTION_TRACE(ut_mutex_terminate); | |
| /* Delete each predefined mutex object */ | |
| for (i = 0; i < ACPI_NUM_MUTEX; i++) { | |
| acpi_ut_delete_mutex(i); | |
| } | |
| acpi_os_delete_mutex(acpi_gbl_osi_mutex); | |
| /* Delete the spinlocks */ | |
| acpi_os_delete_lock(acpi_gbl_gpe_lock); | |
| acpi_os_delete_raw_lock(acpi_gbl_hardware_lock); | |
| acpi_os_delete_lock(acpi_gbl_reference_count_lock); | |
| /* Delete the reader/writer lock */ | |
| acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock); | |
| return_VOID; | |
| } | |
| /******************************************************************************* | |
| * | |
| * FUNCTION: acpi_ut_create_mutex | |
| * | |
| * PARAMETERS: mutex_ID - ID of the mutex to be created | |
| * | |
| * RETURN: Status | |
| * | |
| * DESCRIPTION: Create a mutex object. | |
| * | |
| ******************************************************************************/ | |
| static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id) | |
| { | |
| acpi_status status = AE_OK; | |
| ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id); | |
| if (!acpi_gbl_mutex_info[mutex_id].mutex) { | |
| status = | |
| acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex); | |
| acpi_gbl_mutex_info[mutex_id].thread_id = | |
| ACPI_MUTEX_NOT_ACQUIRED; | |
| acpi_gbl_mutex_info[mutex_id].use_count = 0; | |
| } | |
| return_ACPI_STATUS(status); | |
| } | |
| /******************************************************************************* | |
| * | |
| * FUNCTION: acpi_ut_delete_mutex | |
| * | |
| * PARAMETERS: mutex_ID - ID of the mutex to be deleted | |
| * | |
| * RETURN: Status | |
| * | |
| * DESCRIPTION: Delete a mutex object. | |
| * | |
| ******************************************************************************/ | |
| static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) | |
| { | |
| ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id); | |
| acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex); | |
| acpi_gbl_mutex_info[mutex_id].mutex = NULL; | |
| acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; | |
| return_VOID; | |
| } | |
| /******************************************************************************* | |
| * | |
| * FUNCTION: acpi_ut_acquire_mutex | |
| * | |
| * PARAMETERS: mutex_ID - ID of the mutex to be acquired | |
| * | |
| * RETURN: Status | |
| * | |
| * DESCRIPTION: Acquire a mutex object. | |
| * | |
| ******************************************************************************/ | |
| acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) | |
| { | |
| acpi_status status; | |
| acpi_thread_id this_thread_id; | |
| ACPI_FUNCTION_NAME(ut_acquire_mutex); | |
| if (mutex_id > ACPI_MAX_MUTEX) { | |
| return (AE_BAD_PARAMETER); | |
| } | |
| this_thread_id = acpi_os_get_thread_id(); | |
| #ifdef ACPI_MUTEX_DEBUG | |
| { | |
| u32 i; | |
| /* | |
| * Mutex debug code, for internal debugging only. | |
| * | |
| * Deadlock prevention. Check if this thread owns any mutexes of value | |
| * greater than or equal to this one. If so, the thread has violated | |
| * the mutex ordering rule. This indicates a coding error somewhere in | |
| * the ACPI subsystem code. | |
| */ | |
| for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { | |
| if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { | |
| if (i == mutex_id) { | |
| ACPI_ERROR((AE_INFO, | |
| "Mutex [%s] already acquired by this thread [%u]", | |
| acpi_ut_get_mutex_name | |
| (mutex_id), | |
| (u32)this_thread_id)); | |
| return (AE_ALREADY_ACQUIRED); | |
| } | |
| ACPI_ERROR((AE_INFO, | |
| "Invalid acquire order: Thread %u owns [%s], wants [%s]", | |
| (u32)this_thread_id, | |
| acpi_ut_get_mutex_name(i), | |
| acpi_ut_get_mutex_name(mutex_id))); | |
| return (AE_ACQUIRE_DEADLOCK); | |
| } | |
| } | |
| } | |
| #endif | |
| ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | |
| "Thread %u attempting to acquire Mutex [%s]\n", | |
| (u32)this_thread_id, | |
| acpi_ut_get_mutex_name(mutex_id))); | |
| status = | |
| acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, | |
| ACPI_WAIT_FOREVER); | |
| if (ACPI_SUCCESS(status)) { | |
| ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | |
| "Thread %u acquired Mutex [%s]\n", | |
| (u32)this_thread_id, | |
| acpi_ut_get_mutex_name(mutex_id))); | |
| acpi_gbl_mutex_info[mutex_id].use_count++; | |
| acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; | |
| } else { | |
| ACPI_EXCEPTION((AE_INFO, status, | |
| "Thread %u could not acquire Mutex [%s] (0x%X)", | |
| (u32)this_thread_id, | |
| acpi_ut_get_mutex_name(mutex_id), mutex_id)); | |
| } | |
| return (status); | |
| } | |
| /******************************************************************************* | |
| * | |
| * FUNCTION: acpi_ut_release_mutex | |
| * | |
| * PARAMETERS: mutex_ID - ID of the mutex to be released | |
| * | |
| * RETURN: Status | |
| * | |
| * DESCRIPTION: Release a mutex object. | |
| * | |
| ******************************************************************************/ | |
| acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) | |
| { | |
| ACPI_FUNCTION_NAME(ut_release_mutex); | |
| ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n", | |
| (u32)acpi_os_get_thread_id(), | |
| acpi_ut_get_mutex_name(mutex_id))); | |
| if (mutex_id > ACPI_MAX_MUTEX) { | |
| return (AE_BAD_PARAMETER); | |
| } | |
| /* | |
| * Mutex must be acquired in order to release it! | |
| */ | |
| if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) { | |
| ACPI_ERROR((AE_INFO, | |
| "Mutex [%s] (0x%X) is not acquired, cannot release", | |
| acpi_ut_get_mutex_name(mutex_id), mutex_id)); | |
| return (AE_NOT_ACQUIRED); | |
| } | |
| #ifdef ACPI_MUTEX_DEBUG | |
| { | |
| u32 i; | |
| /* | |
| * Mutex debug code, for internal debugging only. | |
| * | |
| * Deadlock prevention. Check if this thread owns any mutexes of value | |
| * greater than this one. If so, the thread has violated the mutex | |
| * ordering rule. This indicates a coding error somewhere in | |
| * the ACPI subsystem code. | |
| */ | |
| for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { | |
| if (acpi_gbl_mutex_info[i].thread_id == | |
| acpi_os_get_thread_id()) { | |
| if (i == mutex_id) { | |
| continue; | |
| } | |
| ACPI_ERROR((AE_INFO, | |
| "Invalid release order: owns [%s], releasing [%s]", | |
| acpi_ut_get_mutex_name(i), | |
| acpi_ut_get_mutex_name(mutex_id))); | |
| return (AE_RELEASE_DEADLOCK); | |
| } | |
| } | |
| } | |
| #endif | |
| /* Mark unlocked FIRST */ | |
| acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; | |
| acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex); | |
| return (AE_OK); | |
| } |