Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: evglock - Global Lock support
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acevents.h"
0013 #include "acinterp.h"
0014 
0015 #define _COMPONENT          ACPI_EVENTS
0016 ACPI_MODULE_NAME("evglock")
0017 #if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
0018 /* Local prototypes */
0019 static u32 acpi_ev_global_lock_handler(void *context);
0020 
0021 /*******************************************************************************
0022  *
0023  * FUNCTION:    acpi_ev_init_global_lock_handler
0024  *
0025  * PARAMETERS:  None
0026  *
0027  * RETURN:      Status
0028  *
0029  * DESCRIPTION: Install a handler for the global lock release event
0030  *
0031  ******************************************************************************/
0032 
0033 acpi_status acpi_ev_init_global_lock_handler(void)
0034 {
0035     acpi_status status;
0036 
0037     ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
0038 
0039     /* If Hardware Reduced flag is set, there is no global lock */
0040 
0041     if (acpi_gbl_reduced_hardware) {
0042         return_ACPI_STATUS(AE_OK);
0043     }
0044 
0045     /* Attempt installation of the global lock handler */
0046 
0047     status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
0048                           acpi_ev_global_lock_handler,
0049                           NULL);
0050 
0051     /*
0052      * If the global lock does not exist on this platform, the attempt to
0053      * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
0054      * Map to AE_OK, but mark global lock as not present. Any attempt to
0055      * actually use the global lock will be flagged with an error.
0056      */
0057     acpi_gbl_global_lock_present = FALSE;
0058     if (status == AE_NO_HARDWARE_RESPONSE) {
0059         ACPI_ERROR((AE_INFO,
0060                 "No response from Global Lock hardware, disabling lock"));
0061 
0062         return_ACPI_STATUS(AE_OK);
0063     }
0064 
0065     status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock);
0066     if (ACPI_FAILURE(status)) {
0067         return_ACPI_STATUS(status);
0068     }
0069 
0070     acpi_gbl_global_lock_pending = FALSE;
0071     acpi_gbl_global_lock_present = TRUE;
0072     return_ACPI_STATUS(status);
0073 }
0074 
0075 /*******************************************************************************
0076  *
0077  * FUNCTION:    acpi_ev_remove_global_lock_handler
0078  *
0079  * PARAMETERS:  None
0080  *
0081  * RETURN:      Status
0082  *
0083  * DESCRIPTION: Remove the handler for the Global Lock
0084  *
0085  ******************************************************************************/
0086 
0087 acpi_status acpi_ev_remove_global_lock_handler(void)
0088 {
0089     acpi_status status;
0090 
0091     ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
0092 
0093     acpi_gbl_global_lock_present = FALSE;
0094     status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
0095                          acpi_ev_global_lock_handler);
0096 
0097     acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);
0098     return_ACPI_STATUS(status);
0099 }
0100 
0101 /*******************************************************************************
0102  *
0103  * FUNCTION:    acpi_ev_global_lock_handler
0104  *
0105  * PARAMETERS:  context         - From thread interface, not used
0106  *
0107  * RETURN:      ACPI_INTERRUPT_HANDLED
0108  *
0109  * DESCRIPTION: Invoked directly from the SCI handler when a global lock
0110  *              release interrupt occurs. If there is actually a pending
0111  *              request for the lock, signal the waiting thread.
0112  *
0113  ******************************************************************************/
0114 
0115 static u32 acpi_ev_global_lock_handler(void *context)
0116 {
0117     acpi_status status;
0118     acpi_cpu_flags flags;
0119 
0120     flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
0121 
0122     /*
0123      * If a request for the global lock is not actually pending,
0124      * we are done. This handles "spurious" global lock interrupts
0125      * which are possible (and have been seen) with bad BIOSs.
0126      */
0127     if (!acpi_gbl_global_lock_pending) {
0128         goto cleanup_and_exit;
0129     }
0130 
0131     /*
0132      * Send a unit to the global lock semaphore. The actual acquisition
0133      * of the global lock will be performed by the waiting thread.
0134      */
0135     status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
0136     if (ACPI_FAILURE(status)) {
0137         ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
0138     }
0139 
0140     acpi_gbl_global_lock_pending = FALSE;
0141 
0142 cleanup_and_exit:
0143 
0144     acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
0145     return (ACPI_INTERRUPT_HANDLED);
0146 }
0147 
0148 /******************************************************************************
0149  *
0150  * FUNCTION:    acpi_ev_acquire_global_lock
0151  *
0152  * PARAMETERS:  timeout         - Max time to wait for the lock, in millisec.
0153  *
0154  * RETURN:      Status
0155  *
0156  * DESCRIPTION: Attempt to gain ownership of the Global Lock.
0157  *
0158  * MUTEX:       Interpreter must be locked
0159  *
0160  * Note: The original implementation allowed multiple threads to "acquire" the
0161  * Global Lock, and the OS would hold the lock until the last thread had
0162  * released it. However, this could potentially starve the BIOS out of the
0163  * lock, especially in the case where there is a tight handshake between the
0164  * Embedded Controller driver and the BIOS. Therefore, this implementation
0165  * allows only one thread to acquire the HW Global Lock at a time, and makes
0166  * the global lock appear as a standard mutex on the OS side.
0167  *
0168  *****************************************************************************/
0169 
0170 acpi_status acpi_ev_acquire_global_lock(u16 timeout)
0171 {
0172     acpi_cpu_flags flags;
0173     acpi_status status;
0174     u8 acquired = FALSE;
0175 
0176     ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
0177 
0178     /*
0179      * Only one thread can acquire the GL at a time, the global_lock_mutex
0180      * enforces this. This interface releases the interpreter if we must wait.
0181      */
0182     status =
0183         acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex.
0184                       os_mutex, timeout);
0185     if (ACPI_FAILURE(status)) {
0186         return_ACPI_STATUS(status);
0187     }
0188 
0189     /*
0190      * Update the global lock handle and check for wraparound. The handle is
0191      * only used for the external global lock interfaces, but it is updated
0192      * here to properly handle the case where a single thread may acquire the
0193      * lock via both the AML and the acpi_acquire_global_lock interfaces. The
0194      * handle is therefore updated on the first acquire from a given thread
0195      * regardless of where the acquisition request originated.
0196      */
0197     acpi_gbl_global_lock_handle++;
0198     if (acpi_gbl_global_lock_handle == 0) {
0199         acpi_gbl_global_lock_handle = 1;
0200     }
0201 
0202     /*
0203      * Make sure that a global lock actually exists. If not, just
0204      * treat the lock as a standard mutex.
0205      */
0206     if (!acpi_gbl_global_lock_present) {
0207         acpi_gbl_global_lock_acquired = TRUE;
0208         return_ACPI_STATUS(AE_OK);
0209     }
0210 
0211     flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
0212 
0213     do {
0214 
0215         /* Attempt to acquire the actual hardware lock */
0216 
0217         ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
0218         if (acquired) {
0219             acpi_gbl_global_lock_acquired = TRUE;
0220             ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0221                       "Acquired hardware Global Lock\n"));
0222             break;
0223         }
0224 
0225         /*
0226          * Did not get the lock. The pending bit was set above, and
0227          * we must now wait until we receive the global lock
0228          * released interrupt.
0229          */
0230         acpi_gbl_global_lock_pending = TRUE;
0231         acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
0232 
0233         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0234                   "Waiting for hardware Global Lock\n"));
0235 
0236         /*
0237          * Wait for handshake with the global lock interrupt handler.
0238          * This interface releases the interpreter if we must wait.
0239          */
0240         status =
0241             acpi_ex_system_wait_semaphore
0242             (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER);
0243 
0244         flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
0245 
0246     } while (ACPI_SUCCESS(status));
0247 
0248     acpi_gbl_global_lock_pending = FALSE;
0249     acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
0250 
0251     return_ACPI_STATUS(status);
0252 }
0253 
0254 /*******************************************************************************
0255  *
0256  * FUNCTION:    acpi_ev_release_global_lock
0257  *
0258  * PARAMETERS:  None
0259  *
0260  * RETURN:      Status
0261  *
0262  * DESCRIPTION: Releases ownership of the Global Lock.
0263  *
0264  ******************************************************************************/
0265 
0266 acpi_status acpi_ev_release_global_lock(void)
0267 {
0268     u8 pending = FALSE;
0269     acpi_status status = AE_OK;
0270 
0271     ACPI_FUNCTION_TRACE(ev_release_global_lock);
0272 
0273     /* Lock must be already acquired */
0274 
0275     if (!acpi_gbl_global_lock_acquired) {
0276         ACPI_WARNING((AE_INFO,
0277                   "Cannot release the ACPI Global Lock, it has not been acquired"));
0278         return_ACPI_STATUS(AE_NOT_ACQUIRED);
0279     }
0280 
0281     if (acpi_gbl_global_lock_present) {
0282 
0283         /* Allow any thread to release the lock */
0284 
0285         ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
0286 
0287         /*
0288          * If the pending bit was set, we must write GBL_RLS to the control
0289          * register
0290          */
0291         if (pending) {
0292             status =
0293                 acpi_write_bit_register
0294                 (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
0295                  ACPI_ENABLE_EVENT);
0296         }
0297 
0298         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0299                   "Released hardware Global Lock\n"));
0300     }
0301 
0302     acpi_gbl_global_lock_acquired = FALSE;
0303 
0304     /* Release the local GL mutex */
0305 
0306     acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
0307     return_ACPI_STATUS(status);
0308 }
0309 
0310 #endif              /* !ACPI_REDUCED_HARDWARE */