LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - evglock.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 45 81 55.6 %
Date: 2022-03-28 16:04:14 Functions: 3 5 60.0 %
Branches: 11 28 39.3 %

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

Generated by: LCOV version 1.14