195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
20f6896f1SBob Moore /******************************************************************************
30f6896f1SBob Moore *
40f6896f1SBob Moore * Module Name: evglock - Global Lock support
50f6896f1SBob Moore *
6*612c2932SBob Moore * Copyright (C) 2000 - 2023, Intel Corp.
70f6896f1SBob Moore *
895857638SErik Schmauss *****************************************************************************/
90f6896f1SBob Moore
100f6896f1SBob Moore #include <acpi/acpi.h>
110f6896f1SBob Moore #include "accommon.h"
120f6896f1SBob Moore #include "acevents.h"
130f6896f1SBob Moore #include "acinterp.h"
140f6896f1SBob Moore
150f6896f1SBob Moore #define _COMPONENT ACPI_EVENTS
160f6896f1SBob Moore ACPI_MODULE_NAME("evglock")
1733620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
180f6896f1SBob Moore /* Local prototypes */
190f6896f1SBob Moore static u32 acpi_ev_global_lock_handler(void *context);
200f6896f1SBob Moore
210f6896f1SBob Moore /*******************************************************************************
220f6896f1SBob Moore *
230f6896f1SBob Moore * FUNCTION: acpi_ev_init_global_lock_handler
240f6896f1SBob Moore *
250f6896f1SBob Moore * PARAMETERS: None
260f6896f1SBob Moore *
270f6896f1SBob Moore * RETURN: Status
280f6896f1SBob Moore *
290f6896f1SBob Moore * DESCRIPTION: Install a handler for the global lock release event
300f6896f1SBob Moore *
310f6896f1SBob Moore ******************************************************************************/
320f6896f1SBob Moore
acpi_ev_init_global_lock_handler(void)330f6896f1SBob Moore acpi_status acpi_ev_init_global_lock_handler(void)
340f6896f1SBob Moore {
350f6896f1SBob Moore acpi_status status;
360f6896f1SBob Moore
370f6896f1SBob Moore ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
380f6896f1SBob Moore
3922e5b40aSBob Moore /* If Hardware Reduced flag is set, there is no global lock */
4022e5b40aSBob Moore
4122e5b40aSBob Moore if (acpi_gbl_reduced_hardware) {
4222e5b40aSBob Moore return_ACPI_STATUS(AE_OK);
4322e5b40aSBob Moore }
4422e5b40aSBob Moore
450f6896f1SBob Moore /* Attempt installation of the global lock handler */
460f6896f1SBob Moore
470f6896f1SBob Moore status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
480f6896f1SBob Moore acpi_ev_global_lock_handler,
490f6896f1SBob Moore NULL);
500f6896f1SBob Moore
510f6896f1SBob Moore /*
520f6896f1SBob Moore * If the global lock does not exist on this platform, the attempt to
530f6896f1SBob Moore * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
540f6896f1SBob Moore * Map to AE_OK, but mark global lock as not present. Any attempt to
550f6896f1SBob Moore * actually use the global lock will be flagged with an error.
560f6896f1SBob Moore */
570f6896f1SBob Moore acpi_gbl_global_lock_present = FALSE;
580f6896f1SBob Moore if (status == AE_NO_HARDWARE_RESPONSE) {
590f6896f1SBob Moore ACPI_ERROR((AE_INFO,
600f6896f1SBob Moore "No response from Global Lock hardware, disabling lock"));
610f6896f1SBob Moore
620f6896f1SBob Moore return_ACPI_STATUS(AE_OK);
630f6896f1SBob Moore }
640f6896f1SBob Moore
650f6896f1SBob Moore status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock);
660f6896f1SBob Moore if (ACPI_FAILURE(status)) {
670f6896f1SBob Moore return_ACPI_STATUS(status);
680f6896f1SBob Moore }
690f6896f1SBob Moore
700f6896f1SBob Moore acpi_gbl_global_lock_pending = FALSE;
710f6896f1SBob Moore acpi_gbl_global_lock_present = TRUE;
720f6896f1SBob Moore return_ACPI_STATUS(status);
730f6896f1SBob Moore }
740f6896f1SBob Moore
750f6896f1SBob Moore /*******************************************************************************
760f6896f1SBob Moore *
770f6896f1SBob Moore * FUNCTION: acpi_ev_remove_global_lock_handler
780f6896f1SBob Moore *
790f6896f1SBob Moore * PARAMETERS: None
800f6896f1SBob Moore *
810f6896f1SBob Moore * RETURN: Status
820f6896f1SBob Moore *
830f6896f1SBob Moore * DESCRIPTION: Remove the handler for the Global Lock
840f6896f1SBob Moore *
850f6896f1SBob Moore ******************************************************************************/
860f6896f1SBob Moore
acpi_ev_remove_global_lock_handler(void)870f6896f1SBob Moore acpi_status acpi_ev_remove_global_lock_handler(void)
880f6896f1SBob Moore {
890f6896f1SBob Moore acpi_status status;
900f6896f1SBob Moore
910f6896f1SBob Moore ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
920f6896f1SBob Moore
930f6896f1SBob Moore acpi_gbl_global_lock_present = FALSE;
940f6896f1SBob Moore status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
950f6896f1SBob Moore acpi_ev_global_lock_handler);
960f6896f1SBob Moore
979dae7bb0STomasz Nowicki acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);
980f6896f1SBob Moore return_ACPI_STATUS(status);
990f6896f1SBob Moore }
1000f6896f1SBob Moore
1010f6896f1SBob Moore /*******************************************************************************
1020f6896f1SBob Moore *
1030f6896f1SBob Moore * FUNCTION: acpi_ev_global_lock_handler
1040f6896f1SBob Moore *
105ba494beeSBob Moore * PARAMETERS: context - From thread interface, not used
1060f6896f1SBob Moore *
1070f6896f1SBob Moore * RETURN: ACPI_INTERRUPT_HANDLED
1080f6896f1SBob Moore *
1090f6896f1SBob Moore * DESCRIPTION: Invoked directly from the SCI handler when a global lock
1100f6896f1SBob Moore * release interrupt occurs. If there is actually a pending
1110f6896f1SBob Moore * request for the lock, signal the waiting thread.
1120f6896f1SBob Moore *
1130f6896f1SBob Moore ******************************************************************************/
1140f6896f1SBob Moore
acpi_ev_global_lock_handler(void * context)1150f6896f1SBob Moore static u32 acpi_ev_global_lock_handler(void *context)
1160f6896f1SBob Moore {
1170f6896f1SBob Moore acpi_status status;
1180f6896f1SBob Moore acpi_cpu_flags flags;
1190f6896f1SBob Moore
1200f6896f1SBob Moore flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
1210f6896f1SBob Moore
1220f6896f1SBob Moore /*
1230f6896f1SBob Moore * If a request for the global lock is not actually pending,
1240f6896f1SBob Moore * we are done. This handles "spurious" global lock interrupts
1250f6896f1SBob Moore * which are possible (and have been seen) with bad BIOSs.
1260f6896f1SBob Moore */
1270f6896f1SBob Moore if (!acpi_gbl_global_lock_pending) {
1280f6896f1SBob Moore goto cleanup_and_exit;
1290f6896f1SBob Moore }
1300f6896f1SBob Moore
1310f6896f1SBob Moore /*
1320f6896f1SBob Moore * Send a unit to the global lock semaphore. The actual acquisition
1330f6896f1SBob Moore * of the global lock will be performed by the waiting thread.
1340f6896f1SBob Moore */
1350f6896f1SBob Moore status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
1360f6896f1SBob Moore if (ACPI_FAILURE(status)) {
1370f6896f1SBob Moore ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
1380f6896f1SBob Moore }
1390f6896f1SBob Moore
1400f6896f1SBob Moore acpi_gbl_global_lock_pending = FALSE;
1410f6896f1SBob Moore
1420f6896f1SBob Moore cleanup_and_exit:
1430f6896f1SBob Moore
1440f6896f1SBob Moore acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
1450f6896f1SBob Moore return (ACPI_INTERRUPT_HANDLED);
1460f6896f1SBob Moore }
1470f6896f1SBob Moore
1480f6896f1SBob Moore /******************************************************************************
1490f6896f1SBob Moore *
1500f6896f1SBob Moore * FUNCTION: acpi_ev_acquire_global_lock
1510f6896f1SBob Moore *
152ba494beeSBob Moore * PARAMETERS: timeout - Max time to wait for the lock, in millisec.
1530f6896f1SBob Moore *
1540f6896f1SBob Moore * RETURN: Status
1550f6896f1SBob Moore *
1560f6896f1SBob Moore * DESCRIPTION: Attempt to gain ownership of the Global Lock.
1570f6896f1SBob Moore *
1580f6896f1SBob Moore * MUTEX: Interpreter must be locked
1590f6896f1SBob Moore *
1600f6896f1SBob Moore * Note: The original implementation allowed multiple threads to "acquire" the
1610f6896f1SBob Moore * Global Lock, and the OS would hold the lock until the last thread had
1620f6896f1SBob Moore * released it. However, this could potentially starve the BIOS out of the
1630f6896f1SBob Moore * lock, especially in the case where there is a tight handshake between the
1640f6896f1SBob Moore * Embedded Controller driver and the BIOS. Therefore, this implementation
1650f6896f1SBob Moore * allows only one thread to acquire the HW Global Lock at a time, and makes
1660f6896f1SBob Moore * the global lock appear as a standard mutex on the OS side.
1670f6896f1SBob Moore *
1680f6896f1SBob Moore *****************************************************************************/
1690f6896f1SBob Moore
acpi_ev_acquire_global_lock(u16 timeout)1700f6896f1SBob Moore acpi_status acpi_ev_acquire_global_lock(u16 timeout)
1710f6896f1SBob Moore {
1720f6896f1SBob Moore acpi_cpu_flags flags;
1730f6896f1SBob Moore acpi_status status;
1740f6896f1SBob Moore u8 acquired = FALSE;
1750f6896f1SBob Moore
1760f6896f1SBob Moore ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
1770f6896f1SBob Moore
1780f6896f1SBob Moore /*
1790f6896f1SBob Moore * Only one thread can acquire the GL at a time, the global_lock_mutex
1800f6896f1SBob Moore * enforces this. This interface releases the interpreter if we must wait.
1810f6896f1SBob Moore */
1820f6896f1SBob Moore status =
1830f6896f1SBob Moore acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex.
1840f6896f1SBob Moore os_mutex, timeout);
1850f6896f1SBob Moore if (ACPI_FAILURE(status)) {
1860f6896f1SBob Moore return_ACPI_STATUS(status);
1870f6896f1SBob Moore }
1880f6896f1SBob Moore
1890f6896f1SBob Moore /*
1900f6896f1SBob Moore * Update the global lock handle and check for wraparound. The handle is
1910f6896f1SBob Moore * only used for the external global lock interfaces, but it is updated
1920f6896f1SBob Moore * here to properly handle the case where a single thread may acquire the
1930f6896f1SBob Moore * lock via both the AML and the acpi_acquire_global_lock interfaces. The
1940f6896f1SBob Moore * handle is therefore updated on the first acquire from a given thread
1950f6896f1SBob Moore * regardless of where the acquisition request originated.
1960f6896f1SBob Moore */
1970f6896f1SBob Moore acpi_gbl_global_lock_handle++;
1980f6896f1SBob Moore if (acpi_gbl_global_lock_handle == 0) {
1990f6896f1SBob Moore acpi_gbl_global_lock_handle = 1;
2000f6896f1SBob Moore }
2010f6896f1SBob Moore
2020f6896f1SBob Moore /*
2030f6896f1SBob Moore * Make sure that a global lock actually exists. If not, just
2040f6896f1SBob Moore * treat the lock as a standard mutex.
2050f6896f1SBob Moore */
2060f6896f1SBob Moore if (!acpi_gbl_global_lock_present) {
2070f6896f1SBob Moore acpi_gbl_global_lock_acquired = TRUE;
2080f6896f1SBob Moore return_ACPI_STATUS(AE_OK);
2090f6896f1SBob Moore }
2100f6896f1SBob Moore
2110f6896f1SBob Moore flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
2120f6896f1SBob Moore
2130f6896f1SBob Moore do {
2140f6896f1SBob Moore
2150f6896f1SBob Moore /* Attempt to acquire the actual hardware lock */
2160f6896f1SBob Moore
2170f6896f1SBob Moore ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
2180f6896f1SBob Moore if (acquired) {
2190f6896f1SBob Moore acpi_gbl_global_lock_acquired = TRUE;
2200f6896f1SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
2210f6896f1SBob Moore "Acquired hardware Global Lock\n"));
2220f6896f1SBob Moore break;
2230f6896f1SBob Moore }
2240f6896f1SBob Moore
2250f6896f1SBob Moore /*
2260f6896f1SBob Moore * Did not get the lock. The pending bit was set above, and
2270f6896f1SBob Moore * we must now wait until we receive the global lock
2280f6896f1SBob Moore * released interrupt.
2290f6896f1SBob Moore */
2300f6896f1SBob Moore acpi_gbl_global_lock_pending = TRUE;
2310f6896f1SBob Moore acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
2320f6896f1SBob Moore
2330f6896f1SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
2340f6896f1SBob Moore "Waiting for hardware Global Lock\n"));
2350f6896f1SBob Moore
2360f6896f1SBob Moore /*
2370f6896f1SBob Moore * Wait for handshake with the global lock interrupt handler.
2380f6896f1SBob Moore * This interface releases the interpreter if we must wait.
2390f6896f1SBob Moore */
2400f6896f1SBob Moore status =
2410f6896f1SBob Moore acpi_ex_system_wait_semaphore
2420f6896f1SBob Moore (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER);
2430f6896f1SBob Moore
2440f6896f1SBob Moore flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
2450f6896f1SBob Moore
2460f6896f1SBob Moore } while (ACPI_SUCCESS(status));
2470f6896f1SBob Moore
2480f6896f1SBob Moore acpi_gbl_global_lock_pending = FALSE;
2490f6896f1SBob Moore acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
2500f6896f1SBob Moore
2510f6896f1SBob Moore return_ACPI_STATUS(status);
2520f6896f1SBob Moore }
2530f6896f1SBob Moore
2540f6896f1SBob Moore /*******************************************************************************
2550f6896f1SBob Moore *
2560f6896f1SBob Moore * FUNCTION: acpi_ev_release_global_lock
2570f6896f1SBob Moore *
2580f6896f1SBob Moore * PARAMETERS: None
2590f6896f1SBob Moore *
2600f6896f1SBob Moore * RETURN: Status
2610f6896f1SBob Moore *
2620f6896f1SBob Moore * DESCRIPTION: Releases ownership of the Global Lock.
2630f6896f1SBob Moore *
2640f6896f1SBob Moore ******************************************************************************/
2650f6896f1SBob Moore
acpi_ev_release_global_lock(void)2660f6896f1SBob Moore acpi_status acpi_ev_release_global_lock(void)
2670f6896f1SBob Moore {
2680f6896f1SBob Moore u8 pending = FALSE;
2690f6896f1SBob Moore acpi_status status = AE_OK;
2700f6896f1SBob Moore
2710f6896f1SBob Moore ACPI_FUNCTION_TRACE(ev_release_global_lock);
2720f6896f1SBob Moore
2730f6896f1SBob Moore /* Lock must be already acquired */
2740f6896f1SBob Moore
2750f6896f1SBob Moore if (!acpi_gbl_global_lock_acquired) {
2760f6896f1SBob Moore ACPI_WARNING((AE_INFO,
2770f6896f1SBob Moore "Cannot release the ACPI Global Lock, it has not been acquired"));
2780f6896f1SBob Moore return_ACPI_STATUS(AE_NOT_ACQUIRED);
2790f6896f1SBob Moore }
2800f6896f1SBob Moore
2810f6896f1SBob Moore if (acpi_gbl_global_lock_present) {
2820f6896f1SBob Moore
2830f6896f1SBob Moore /* Allow any thread to release the lock */
2840f6896f1SBob Moore
2850f6896f1SBob Moore ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
2860f6896f1SBob Moore
2870f6896f1SBob Moore /*
2880f6896f1SBob Moore * If the pending bit was set, we must write GBL_RLS to the control
2890f6896f1SBob Moore * register
2900f6896f1SBob Moore */
2910f6896f1SBob Moore if (pending) {
2920f6896f1SBob Moore status =
2930f6896f1SBob Moore acpi_write_bit_register
2940f6896f1SBob Moore (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
2950f6896f1SBob Moore ACPI_ENABLE_EVENT);
2960f6896f1SBob Moore }
2970f6896f1SBob Moore
2980f6896f1SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
2990f6896f1SBob Moore "Released hardware Global Lock\n"));
3000f6896f1SBob Moore }
3010f6896f1SBob Moore
3020f6896f1SBob Moore acpi_gbl_global_lock_acquired = FALSE;
3030f6896f1SBob Moore
3040f6896f1SBob Moore /* Release the local GL mutex */
3050f6896f1SBob Moore
3060f6896f1SBob Moore acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
3070f6896f1SBob Moore return_ACPI_STATUS(status);
3080f6896f1SBob Moore }
30933620c54SBob Moore
31033620c54SBob Moore #endif /* !ACPI_REDUCED_HARDWARE */
311