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