brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 989dc01 Raw
311 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: evglock - Global Lock support5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acevents.h"13#include "acinterp.h"14 15#define _COMPONENT          ACPI_EVENTS16ACPI_MODULE_NAME("evglock")17#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */18/* Local prototypes */19static u32 acpi_ev_global_lock_handler(void *context);20 21/*******************************************************************************22 *23 * FUNCTION:    acpi_ev_init_global_lock_handler24 *25 * PARAMETERS:  None26 *27 * RETURN:      Status28 *29 * DESCRIPTION: Install a handler for the global lock release event30 *31 ******************************************************************************/32 33acpi_status acpi_ev_init_global_lock_handler(void)34{35	acpi_status status;36 37	ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);38 39	/* If Hardware Reduced flag is set, there is no global lock */40 41	if (acpi_gbl_reduced_hardware) {42		return_ACPI_STATUS(AE_OK);43	}44 45	/* Attempt installation of the global lock handler */46 47	status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,48						  acpi_ev_global_lock_handler,49						  NULL);50 51	/*52	 * If the global lock does not exist on this platform, the attempt to53	 * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).54	 * Map to AE_OK, but mark global lock as not present. Any attempt to55	 * actually use the global lock will be flagged with an error.56	 */57	acpi_gbl_global_lock_present = FALSE;58	if (status == AE_NO_HARDWARE_RESPONSE) {59		ACPI_ERROR((AE_INFO,60			    "No response from Global Lock hardware, disabling lock"));61 62		return_ACPI_STATUS(AE_OK);63	}64 65	status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock);66	if (ACPI_FAILURE(status)) {67		return_ACPI_STATUS(status);68	}69 70	acpi_gbl_global_lock_pending = FALSE;71	acpi_gbl_global_lock_present = TRUE;72	return_ACPI_STATUS(status);73}74 75/*******************************************************************************76 *77 * FUNCTION:    acpi_ev_remove_global_lock_handler78 *79 * PARAMETERS:  None80 *81 * RETURN:      Status82 *83 * DESCRIPTION: Remove the handler for the Global Lock84 *85 ******************************************************************************/86 87acpi_status acpi_ev_remove_global_lock_handler(void)88{89	acpi_status status;90 91	ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);92 93	acpi_gbl_global_lock_present = FALSE;94	status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,95						 acpi_ev_global_lock_handler);96 97	acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);98	return_ACPI_STATUS(status);99}100 101/*******************************************************************************102 *103 * FUNCTION:    acpi_ev_global_lock_handler104 *105 * PARAMETERS:  context         - From thread interface, not used106 *107 * RETURN:      ACPI_INTERRUPT_HANDLED108 *109 * DESCRIPTION: Invoked directly from the SCI handler when a global lock110 *              release interrupt occurs. If there is actually a pending111 *              request for the lock, signal the waiting thread.112 *113 ******************************************************************************/114 115static u32 acpi_ev_global_lock_handler(void *context)116{117	acpi_status status;118	acpi_cpu_flags flags;119 120	flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);121 122	/*123	 * If a request for the global lock is not actually pending,124	 * we are done. This handles "spurious" global lock interrupts125	 * which are possible (and have been seen) with bad BIOSs.126	 */127	if (!acpi_gbl_global_lock_pending) {128		goto cleanup_and_exit;129	}130 131	/*132	 * Send a unit to the global lock semaphore. The actual acquisition133	 * of the global lock will be performed by the waiting thread.134	 */135	status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);136	if (ACPI_FAILURE(status)) {137		ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));138	}139 140	acpi_gbl_global_lock_pending = FALSE;141 142cleanup_and_exit:143 144	acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);145	return (ACPI_INTERRUPT_HANDLED);146}147 148/******************************************************************************149 *150 * FUNCTION:    acpi_ev_acquire_global_lock151 *152 * PARAMETERS:  timeout         - Max time to wait for the lock, in millisec.153 *154 * RETURN:      Status155 *156 * DESCRIPTION: Attempt to gain ownership of the Global Lock.157 *158 * MUTEX:       Interpreter must be locked159 *160 * Note: The original implementation allowed multiple threads to "acquire" the161 * Global Lock, and the OS would hold the lock until the last thread had162 * released it. However, this could potentially starve the BIOS out of the163 * lock, especially in the case where there is a tight handshake between the164 * Embedded Controller driver and the BIOS. Therefore, this implementation165 * allows only one thread to acquire the HW Global Lock at a time, and makes166 * the global lock appear as a standard mutex on the OS side.167 *168 *****************************************************************************/169 170acpi_status acpi_ev_acquire_global_lock(u16 timeout)171{172	acpi_cpu_flags flags;173	acpi_status status;174	u8 acquired = FALSE;175 176	ACPI_FUNCTION_TRACE(ev_acquire_global_lock);177 178	/*179	 * Only one thread can acquire the GL at a time, the global_lock_mutex180	 * enforces this. This interface releases the interpreter if we must wait.181	 */182	status =183	    acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex.184				      os_mutex, timeout);185	if (ACPI_FAILURE(status)) {186		return_ACPI_STATUS(status);187	}188 189	/*190	 * Update the global lock handle and check for wraparound. The handle is191	 * only used for the external global lock interfaces, but it is updated192	 * here to properly handle the case where a single thread may acquire the193	 * lock via both the AML and the acpi_acquire_global_lock interfaces. The194	 * handle is therefore updated on the first acquire from a given thread195	 * regardless of where the acquisition request originated.196	 */197	acpi_gbl_global_lock_handle++;198	if (acpi_gbl_global_lock_handle == 0) {199		acpi_gbl_global_lock_handle = 1;200	}201 202	/*203	 * Make sure that a global lock actually exists. If not, just204	 * treat the lock as a standard mutex.205	 */206	if (!acpi_gbl_global_lock_present) {207		acpi_gbl_global_lock_acquired = TRUE;208		return_ACPI_STATUS(AE_OK);209	}210 211	flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);212 213	do {214 215		/* Attempt to acquire the actual hardware lock */216 217		ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);218		if (acquired) {219			acpi_gbl_global_lock_acquired = TRUE;220			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,221					  "Acquired hardware Global Lock\n"));222			break;223		}224 225		/*226		 * Did not get the lock. The pending bit was set above, and227		 * we must now wait until we receive the global lock228		 * released interrupt.229		 */230		acpi_gbl_global_lock_pending = TRUE;231		acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);232 233		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,234				  "Waiting for hardware Global Lock\n"));235 236		/*237		 * Wait for handshake with the global lock interrupt handler.238		 * This interface releases the interpreter if we must wait.239		 */240		status =241		    acpi_ex_system_wait_semaphore242		    (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER);243 244		flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);245 246	} while (ACPI_SUCCESS(status));247 248	acpi_gbl_global_lock_pending = FALSE;249	acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);250 251	return_ACPI_STATUS(status);252}253 254/*******************************************************************************255 *256 * FUNCTION:    acpi_ev_release_global_lock257 *258 * PARAMETERS:  None259 *260 * RETURN:      Status261 *262 * DESCRIPTION: Releases ownership of the Global Lock.263 *264 ******************************************************************************/265 266acpi_status acpi_ev_release_global_lock(void)267{268	u8 pending = FALSE;269	acpi_status status = AE_OK;270 271	ACPI_FUNCTION_TRACE(ev_release_global_lock);272 273	/* Lock must be already acquired */274 275	if (!acpi_gbl_global_lock_acquired) {276		ACPI_WARNING((AE_INFO,277			      "Cannot release the ACPI Global Lock, it has not been acquired"));278		return_ACPI_STATUS(AE_NOT_ACQUIRED);279	}280 281	if (acpi_gbl_global_lock_present) {282 283		/* Allow any thread to release the lock */284 285		ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);286 287		/*288		 * If the pending bit was set, we must write GBL_RLS to the control289		 * register290		 */291		if (pending) {292			status =293			    acpi_write_bit_register294			    (ACPI_BITREG_GLOBAL_LOCK_RELEASE,295			     ACPI_ENABLE_EVENT);296		}297 298		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,299				  "Released hardware Global Lock\n"));300	}301 302	acpi_gbl_global_lock_acquired = FALSE;303 304	/* Release the local GL mutex */305 306	acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);307	return_ACPI_STATUS(status);308}309 310#endif				/* !ACPI_REDUCED_HARDWARE */311