|
@@ -298,19 +298,13 @@ static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
|
|
|
{
|
|
|
acpi_status status;
|
|
|
|
|
|
- /* Signal threads that are waiting for the lock */
|
|
|
+ /* Signal the thread that is waiting for the lock */
|
|
|
|
|
|
- if (acpi_gbl_global_lock_thread_count) {
|
|
|
+ /* Send a unit to the semaphore */
|
|
|
|
|
|
- /* Send sufficient units to the semaphore */
|
|
|
-
|
|
|
- status =
|
|
|
- acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore,
|
|
|
- acpi_gbl_global_lock_thread_count);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- ACPI_ERROR((AE_INFO,
|
|
|
- "Could not signal Global Lock semaphore"));
|
|
|
- }
|
|
|
+ status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -333,7 +327,8 @@ static u32 acpi_ev_global_lock_handler(void *context)
|
|
|
u8 acquired = FALSE;
|
|
|
|
|
|
/*
|
|
|
- * Attempt to get the lock
|
|
|
+ * Attempt to get the lock.
|
|
|
+ *
|
|
|
* If we don't get it now, it will be marked pending and we will
|
|
|
* take another interrupt when it becomes free.
|
|
|
*/
|
|
@@ -341,6 +336,7 @@ static u32 acpi_ev_global_lock_handler(void *context)
|
|
|
if (acquired) {
|
|
|
|
|
|
/* Got the lock, now wake all threads waiting for it */
|
|
|
+
|
|
|
acpi_gbl_global_lock_acquired = TRUE;
|
|
|
acpi_ev_global_lock_thread(context);
|
|
|
}
|
|
@@ -399,6 +395,16 @@ acpi_status acpi_ev_init_global_lock_handler(void)
|
|
|
*
|
|
|
* DESCRIPTION: Attempt to gain ownership of the Global Lock.
|
|
|
*
|
|
|
+ * MUTEX: Interpreter must be locked
|
|
|
+ *
|
|
|
+ * Note: The original implementation allowed multiple threads to "acquire" the
|
|
|
+ * Global Lock, and the OS would hold the lock until the last thread had
|
|
|
+ * released it. However, this could potentially starve the BIOS out of the
|
|
|
+ * lock, especially in the case where there is a tight handshake between the
|
|
|
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
|
|
|
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
|
|
|
+ * the global lock appear as a standard mutex on the OS side.
|
|
|
+ *
|
|
|
*****************************************************************************/
|
|
|
|
|
|
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
|
|
@@ -408,27 +414,25 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
|
|
|
|
|
|
ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
|
|
|
|
|
|
-#ifndef ACPI_APPLICATION
|
|
|
- /* Make sure that we actually have a global lock */
|
|
|
-
|
|
|
- if (!acpi_gbl_global_lock_present) {
|
|
|
- return_ACPI_STATUS(AE_NO_GLOBAL_LOCK);
|
|
|
+ /*
|
|
|
+ * Only one thread can acquire the GL at a time, the global_lock_mutex
|
|
|
+ * enforces this. This interface releases the interpreter if we must wait.
|
|
|
+ */
|
|
|
+ status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ return_ACPI_STATUS(status);
|
|
|
}
|
|
|
-#endif
|
|
|
-
|
|
|
- /* One more thread wants the global lock */
|
|
|
-
|
|
|
- acpi_gbl_global_lock_thread_count++;
|
|
|
|
|
|
/*
|
|
|
- * If we (OS side vs. BIOS side) have the hardware lock already,
|
|
|
- * we are done
|
|
|
+ * Make sure that a global lock actually exists. If not, just treat
|
|
|
+ * the lock as a standard mutex.
|
|
|
*/
|
|
|
- if (acpi_gbl_global_lock_acquired) {
|
|
|
+ if (!acpi_gbl_global_lock_present) {
|
|
|
+ acpi_gbl_global_lock_acquired = TRUE;
|
|
|
return_ACPI_STATUS(AE_OK);
|
|
|
}
|
|
|
|
|
|
- /* We must acquire the actual hardware lock */
|
|
|
+ /* Attempt to acquire the actual hardware lock */
|
|
|
|
|
|
ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
|
|
|
if (acquired) {
|
|
@@ -436,25 +440,24 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
|
|
|
/* We got the lock */
|
|
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
|
|
- "Acquired the HW Global Lock\n"));
|
|
|
+ "Acquired hardware Global Lock\n"));
|
|
|
|
|
|
acpi_gbl_global_lock_acquired = TRUE;
|
|
|
return_ACPI_STATUS(AE_OK);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Did not get the lock. The pending bit was set above, and we must now
|
|
|
+ * Did not get the lock. The pending bit was set above, and we must now
|
|
|
* wait until we get the global lock released interrupt.
|
|
|
*/
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
|
|
|
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
|
|
|
|
|
|
/*
|
|
|
- * Acquire the global lock semaphore first.
|
|
|
- * Since this wait will block, we must release the interpreter
|
|
|
+ * Wait for handshake with the global lock interrupt handler.
|
|
|
+ * This interface releases the interpreter if we must wait.
|
|
|
*/
|
|
|
- status =
|
|
|
- acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
|
|
|
- timeout);
|
|
|
+ status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
|
|
|
+ ACPI_WAIT_FOREVER);
|
|
|
return_ACPI_STATUS(status);
|
|
|
}
|
|
|
|
|
@@ -477,38 +480,40 @@ acpi_status acpi_ev_release_global_lock(void)
|
|
|
|
|
|
ACPI_FUNCTION_TRACE(ev_release_global_lock);
|
|
|
|
|
|
- if (!acpi_gbl_global_lock_thread_count) {
|
|
|
+ /* Lock must be acquired */
|
|
|
+
|
|
|
+ if (!acpi_gbl_global_lock_acquired) {
|
|
|
ACPI_WARNING((AE_INFO,
|
|
|
- "Cannot release HW Global Lock, it has not been acquired"));
|
|
|
+ "Cannot release the ACPI Global Lock, it has not been acquired"));
|
|
|
return_ACPI_STATUS(AE_NOT_ACQUIRED);
|
|
|
}
|
|
|
|
|
|
- /* One fewer thread has the global lock */
|
|
|
+ if (acpi_gbl_global_lock_present) {
|
|
|
|
|
|
- acpi_gbl_global_lock_thread_count--;
|
|
|
- if (acpi_gbl_global_lock_thread_count) {
|
|
|
+ /* Allow any thread to release the lock */
|
|
|
|
|
|
- /* There are still some threads holding the lock, cannot release */
|
|
|
+ ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock,
|
|
|
+ pending);
|
|
|
|
|
|
- return_ACPI_STATUS(AE_OK);
|
|
|
+ /*
|
|
|
+ * If the pending bit was set, we must write GBL_RLS to the control
|
|
|
+ * register
|
|
|
+ */
|
|
|
+ if (pending) {
|
|
|
+ status =
|
|
|
+ acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
|
|
|
+ 1, ACPI_MTX_LOCK);
|
|
|
+ }
|
|
|
+
|
|
|
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
|
|
+ "Released hardware Global Lock\n"));
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * No more threads holding lock, we can do the actual hardware
|
|
|
- * release
|
|
|
- */
|
|
|
- ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending);
|
|
|
acpi_gbl_global_lock_acquired = FALSE;
|
|
|
|
|
|
- /*
|
|
|
- * If the pending bit was set, we must write GBL_RLS to the control
|
|
|
- * register
|
|
|
- */
|
|
|
- if (pending) {
|
|
|
- status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
|
|
|
- 1, ACPI_MTX_LOCK);
|
|
|
- }
|
|
|
+ /* Release the local GL mutex */
|
|
|
|
|
|
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
|
|
|
return_ACPI_STATUS(status);
|
|
|
}
|
|
|
|