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: Bob Moore <robert.moore@intel.com>
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 2d88a3d..e66b367 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -71,7 +71,6 @@
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 @@
/* 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 @@
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 @@
/* 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);
/* 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 @@
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 @@
/* 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_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 @@
/* 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);
/* 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 */
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 6748e3e..0bebe75 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -126,6 +126,66 @@
/*******************************************************************************
*
+ * 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
*
* PARAMETERS: time_desc - Timeout integer
@@ -161,7 +221,7 @@
}
/*
- * 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 @@
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;
+
+ /* 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);
+}
+
+/*******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ex_release_mutex_object);
+
+ /* 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);
+ }
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);
- }
+
+ /* Unlink the mutex from the owner's list */
+
+ acpi_ex_unlink_mutex(obj_desc);
+ obj_desc->mutex.owner_thread = NULL;
}
- /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+ /* Release the mutex, special case for Global Lock */
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- status =
- acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
} else {
- status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
- (u16) time_desc->integer.
- value);
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
}
- if (ACPI_FAILURE(status)) {
-
- /* Includes failure from a timeout on time_desc */
-
- return_ACPI_STATUS(status);
- }
-
- /* Have the mutex: update mutex and walk info and save the sync_level */
-
- 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;
-
- walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
-
- /* 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(AE_OK);
+ obj_desc->mutex.thread_id = 0;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -253,22 +332,13 @@
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 @@
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 @@
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Match multiple Acquires with multiple Releases */
+ status = acpi_ex_release_mutex_object(obj_desc);
- obj_desc->mutex.acquisition_depth--;
- if (obj_desc->mutex.acquisition_depth != 0) {
+ /* Restore sync_level */
- /* 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 */
-
- 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 */
-
- 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 @@
/* 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 @@
/* 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) */
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 6b0aecc..c0837af 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -240,72 +240,66 @@
* PARAMETERS: field_flags - Flags with Lock rule:
* always_lock or never_lock
*
- * RETURN: TRUE/FALSE indicating whether the lock was actually acquired
+ * RETURN: None
*
- * DESCRIPTION: Obtain the global lock and keep track of this fact via two
- * methods. A global variable keeps the state of the lock, and
- * the state is returned to the caller.
+ * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
+ * flags specifiy that it is to be obtained before field access.
*
******************************************************************************/
-u8 acpi_ex_acquire_global_lock(u32 field_flags)
+void acpi_ex_acquire_global_lock(u32 field_flags)
{
- u8 locked = FALSE;
acpi_status status;
ACPI_FUNCTION_TRACE(ex_acquire_global_lock);
- /* Only attempt lock if the always_lock bit is set */
+ /* Only use the lock if the always_lock bit is set */
- if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
-
- /* We should attempt to get the lock, wait forever */
-
- status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
- if (ACPI_SUCCESS(status)) {
- locked = TRUE;
- } else {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire Global Lock"));
- }
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
}
- return_UINT8(locked);
+ /* Attempt to get the global lock, wait forever */
+
+ status = acpi_ex_acquire_mutex_object(ACPI_WAIT_FOREVER,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not acquire Global Lock"));
+ }
+
+ return_VOID;
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_release_global_lock
*
- * PARAMETERS: locked_by_me - Return value from corresponding call to
- * acquire_global_lock.
+ * PARAMETERS: None
*
* RETURN: None
*
- * DESCRIPTION: Release the global lock if it is locked.
+ * DESCRIPTION: Release the ACPI hardware Global Lock
*
******************************************************************************/
-void acpi_ex_release_global_lock(u8 locked_by_me)
+void acpi_ex_release_global_lock(void)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ex_release_global_lock);
- /* Only attempt unlock if the caller locked it */
+ /* Release the global lock */
- if (locked_by_me) {
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
+ if (ACPI_FAILURE(status)) {
- /* OK, now release the lock */
+ /* Report the error, but there isn't much else we can do */
- status = acpi_ev_release_global_lock();
- if (ACPI_FAILURE(status)) {
-
- /* Report the error, but there isn't much else we can do */
-
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not release ACPI Global Lock"));
- }
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not release Global Lock"));
}
return_VOID;