linux/drivers/acpi/acpica/exmutex.c
<<
>>
Prefs
   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 - 2021, 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
  16ACPI_MODULE_NAME("exmutex")
  17
  18/* Local prototypes */
  19static void
  20acpi_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
  35void 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
  78static void
  79acpi_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
 125acpi_status
 126acpi_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
 190acpi_status
 191acpi_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
 283acpi_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
 338acpi_status
 339acpi_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
 461void 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}
 507