xref: /openbmc/linux/drivers/acpi/acpica/evglock.c (revision 612c2932)
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