mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
8.4 KiB
330 lines
8.4 KiB
// 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); |
|
}
|
|
|