1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: evglock - Global Lock support 5 * 6 * Copyright (C) 2000 - 2025, 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_EVENTS 16 ACPI_MODULE_NAME("evglock") 17 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 18 /* Local prototypes */ 19 static u32 acpi_ev_global_lock_handler(void *context); 20 21 /******************************************************************************* 22 * 23 * FUNCTION: acpi_ev_init_global_lock_handler 24 * 25 * PARAMETERS: None 26 * 27 * RETURN: Status 28 * 29 * DESCRIPTION: Install a handler for the global lock release event 30 * 31 ******************************************************************************/ 32 33 acpi_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 if (!acpi_gbl_use_global_lock) { 46 return_ACPI_STATUS(AE_OK); 47 } 48 49 /* Attempt installation of the global lock handler */ 50 51 status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, 52 acpi_ev_global_lock_handler, 53 NULL); 54 55 /* 56 * If the global lock does not exist on this platform, the attempt to 57 * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick). 58 * Map to AE_OK, but mark global lock as not present. Any attempt to 59 * actually use the global lock will be flagged with an error. 60 */ 61 acpi_gbl_global_lock_present = FALSE; 62 if (status == AE_NO_HARDWARE_RESPONSE) { 63 ACPI_ERROR((AE_INFO, 64 "No response from Global Lock hardware, disabling lock")); 65 66 return_ACPI_STATUS(AE_OK); 67 } 68 69 status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock); 70 if (ACPI_FAILURE(status)) { 71 return_ACPI_STATUS(status); 72 } 73 74 acpi_gbl_global_lock_pending = FALSE; 75 acpi_gbl_global_lock_present = TRUE; 76 return_ACPI_STATUS(status); 77 } 78 79 /******************************************************************************* 80 * 81 * FUNCTION: acpi_ev_remove_global_lock_handler 82 * 83 * PARAMETERS: None 84 * 85 * RETURN: Status 86 * 87 * DESCRIPTION: Remove the handler for the Global Lock 88 * 89 ******************************************************************************/ 90 91 acpi_status acpi_ev_remove_global_lock_handler(void) 92 { 93 acpi_status status; 94 95 ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler); 96 97 acpi_gbl_global_lock_present = FALSE; 98 status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL, 99 acpi_ev_global_lock_handler); 100 101 acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock); 102 return_ACPI_STATUS(status); 103 } 104 105 /******************************************************************************* 106 * 107 * FUNCTION: acpi_ev_global_lock_handler 108 * 109 * PARAMETERS: context - From thread interface, not used 110 * 111 * RETURN: ACPI_INTERRUPT_HANDLED 112 * 113 * DESCRIPTION: Invoked directly from the SCI handler when a global lock 114 * release interrupt occurs. If there is actually a pending 115 * request for the lock, signal the waiting thread. 116 * 117 ******************************************************************************/ 118 119 static u32 acpi_ev_global_lock_handler(void *context) 120 { 121 acpi_status status; 122 acpi_cpu_flags flags; 123 124 flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); 125 126 /* 127 * If a request for the global lock is not actually pending, 128 * we are done. This handles "spurious" global lock interrupts 129 * which are possible (and have been seen) with bad BIOSs. 130 */ 131 if (!acpi_gbl_global_lock_pending) { 132 goto cleanup_and_exit; 133 } 134 135 /* 136 * Send a unit to the global lock semaphore. The actual acquisition 137 * of the global lock will be performed by the waiting thread. 138 */ 139 status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1); 140 if (ACPI_FAILURE(status)) { 141 ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore")); 142 } 143 144 acpi_gbl_global_lock_pending = FALSE; 145 146 cleanup_and_exit: 147 148 acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); 149 return (ACPI_INTERRUPT_HANDLED); 150 } 151 152 /****************************************************************************** 153 * 154 * FUNCTION: acpi_ev_acquire_global_lock 155 * 156 * PARAMETERS: timeout - Max time to wait for the lock, in millisec. 157 * 158 * RETURN: Status 159 * 160 * DESCRIPTION: Attempt to gain ownership of the Global Lock. 161 * 162 * MUTEX: Interpreter must be locked 163 * 164 * Note: The original implementation allowed multiple threads to "acquire" the 165 * Global Lock, and the OS would hold the lock until the last thread had 166 * released it. However, this could potentially starve the BIOS out of the 167 * lock, especially in the case where there is a tight handshake between the 168 * Embedded Controller driver and the BIOS. Therefore, this implementation 169 * allows only one thread to acquire the HW Global Lock at a time, and makes 170 * the global lock appear as a standard mutex on the OS side. 171 * 172 *****************************************************************************/ 173 174 acpi_status acpi_ev_acquire_global_lock(u16 timeout) 175 { 176 acpi_cpu_flags flags; 177 acpi_status status; 178 u8 acquired = FALSE; 179 180 ACPI_FUNCTION_TRACE(ev_acquire_global_lock); 181 182 /* 183 * Only one thread can acquire the GL at a time, the global_lock_mutex 184 * enforces this. This interface releases the interpreter if we must wait. 185 */ 186 status = 187 acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex. 188 os_mutex, timeout); 189 if (ACPI_FAILURE(status)) { 190 return_ACPI_STATUS(status); 191 } 192 193 /* 194 * Update the global lock handle and check for wraparound. The handle is 195 * only used for the external global lock interfaces, but it is updated 196 * here to properly handle the case where a single thread may acquire the 197 * lock via both the AML and the acpi_acquire_global_lock interfaces. The 198 * handle is therefore updated on the first acquire from a given thread 199 * regardless of where the acquisition request originated. 200 */ 201 acpi_gbl_global_lock_handle++; 202 if (acpi_gbl_global_lock_handle == 0) { 203 acpi_gbl_global_lock_handle = 1; 204 } 205 206 /* 207 * Make sure that a global lock actually exists. If not, just 208 * treat the lock as a standard mutex. 209 */ 210 if (!acpi_gbl_global_lock_present) { 211 acpi_gbl_global_lock_acquired = TRUE; 212 return_ACPI_STATUS(AE_OK); 213 } 214 215 flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); 216 217 do { 218 219 /* Attempt to acquire the actual hardware lock */ 220 221 ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); 222 if (acquired) { 223 acpi_gbl_global_lock_acquired = TRUE; 224 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 225 "Acquired hardware Global Lock\n")); 226 break; 227 } 228 229 /* 230 * Did not get the lock. The pending bit was set above, and 231 * we must now wait until we receive the global lock 232 * released interrupt. 233 */ 234 acpi_gbl_global_lock_pending = TRUE; 235 acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); 236 237 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 238 "Waiting for hardware Global Lock\n")); 239 240 /* 241 * Wait for handshake with the global lock interrupt handler. 242 * This interface releases the interpreter if we must wait. 243 */ 244 status = 245 acpi_ex_system_wait_semaphore 246 (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER); 247 248 flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); 249 250 } while (ACPI_SUCCESS(status)); 251 252 acpi_gbl_global_lock_pending = FALSE; 253 acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); 254 255 return_ACPI_STATUS(status); 256 } 257 258 /******************************************************************************* 259 * 260 * FUNCTION: acpi_ev_release_global_lock 261 * 262 * PARAMETERS: None 263 * 264 * RETURN: Status 265 * 266 * DESCRIPTION: Releases ownership of the Global Lock. 267 * 268 ******************************************************************************/ 269 270 acpi_status acpi_ev_release_global_lock(void) 271 { 272 u8 pending = FALSE; 273 acpi_status status = AE_OK; 274 275 ACPI_FUNCTION_TRACE(ev_release_global_lock); 276 277 /* Lock must be already acquired */ 278 279 if (!acpi_gbl_global_lock_acquired) { 280 ACPI_WARNING((AE_INFO, 281 "Cannot release the ACPI Global Lock, it has not been acquired")); 282 return_ACPI_STATUS(AE_NOT_ACQUIRED); 283 } 284 285 if (acpi_gbl_global_lock_present) { 286 287 /* Allow any thread to release the lock */ 288 289 ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending); 290 291 /* 292 * If the pending bit was set, we must write GBL_RLS to the control 293 * register 294 */ 295 if (pending) { 296 status = 297 acpi_write_bit_register 298 (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 299 ACPI_ENABLE_EVENT); 300 } 301 302 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 303 "Released hardware Global Lock\n")); 304 } 305 306 acpi_gbl_global_lock_acquired = FALSE; 307 308 /* Release the local GL mutex */ 309 310 acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex); 311 return_ACPI_STATUS(status); 312 } 313 314 #endif /* !ACPI_REDUCED_HARDWARE */ 315