Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /******************************************************************************
  2.  *
  3.  * Module Name: evglock - Global Lock support
  4.  *
  5.  *****************************************************************************/
  6.  
  7. /*
  8.  * Copyright (C) 2000 - 2015, Intel Corp.
  9.  * All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms, with or without
  12.  * modification, are permitted provided that the following conditions
  13.  * are met:
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions, and the following disclaimer,
  16.  *    without modification.
  17.  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18.  *    substantially similar to the "NO WARRANTY" disclaimer below
  19.  *    ("Disclaimer") and any redistribution must be conditioned upon
  20.  *    including a substantially similar Disclaimer requirement for further
  21.  *    binary redistribution.
  22.  * 3. Neither the names of the above-listed copyright holders nor the names
  23.  *    of any contributors may be used to endorse or promote products derived
  24.  *    from this software without specific prior written permission.
  25.  *
  26.  * Alternatively, this software may be distributed under the terms of the
  27.  * GNU General Public License ("GPL") version 2 as published by the Free
  28.  * Software Foundation.
  29.  *
  30.  * NO WARRANTY
  31.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35.  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41.  * POSSIBILITY OF SUCH DAMAGES.
  42.  */
  43.  
  44. #include <acpi/acpi.h>
  45. #include "accommon.h"
  46. #include "acevents.h"
  47. #include "acinterp.h"
  48.  
  49. #define _COMPONENT          ACPI_EVENTS
  50. ACPI_MODULE_NAME("evglock")
  51. #if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
  52. /* Local prototypes */
  53. static u32 acpi_ev_global_lock_handler(void *context);
  54.  
  55. /*******************************************************************************
  56.  *
  57.  * FUNCTION:    acpi_ev_init_global_lock_handler
  58.  *
  59.  * PARAMETERS:  None
  60.  *
  61.  * RETURN:      Status
  62.  *
  63.  * DESCRIPTION: Install a handler for the global lock release event
  64.  *
  65.  ******************************************************************************/
  66.  
  67. acpi_status acpi_ev_init_global_lock_handler(void)
  68. {
  69.         acpi_status status;
  70.  
  71.         ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
  72.  
  73.         /* If Hardware Reduced flag is set, there is no global lock */
  74.  
  75.         if (acpi_gbl_reduced_hardware) {
  76.                 return_ACPI_STATUS(AE_OK);
  77.         }
  78.  
  79.         /* Attempt installation of the global lock handler */
  80.  
  81.         status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
  82.                                                   acpi_ev_global_lock_handler,
  83.                                                   NULL);
  84.  
  85.         /*
  86.          * If the global lock does not exist on this platform, the attempt to
  87.          * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
  88.          * Map to AE_OK, but mark global lock as not present. Any attempt to
  89.          * actually use the global lock will be flagged with an error.
  90.          */
  91.         acpi_gbl_global_lock_present = FALSE;
  92.         if (status == AE_NO_HARDWARE_RESPONSE) {
  93.                 ACPI_ERROR((AE_INFO,
  94.                             "No response from Global Lock hardware, disabling lock"));
  95.  
  96.                 return_ACPI_STATUS(AE_OK);
  97.         }
  98.  
  99.         status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock);
  100.         if (ACPI_FAILURE(status)) {
  101.                 return_ACPI_STATUS(status);
  102.         }
  103.  
  104.         acpi_gbl_global_lock_pending = FALSE;
  105.         acpi_gbl_global_lock_present = TRUE;
  106.         return_ACPI_STATUS(status);
  107. }
  108.  
  109. /*******************************************************************************
  110.  *
  111.  * FUNCTION:    acpi_ev_remove_global_lock_handler
  112.  *
  113.  * PARAMETERS:  None
  114.  *
  115.  * RETURN:      Status
  116.  *
  117.  * DESCRIPTION: Remove the handler for the Global Lock
  118.  *
  119.  ******************************************************************************/
  120.  
  121. acpi_status acpi_ev_remove_global_lock_handler(void)
  122. {
  123.         acpi_status status;
  124.  
  125.         ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
  126.  
  127.         acpi_gbl_global_lock_present = FALSE;
  128.         status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
  129.                                                  acpi_ev_global_lock_handler);
  130.  
  131.         acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);
  132.         return_ACPI_STATUS(status);
  133. }
  134.  
  135. /*******************************************************************************
  136.  *
  137.  * FUNCTION:    acpi_ev_global_lock_handler
  138.  *
  139.  * PARAMETERS:  context         - From thread interface, not used
  140.  *
  141.  * RETURN:      ACPI_INTERRUPT_HANDLED
  142.  *
  143.  * DESCRIPTION: Invoked directly from the SCI handler when a global lock
  144.  *              release interrupt occurs. If there is actually a pending
  145.  *              request for the lock, signal the waiting thread.
  146.  *
  147.  ******************************************************************************/
  148.  
  149. static u32 acpi_ev_global_lock_handler(void *context)
  150. {
  151.         acpi_status status;
  152.         acpi_cpu_flags flags;
  153.  
  154.         flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
  155.  
  156.         /*
  157.          * If a request for the global lock is not actually pending,
  158.          * we are done. This handles "spurious" global lock interrupts
  159.          * which are possible (and have been seen) with bad BIOSs.
  160.          */
  161.         if (!acpi_gbl_global_lock_pending) {
  162.                 goto cleanup_and_exit;
  163.         }
  164.  
  165.         /*
  166.          * Send a unit to the global lock semaphore. The actual acquisition
  167.          * of the global lock will be performed by the waiting thread.
  168.          */
  169.         status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
  170.         if (ACPI_FAILURE(status)) {
  171.                 ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
  172.         }
  173.  
  174.         acpi_gbl_global_lock_pending = FALSE;
  175.  
  176. cleanup_and_exit:
  177.  
  178.         acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
  179.         return (ACPI_INTERRUPT_HANDLED);
  180. }
  181.  
  182. /******************************************************************************
  183.  *
  184.  * FUNCTION:    acpi_ev_acquire_global_lock
  185.  *
  186.  * PARAMETERS:  timeout         - Max time to wait for the lock, in millisec.
  187.  *
  188.  * RETURN:      Status
  189.  *
  190.  * DESCRIPTION: Attempt to gain ownership of the Global Lock.
  191.  *
  192.  * MUTEX:       Interpreter must be locked
  193.  *
  194.  * Note: The original implementation allowed multiple threads to "acquire" the
  195.  * Global Lock, and the OS would hold the lock until the last thread had
  196.  * released it. However, this could potentially starve the BIOS out of the
  197.  * lock, especially in the case where there is a tight handshake between the
  198.  * Embedded Controller driver and the BIOS. Therefore, this implementation
  199.  * allows only one thread to acquire the HW Global Lock at a time, and makes
  200.  * the global lock appear as a standard mutex on the OS side.
  201.  *
  202.  *****************************************************************************/
  203.  
  204. acpi_status acpi_ev_acquire_global_lock(u16 timeout)
  205. {
  206.         acpi_cpu_flags flags;
  207.         acpi_status status;
  208.         u8 acquired = FALSE;
  209.  
  210.         ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
  211.  
  212.         /*
  213.          * Only one thread can acquire the GL at a time, the global_lock_mutex
  214.          * enforces this. This interface releases the interpreter if we must wait.
  215.          */
  216.         status =
  217.             acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex.
  218.                                       os_mutex, timeout);
  219.         if (ACPI_FAILURE(status)) {
  220.                 return_ACPI_STATUS(status);
  221.         }
  222.  
  223.         /*
  224.          * Update the global lock handle and check for wraparound. The handle is
  225.          * only used for the external global lock interfaces, but it is updated
  226.          * here to properly handle the case where a single thread may acquire the
  227.          * lock via both the AML and the acpi_acquire_global_lock interfaces. The
  228.          * handle is therefore updated on the first acquire from a given thread
  229.          * regardless of where the acquisition request originated.
  230.          */
  231.         acpi_gbl_global_lock_handle++;
  232.         if (acpi_gbl_global_lock_handle == 0) {
  233.                 acpi_gbl_global_lock_handle = 1;
  234.         }
  235.  
  236.         /*
  237.          * Make sure that a global lock actually exists. If not, just
  238.          * treat the lock as a standard mutex.
  239.          */
  240.         if (!acpi_gbl_global_lock_present) {
  241.                 acpi_gbl_global_lock_acquired = TRUE;
  242.                 return_ACPI_STATUS(AE_OK);
  243.         }
  244.  
  245.         flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
  246.  
  247.         do {
  248.  
  249.                 /* Attempt to acquire the actual hardware lock */
  250.  
  251.                 ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
  252.                 if (acquired) {
  253.                         acpi_gbl_global_lock_acquired = TRUE;
  254.                         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
  255.                                           "Acquired hardware Global Lock\n"));
  256.                         break;
  257.                 }
  258.  
  259.                 /*
  260.                  * Did not get the lock. The pending bit was set above, and
  261.                  * we must now wait until we receive the global lock
  262.                  * released interrupt.
  263.                  */
  264.                 acpi_gbl_global_lock_pending = TRUE;
  265.                 acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
  266.  
  267.                 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
  268.                                   "Waiting for hardware Global Lock\n"));
  269.  
  270.                 /*
  271.                  * Wait for handshake with the global lock interrupt handler.
  272.                  * This interface releases the interpreter if we must wait.
  273.                  */
  274.                 status =
  275.                     acpi_ex_system_wait_semaphore
  276.                     (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER);
  277.  
  278.                 flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
  279.  
  280.         } while (ACPI_SUCCESS(status));
  281.  
  282.         acpi_gbl_global_lock_pending = FALSE;
  283.         acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
  284.  
  285.         return_ACPI_STATUS(status);
  286. }
  287.  
  288. /*******************************************************************************
  289.  *
  290.  * FUNCTION:    acpi_ev_release_global_lock
  291.  *
  292.  * PARAMETERS:  None
  293.  *
  294.  * RETURN:      Status
  295.  *
  296.  * DESCRIPTION: Releases ownership of the Global Lock.
  297.  *
  298.  ******************************************************************************/
  299.  
  300. acpi_status acpi_ev_release_global_lock(void)
  301. {
  302.         u8 pending = FALSE;
  303.         acpi_status status = AE_OK;
  304.  
  305.         ACPI_FUNCTION_TRACE(ev_release_global_lock);
  306.  
  307.         /* Lock must be already acquired */
  308.  
  309.         if (!acpi_gbl_global_lock_acquired) {
  310.                 ACPI_WARNING((AE_INFO,
  311.                               "Cannot release the ACPI Global Lock, it has not been acquired"));
  312.                 return_ACPI_STATUS(AE_NOT_ACQUIRED);
  313.         }
  314.  
  315.         if (acpi_gbl_global_lock_present) {
  316.  
  317.                 /* Allow any thread to release the lock */
  318.  
  319.                 ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
  320.  
  321.                 /*
  322.                  * If the pending bit was set, we must write GBL_RLS to the control
  323.                  * register
  324.                  */
  325.                 if (pending) {
  326.                         status =
  327.                             acpi_write_bit_register
  328.                             (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
  329.                              ACPI_ENABLE_EVENT);
  330.                 }
  331.  
  332.                 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
  333.                                   "Released hardware Global Lock\n"));
  334.         }
  335.  
  336.         acpi_gbl_global_lock_acquired = FALSE;
  337.  
  338.         /* Release the local GL mutex */
  339.  
  340.         acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
  341.         return_ACPI_STATUS(status);
  342. }
  343.  
  344. #endif                          /* !ACPI_REDUCED_HARDWARE */
  345.