root/drivers/acpi/acpica/exmutex.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ACPI_MODULE_NAME
  2. acpi_ex_link_mutex
  3. acpi_ex_acquire_mutex_object
  4. acpi_ex_acquire_mutex
  5. acpi_ex_release_mutex_object
  6. acpi_ex_release_mutex
  7. acpi_ex_release_all_mutexes

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /******************************************************************************
   3  *
   4  * Module Name: exmutex - ASL Mutex Acquire/Release functions
   5  *
   6  * Copyright (C) 2000 - 2019, Intel Corp.
   7  *
   8  *****************************************************************************/
   9 
  10 #include <acpi/acpi.h>
  11 #include "accommon.h"
  12 #include "acinterp.h"
  13 #include "acevents.h"
  14 
  15 #define _COMPONENT          ACPI_EXECUTER
  16 ACPI_MODULE_NAME("exmutex")
  17 
  18 /* Local prototypes */
  19 static void
  20 acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
  21                    struct acpi_thread_state *thread);
  22 
  23 /*******************************************************************************
  24  *
  25  * FUNCTION:    acpi_ex_unlink_mutex
  26  *
  27  * PARAMETERS:  obj_desc            - The mutex to be unlinked
  28  *
  29  * RETURN:      None
  30  *
  31  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
  32  *
  33  ******************************************************************************/
  34 
  35 void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
  36 {
  37         struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
  38 
  39         if (!thread) {
  40                 return;
  41         }
  42 
  43         /* Doubly linked list */
  44 
  45         if (obj_desc->mutex.next) {
  46                 (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev;
  47         }
  48 
  49         if (obj_desc->mutex.prev) {
  50                 (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
  51 
  52                 /*
  53                  * Migrate the previous sync level associated with this mutex to
  54                  * the previous mutex on the list so that it may be preserved.
  55                  * This handles the case where several mutexes have been acquired
  56                  * at the same level, but are not released in opposite order.
  57                  */
  58                 (obj_desc->mutex.prev)->mutex.original_sync_level =
  59                     obj_desc->mutex.original_sync_level;
  60         } else {
  61                 thread->acquired_mutex_list = obj_desc->mutex.next;
  62         }
  63 }
  64 
  65 /*******************************************************************************
  66  *
  67  * FUNCTION:    acpi_ex_link_mutex
  68  *
  69  * PARAMETERS:  obj_desc            - The mutex to be linked
  70  *              thread              - Current executing thread object
  71  *
  72  * RETURN:      None
  73  *
  74  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
  75  *
  76  ******************************************************************************/
  77 
  78 static void
  79 acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
  80                    struct acpi_thread_state *thread)
  81 {
  82         union acpi_operand_object *list_head;
  83 
  84         list_head = thread->acquired_mutex_list;
  85 
  86         /* This object will be the first object in the list */
  87 
  88         obj_desc->mutex.prev = NULL;
  89         obj_desc->mutex.next = list_head;
  90 
  91         /* Update old first object to point back to this object */
  92 
  93         if (list_head) {
  94                 list_head->mutex.prev = obj_desc;
  95         }
  96 
  97         /* Update list head */
  98 
  99         thread->acquired_mutex_list = obj_desc;
 100 }
 101 
 102 /*******************************************************************************
 103  *
 104  * FUNCTION:    acpi_ex_acquire_mutex_object
 105  *
 106  * PARAMETERS:  timeout             - Timeout in milliseconds
 107  *              obj_desc            - Mutex object
 108  *              thread_id           - Current thread state
 109  *
 110  * RETURN:      Status
 111  *
 112  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
 113  *              path that supports multiple acquires by the same thread.
 114  *
 115  * MUTEX:       Interpreter must be locked
 116  *
 117  * NOTE: This interface is called from three places:
 118  * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator
 119  * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the
 120  *    global lock
 121  * 3) From the external interface, acpi_acquire_global_lock
 122  *
 123  ******************************************************************************/
 124 
 125 acpi_status
 126 acpi_ex_acquire_mutex_object(u16 timeout,
 127                              union acpi_operand_object *obj_desc,
 128                              acpi_thread_id thread_id)
 129 {
 130         acpi_status status;
 131 
 132         ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc);
 133 
 134         if (!obj_desc) {
 135                 return_ACPI_STATUS(AE_BAD_PARAMETER);
 136         }
 137 
 138         /* Support for multiple acquires by the owning thread */
 139 
 140         if (obj_desc->mutex.thread_id == thread_id) {
 141                 /*
 142                  * The mutex is already owned by this thread, just increment the
 143                  * acquisition depth
 144                  */
 145                 obj_desc->mutex.acquisition_depth++;
 146                 return_ACPI_STATUS(AE_OK);
 147         }
 148 
 149         /* Acquire the mutex, wait if necessary. Special case for Global Lock */
 150 
 151         if (obj_desc == acpi_gbl_global_lock_mutex) {
 152                 status = acpi_ev_acquire_global_lock(timeout);
 153         } else {
 154                 status =
 155                     acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
 156                                               timeout);
 157         }
 158 
 159         if (ACPI_FAILURE(status)) {
 160 
 161                 /* Includes failure from a timeout on time_desc */
 162 
 163                 return_ACPI_STATUS(status);
 164         }
 165 
 166         /* Acquired the mutex: update mutex object */
 167 
 168         obj_desc->mutex.thread_id = thread_id;
 169         obj_desc->mutex.acquisition_depth = 1;
 170         obj_desc->mutex.original_sync_level = 0;
 171         obj_desc->mutex.owner_thread = NULL;    /* Used only for AML Acquire() */
 172 
 173         return_ACPI_STATUS(AE_OK);
 174 }
 175 
 176 /*******************************************************************************
 177  *
 178  * FUNCTION:    acpi_ex_acquire_mutex
 179  *
 180  * PARAMETERS:  time_desc           - Timeout integer
 181  *              obj_desc            - Mutex object
 182  *              walk_state          - Current method execution state
 183  *
 184  * RETURN:      Status
 185  *
 186  * DESCRIPTION: Acquire an AML mutex
 187  *
 188  ******************************************************************************/
 189 
 190 acpi_status
 191 acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
 192                       union acpi_operand_object *obj_desc,
 193                       struct acpi_walk_state *walk_state)
 194 {
 195         acpi_status status;
 196 
 197         ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc);
 198 
 199         if (!obj_desc) {
 200                 return_ACPI_STATUS(AE_BAD_PARAMETER);
 201         }
 202 
 203         /* Must have a valid thread state struct */
 204 
 205         if (!walk_state->thread) {
 206                 ACPI_ERROR((AE_INFO,
 207                             "Cannot acquire Mutex [%4.4s], null thread info",
 208                             acpi_ut_get_node_name(obj_desc->mutex.node)));
 209                 return_ACPI_STATUS(AE_AML_INTERNAL);
 210         }
 211 
 212         /*
 213          * Current sync level must be less than or equal to the sync level
 214          * of the mutex. This mechanism provides some deadlock prevention.
 215          */
 216         if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
 217                 ACPI_ERROR((AE_INFO,
 218                             "Cannot acquire Mutex [%4.4s], "
 219                             "current SyncLevel is too large (%u)",
 220                             acpi_ut_get_node_name(obj_desc->mutex.node),
 221                             walk_state->thread->current_sync_level));
 222                 return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
 223         }
 224 
 225         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 226                           "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, "
 227                           "Depth %u TID %p\n",
 228                           obj_desc->mutex.sync_level,
 229                           walk_state->thread->current_sync_level,
 230                           obj_desc->mutex.acquisition_depth,
 231                           walk_state->thread));
 232 
 233         status = acpi_ex_acquire_mutex_object((u16)time_desc->integer.value,
 234                                               obj_desc,
 235                                               walk_state->thread->thread_id);
 236 
 237         if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) {
 238 
 239                 /* Save Thread object, original/current sync levels */
 240 
 241                 obj_desc->mutex.owner_thread = walk_state->thread;
 242                 obj_desc->mutex.original_sync_level =
 243                     walk_state->thread->current_sync_level;
 244                 walk_state->thread->current_sync_level =
 245                     obj_desc->mutex.sync_level;
 246 
 247                 /* Link the mutex to the current thread for force-unlock at method exit */
 248 
 249                 acpi_ex_link_mutex(obj_desc, walk_state->thread);
 250         }
 251 
 252         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 253                           "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n",
 254                           obj_desc->mutex.sync_level,
 255                           walk_state->thread->current_sync_level,
 256                           obj_desc->mutex.acquisition_depth));
 257 
 258         return_ACPI_STATUS(status);
 259 }
 260 
 261 /*******************************************************************************
 262  *
 263  * FUNCTION:    acpi_ex_release_mutex_object
 264  *
 265  * PARAMETERS:  obj_desc            - The object descriptor for this op
 266  *
 267  * RETURN:      Status
 268  *
 269  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
 270  *              Provides a common path that supports multiple releases (after
 271  *              previous multiple acquires) by the same thread.
 272  *
 273  * MUTEX:       Interpreter must be locked
 274  *
 275  * NOTE: This interface is called from three places:
 276  * 1) From acpi_ex_release_mutex, via an AML Acquire() operator
 277  * 2) From acpi_ex_release_global_lock when an AML Field access requires the
 278  *    global lock
 279  * 3) From the external interface, acpi_release_global_lock
 280  *
 281  ******************************************************************************/
 282 
 283 acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
 284 {
 285         acpi_status status = AE_OK;
 286 
 287         ACPI_FUNCTION_TRACE(ex_release_mutex_object);
 288 
 289         if (obj_desc->mutex.acquisition_depth == 0) {
 290                 return_ACPI_STATUS(AE_NOT_ACQUIRED);
 291         }
 292 
 293         /* Match multiple Acquires with multiple Releases */
 294 
 295         obj_desc->mutex.acquisition_depth--;
 296         if (obj_desc->mutex.acquisition_depth != 0) {
 297 
 298                 /* Just decrement the depth and return */
 299 
 300                 return_ACPI_STATUS(AE_OK);
 301         }
 302 
 303         if (obj_desc->mutex.owner_thread) {
 304 
 305                 /* Unlink the mutex from the owner's list */
 306 
 307                 acpi_ex_unlink_mutex(obj_desc);
 308                 obj_desc->mutex.owner_thread = NULL;
 309         }
 310 
 311         /* Release the mutex, special case for Global Lock */
 312 
 313         if (obj_desc == acpi_gbl_global_lock_mutex) {
 314                 status = acpi_ev_release_global_lock();
 315         } else {
 316                 acpi_os_release_mutex(obj_desc->mutex.os_mutex);
 317         }
 318 
 319         /* Clear mutex info */
 320 
 321         obj_desc->mutex.thread_id = 0;
 322         return_ACPI_STATUS(status);
 323 }
 324 
 325 /*******************************************************************************
 326  *
 327  * FUNCTION:    acpi_ex_release_mutex
 328  *
 329  * PARAMETERS:  obj_desc            - The object descriptor for this op
 330  *              walk_state          - Current method execution state
 331  *
 332  * RETURN:      Status
 333  *
 334  * DESCRIPTION: Release a previously acquired Mutex.
 335  *
 336  ******************************************************************************/
 337 
 338 acpi_status
 339 acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 340                       struct acpi_walk_state *walk_state)
 341 {
 342         u8 previous_sync_level;
 343         struct acpi_thread_state *owner_thread;
 344         acpi_status status = AE_OK;
 345 
 346         ACPI_FUNCTION_TRACE(ex_release_mutex);
 347 
 348         if (!obj_desc) {
 349                 return_ACPI_STATUS(AE_BAD_PARAMETER);
 350         }
 351 
 352         owner_thread = obj_desc->mutex.owner_thread;
 353 
 354         /* The mutex must have been previously acquired in order to release it */
 355 
 356         if (!owner_thread) {
 357                 ACPI_ERROR((AE_INFO,
 358                             "Cannot release Mutex [%4.4s], not acquired",
 359                             acpi_ut_get_node_name(obj_desc->mutex.node)));
 360                 return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
 361         }
 362 
 363         /* Must have a valid thread ID */
 364 
 365         if (!walk_state->thread) {
 366                 ACPI_ERROR((AE_INFO,
 367                             "Cannot release Mutex [%4.4s], null thread info",
 368                             acpi_ut_get_node_name(obj_desc->mutex.node)));
 369                 return_ACPI_STATUS(AE_AML_INTERNAL);
 370         }
 371 
 372         /*
 373          * The Mutex is owned, but this thread must be the owner.
 374          * Special case for Global Lock, any thread can release
 375          */
 376         if ((owner_thread->thread_id != walk_state->thread->thread_id) &&
 377             (obj_desc != acpi_gbl_global_lock_mutex)) {
 378                 ACPI_ERROR((AE_INFO,
 379                             "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
 380                             (u32)walk_state->thread->thread_id,
 381                             acpi_ut_get_node_name(obj_desc->mutex.node),
 382                             (u32)owner_thread->thread_id));
 383                 return_ACPI_STATUS(AE_AML_NOT_OWNER);
 384         }
 385 
 386         /*
 387          * The sync level of the mutex must be equal to the current sync level. In
 388          * other words, the current level means that at least one mutex at that
 389          * level is currently being held. Attempting to release a mutex of a
 390          * different level can only mean that the mutex ordering rule is being
 391          * violated. This behavior is clarified in ACPI 4.0 specification.
 392          */
 393         if (obj_desc->mutex.sync_level != owner_thread->current_sync_level) {
 394                 ACPI_ERROR((AE_INFO,
 395                             "Cannot release Mutex [%4.4s], SyncLevel mismatch: "
 396                             "mutex %u current %u",
 397                             acpi_ut_get_node_name(obj_desc->mutex.node),
 398                             obj_desc->mutex.sync_level,
 399                             walk_state->thread->current_sync_level));
 400                 return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
 401         }
 402 
 403         /*
 404          * Get the previous sync_level from the head of the acquired mutex list.
 405          * This handles the case where several mutexes at the same level have been
 406          * acquired, but are not released in reverse order.
 407          */
 408         previous_sync_level =
 409             owner_thread->acquired_mutex_list->mutex.original_sync_level;
 410 
 411         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 412                           "Releasing: Object SyncLevel %u, Thread SyncLevel %u, "
 413                           "Prev SyncLevel %u, Depth %u TID %p\n",
 414                           obj_desc->mutex.sync_level,
 415                           walk_state->thread->current_sync_level,
 416                           previous_sync_level,
 417                           obj_desc->mutex.acquisition_depth,
 418                           walk_state->thread));
 419 
 420         status = acpi_ex_release_mutex_object(obj_desc);
 421         if (ACPI_FAILURE(status)) {
 422                 return_ACPI_STATUS(status);
 423         }
 424 
 425         if (obj_desc->mutex.acquisition_depth == 0) {
 426 
 427                 /* Restore the previous sync_level */
 428 
 429                 owner_thread->current_sync_level = previous_sync_level;
 430         }
 431 
 432         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 433                           "Released: Object SyncLevel %u, Thread SyncLevel, %u, "
 434                           "Prev SyncLevel %u, Depth %u\n",
 435                           obj_desc->mutex.sync_level,
 436                           walk_state->thread->current_sync_level,
 437                           previous_sync_level,
 438                           obj_desc->mutex.acquisition_depth));
 439 
 440         return_ACPI_STATUS(status);
 441 }
 442 
 443 /*******************************************************************************
 444  *
 445  * FUNCTION:    acpi_ex_release_all_mutexes
 446  *
 447  * PARAMETERS:  thread              - Current executing thread object
 448  *
 449  * RETURN:      Status
 450  *
 451  * DESCRIPTION: Release all mutexes held by this thread
 452  *
 453  * NOTE: This function is called as the thread is exiting the interpreter.
 454  * Mutexes are not released when an individual control method is exited, but
 455  * only when the parent thread actually exits the interpreter. This allows one
 456  * method to acquire a mutex, and a different method to release it, as long as
 457  * this is performed underneath a single parent control method.
 458  *
 459  ******************************************************************************/
 460 
 461 void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
 462 {
 463         union acpi_operand_object *next = thread->acquired_mutex_list;
 464         union acpi_operand_object *obj_desc;
 465 
 466         ACPI_FUNCTION_TRACE(ex_release_all_mutexes);
 467 
 468         /* Traverse the list of owned mutexes, releasing each one */
 469 
 470         while (next) {
 471                 obj_desc = next;
 472                 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 473                                   "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n",
 474                                   obj_desc->mutex.node->name.ascii,
 475                                   obj_desc->mutex.sync_level,
 476                                   obj_desc->mutex.acquisition_depth));
 477 
 478                 /* Release the mutex, special case for Global Lock */
 479 
 480                 if (obj_desc == acpi_gbl_global_lock_mutex) {
 481 
 482                         /* Ignore errors */
 483 
 484                         (void)acpi_ev_release_global_lock();
 485                 } else {
 486                         acpi_os_release_mutex(obj_desc->mutex.os_mutex);
 487                 }
 488 
 489                 /* Update Thread sync_level (Last mutex is the important one) */
 490 
 491                 thread->current_sync_level =
 492                     obj_desc->mutex.original_sync_level;
 493 
 494                 /* Mark mutex unowned */
 495 
 496                 next = obj_desc->mutex.next;
 497 
 498                 obj_desc->mutex.prev = NULL;
 499                 obj_desc->mutex.next = NULL;
 500                 obj_desc->mutex.acquisition_depth = 0;
 501                 obj_desc->mutex.owner_thread = NULL;
 502                 obj_desc->mutex.thread_id = 0;
 503         }
 504 
 505         return_VOID;
 506 }

/* [<][>][^][v][top][bottom][index][help] */