1 /*******************************************************************************
   2  *
   3  * Module Name: utmutex - local mutex support
   4  *
   5  ******************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, 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 
  45 #define __UTMUTEX_C__
  46 
  47 #include "acpi.h"
  48 #include "accommon.h"
  49 
  50 #define _COMPONENT          ACPI_UTILITIES
  51         ACPI_MODULE_NAME    ("utmutex")
  52 
  53 /* Local prototypes */
  54 
  55 static ACPI_STATUS
  56 AcpiUtCreateMutex (
  57     ACPI_MUTEX_HANDLE       MutexId);
  58 
  59 static void
  60 AcpiUtDeleteMutex (
  61     ACPI_MUTEX_HANDLE       MutexId);
  62 
  63 
  64 /*******************************************************************************
  65  *
  66  * FUNCTION:    AcpiUtMutexInitialize
  67  *
  68  * PARAMETERS:  None.
  69  *
  70  * RETURN:      Status
  71  *
  72  * DESCRIPTION: Create the system mutex objects. This includes mutexes,
  73  *              spin locks, and reader/writer locks.
  74  *
  75  ******************************************************************************/
  76 
  77 ACPI_STATUS
  78 AcpiUtMutexInitialize (
  79     void)
  80 {
  81     UINT32                  i;
  82     ACPI_STATUS             Status;
  83 
  84 
  85     ACPI_FUNCTION_TRACE (UtMutexInitialize);
  86 
  87 
  88     /* Create each of the predefined mutex objects */
  89 
  90     for (i = 0; i < ACPI_NUM_MUTEX; i++)
  91     {
  92         Status = AcpiUtCreateMutex (i);
  93         if (ACPI_FAILURE (Status))
  94         {
  95             return_ACPI_STATUS (Status);
  96         }
  97     }
  98 
  99     /* Create the spinlocks for use at interrupt level or for speed */
 100 
 101     Status = AcpiOsCreateLock (&AcpiGbl_GpeLock);
 102     if (ACPI_FAILURE (Status))
 103     {
 104         return_ACPI_STATUS (Status);
 105     }
 106 
 107     Status = AcpiOsCreateLock (&AcpiGbl_HardwareLock);
 108     if (ACPI_FAILURE (Status))
 109     {
 110         return_ACPI_STATUS (Status);
 111     }
 112 
 113     Status = AcpiOsCreateLock (&AcpiGbl_ReferenceCountLock);
 114     if (ACPI_FAILURE (Status))
 115     {
 116         return_ACPI_STATUS (Status);
 117     }
 118 
 119     /* Mutex for _OSI support */
 120 
 121     Status = AcpiOsCreateMutex (&AcpiGbl_OsiMutex);
 122     if (ACPI_FAILURE (Status))
 123     {
 124         return_ACPI_STATUS (Status);
 125     }
 126 
 127     /* Create the reader/writer lock for namespace access */
 128 
 129     Status = AcpiUtCreateRwLock (&AcpiGbl_NamespaceRwLock);
 130     return_ACPI_STATUS (Status);
 131 }
 132 
 133 
 134 /*******************************************************************************
 135  *
 136  * FUNCTION:    AcpiUtMutexTerminate
 137  *
 138  * PARAMETERS:  None.
 139  *
 140  * RETURN:      None.
 141  *
 142  * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
 143  *              spin locks, and reader/writer locks.
 144  *
 145  ******************************************************************************/
 146 
 147 void
 148 AcpiUtMutexTerminate (
 149     void)
 150 {
 151     UINT32                  i;
 152 
 153 
 154     ACPI_FUNCTION_TRACE (UtMutexTerminate);
 155 
 156 
 157     /* Delete each predefined mutex object */
 158 
 159     for (i = 0; i < ACPI_NUM_MUTEX; i++)
 160     {
 161         AcpiUtDeleteMutex (i);
 162     }
 163 
 164     AcpiOsDeleteMutex (AcpiGbl_OsiMutex);
 165 
 166     /* Delete the spinlocks */
 167 
 168     AcpiOsDeleteLock (AcpiGbl_GpeLock);
 169     AcpiOsDeleteLock (AcpiGbl_HardwareLock);
 170     AcpiOsDeleteLock (AcpiGbl_ReferenceCountLock);
 171 
 172     /* Delete the reader/writer lock */
 173 
 174     AcpiUtDeleteRwLock (&AcpiGbl_NamespaceRwLock);
 175     return_VOID;
 176 }
 177 
 178 
 179 /*******************************************************************************
 180  *
 181  * FUNCTION:    AcpiUtCreateMutex
 182  *
 183  * PARAMETERS:  MutexID         - ID of the mutex to be created
 184  *
 185  * RETURN:      Status
 186  *
 187  * DESCRIPTION: Create a mutex object.
 188  *
 189  ******************************************************************************/
 190 
 191 static ACPI_STATUS
 192 AcpiUtCreateMutex (
 193     ACPI_MUTEX_HANDLE       MutexId)
 194 {
 195     ACPI_STATUS             Status = AE_OK;
 196 
 197 
 198     ACPI_FUNCTION_TRACE_U32 (UtCreateMutex, MutexId);
 199 
 200 
 201     if (!AcpiGbl_MutexInfo[MutexId].Mutex)
 202     {
 203         Status = AcpiOsCreateMutex (&AcpiGbl_MutexInfo[MutexId].Mutex);
 204         AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
 205         AcpiGbl_MutexInfo[MutexId].UseCount = 0;
 206     }
 207 
 208     return_ACPI_STATUS (Status);
 209 }
 210 
 211 
 212 /*******************************************************************************
 213  *
 214  * FUNCTION:    AcpiUtDeleteMutex
 215  *
 216  * PARAMETERS:  MutexID         - ID of the mutex to be deleted
 217  *
 218  * RETURN:      Status
 219  *
 220  * DESCRIPTION: Delete a mutex object.
 221  *
 222  ******************************************************************************/
 223 
 224 static void
 225 AcpiUtDeleteMutex (
 226     ACPI_MUTEX_HANDLE       MutexId)
 227 {
 228 
 229     ACPI_FUNCTION_TRACE_U32 (UtDeleteMutex, MutexId);
 230 
 231 
 232     AcpiOsDeleteMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
 233 
 234     AcpiGbl_MutexInfo[MutexId].Mutex = NULL;
 235     AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
 236 
 237     return_VOID;
 238 }
 239 
 240 
 241 /*******************************************************************************
 242  *
 243  * FUNCTION:    AcpiUtAcquireMutex
 244  *
 245  * PARAMETERS:  MutexID         - ID of the mutex to be acquired
 246  *
 247  * RETURN:      Status
 248  *
 249  * DESCRIPTION: Acquire a mutex object.
 250  *
 251  ******************************************************************************/
 252 
 253 ACPI_STATUS
 254 AcpiUtAcquireMutex (
 255     ACPI_MUTEX_HANDLE       MutexId)
 256 {
 257     ACPI_STATUS             Status;
 258     ACPI_THREAD_ID          ThisThreadId;
 259 
 260 
 261     ACPI_FUNCTION_NAME (UtAcquireMutex);
 262 
 263 
 264     if (MutexId > ACPI_MAX_MUTEX)
 265     {
 266         return (AE_BAD_PARAMETER);
 267     }
 268 
 269     ThisThreadId = AcpiOsGetThreadId ();
 270 
 271 #ifdef ACPI_MUTEX_DEBUG
 272     {
 273         UINT32                  i;
 274         /*
 275          * Mutex debug code, for internal debugging only.
 276          *
 277          * Deadlock prevention. Check if this thread owns any mutexes of value
 278          * greater than or equal to this one. If so, the thread has violated
 279          * the mutex ordering rule. This indicates a coding error somewhere in
 280          * the ACPI subsystem code.
 281          */
 282         for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
 283         {
 284             if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId)
 285             {
 286                 if (i == MutexId)
 287                 {
 288                     ACPI_ERROR ((AE_INFO,
 289                         "Mutex [%s] already acquired by this thread [%u]",
 290                         AcpiUtGetMutexName (MutexId),
 291                         (UINT32) ThisThreadId));
 292 
 293                     return (AE_ALREADY_ACQUIRED);
 294                 }
 295 
 296                 ACPI_ERROR ((AE_INFO,
 297                     "Invalid acquire order: Thread %u owns [%s], wants [%s]",
 298                     (UINT32) ThisThreadId, AcpiUtGetMutexName (i),
 299                     AcpiUtGetMutexName (MutexId)));
 300 
 301                 return (AE_ACQUIRE_DEADLOCK);
 302             }
 303         }
 304     }
 305 #endif
 306 
 307     ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
 308         "Thread %u attempting to acquire Mutex [%s]\n",
 309         (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
 310 
 311     Status = AcpiOsAcquireMutex (AcpiGbl_MutexInfo[MutexId].Mutex,
 312                 ACPI_WAIT_FOREVER);
 313     if (ACPI_SUCCESS (Status))
 314     {
 315         ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u acquired Mutex [%s]\n",
 316             (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
 317 
 318         AcpiGbl_MutexInfo[MutexId].UseCount++;
 319         AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId;
 320     }
 321     else
 322     {
 323         ACPI_EXCEPTION ((AE_INFO, Status,
 324             "Thread %u could not acquire Mutex [0x%X]",
 325             (UINT32) ThisThreadId, MutexId));
 326     }
 327 
 328     return (Status);
 329 }
 330 
 331 
 332 /*******************************************************************************
 333  *
 334  * FUNCTION:    AcpiUtReleaseMutex
 335  *
 336  * PARAMETERS:  MutexID         - ID of the mutex to be released
 337  *
 338  * RETURN:      Status
 339  *
 340  * DESCRIPTION: Release a mutex object.
 341  *
 342  ******************************************************************************/
 343 
 344 ACPI_STATUS
 345 AcpiUtReleaseMutex (
 346     ACPI_MUTEX_HANDLE       MutexId)
 347 {
 348     ACPI_FUNCTION_NAME (UtReleaseMutex);
 349 
 350 
 351     ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
 352         (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId)));
 353 
 354     if (MutexId > ACPI_MAX_MUTEX)
 355     {
 356         return (AE_BAD_PARAMETER);
 357     }
 358 
 359     /*
 360      * Mutex must be acquired in order to release it!
 361      */
 362     if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED)
 363     {
 364         ACPI_ERROR ((AE_INFO,
 365             "Mutex [0x%X] is not acquired, cannot release", MutexId));
 366 
 367         return (AE_NOT_ACQUIRED);
 368     }
 369 
 370 #ifdef ACPI_MUTEX_DEBUG
 371     {
 372         UINT32                  i;
 373         /*
 374          * Mutex debug code, for internal debugging only.
 375          *
 376          * Deadlock prevention. Check if this thread owns any mutexes of value
 377          * greater than this one. If so, the thread has violated the mutex
 378          * ordering rule. This indicates a coding error somewhere in
 379          * the ACPI subsystem code.
 380          */
 381         for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
 382         {
 383             if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ())
 384             {
 385                 if (i == MutexId)
 386                 {
 387                     continue;
 388                 }
 389 
 390                 ACPI_ERROR ((AE_INFO,
 391                     "Invalid release order: owns [%s], releasing [%s]",
 392                     AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId)));
 393 
 394                 return (AE_RELEASE_DEADLOCK);
 395             }
 396         }
 397     }
 398 #endif
 399 
 400     /* Mark unlocked FIRST */
 401 
 402     AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
 403 
 404     AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
 405     return (AE_OK);
 406 }