162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: utownerid - Support for Table/Method Owner IDs 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci ******************************************************************************/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <acpi/acpi.h> 962306a36Sopenharmony_ci#include "accommon.h" 1062306a36Sopenharmony_ci#include "acnamesp.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define _COMPONENT ACPI_UTILITIES 1362306a36Sopenharmony_ciACPI_MODULE_NAME("utownerid") 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/******************************************************************************* 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * FUNCTION: acpi_ut_allocate_owner_id 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * PARAMETERS: owner_id - Where the new owner ID is returned 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * RETURN: Status 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to 2462306a36Sopenharmony_ci * track objects created by the table or method, to be deleted 2562306a36Sopenharmony_ci * when the method exits or the table is unloaded. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci ******************************************************************************/ 2862306a36Sopenharmony_ciacpi_status acpi_ut_allocate_owner_id(acpi_owner_id *owner_id) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci u32 i; 3162306a36Sopenharmony_ci u32 j; 3262306a36Sopenharmony_ci u32 k; 3362306a36Sopenharmony_ci acpi_status status; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_allocate_owner_id); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* Guard against multiple allocations of ID to the same location */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (*owner_id) { 4062306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 4162306a36Sopenharmony_ci "Owner ID [0x%3.3X] already exists", *owner_id)); 4262306a36Sopenharmony_ci return_ACPI_STATUS(AE_ALREADY_EXISTS); 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* Mutex for the global ID mask */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 4862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 4962306a36Sopenharmony_ci return_ACPI_STATUS(status); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* 5362306a36Sopenharmony_ci * Find a free owner ID, cycle through all possible IDs on repeated 5462306a36Sopenharmony_ci * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index 5562306a36Sopenharmony_ci * may have to be scanned twice. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci for (i = 0, j = acpi_gbl_last_owner_id_index; 5862306a36Sopenharmony_ci i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) { 5962306a36Sopenharmony_ci if (j >= ACPI_NUM_OWNERID_MASKS) { 6062306a36Sopenharmony_ci j = 0; /* Wraparound to start of mask array */ 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) { 6462306a36Sopenharmony_ci if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) { 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* There are no free IDs in this mask */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * Note: the u32 cast ensures that 1 is stored as a unsigned 7362306a36Sopenharmony_ci * integer. Omitting the cast may result in 1 being stored as an 7462306a36Sopenharmony_ci * int. Some compilers or runtime error detection may flag this as 7562306a36Sopenharmony_ci * an error. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci if (!(acpi_gbl_owner_id_mask[j] & ((u32)1 << k))) { 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * Found a free ID. The actual ID is the bit index plus one, 8062306a36Sopenharmony_ci * making zero an invalid Owner ID. Save this as the last ID 8162306a36Sopenharmony_ci * allocated and update the global ID mask. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci acpi_gbl_owner_id_mask[j] |= ((u32)1 << k); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci acpi_gbl_last_owner_id_index = (u8)j; 8662306a36Sopenharmony_ci acpi_gbl_next_owner_id_offset = (u8)(k + 1); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * Construct encoded ID from the index and bit position 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * Note: Last [j].k (bit 4095) is never used and is marked 9262306a36Sopenharmony_ci * permanently allocated (prevents +1 overflow) 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci *owner_id = 9562306a36Sopenharmony_ci (acpi_owner_id)((k + 1) + ACPI_MUL_32(j)); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_VALUES, 9862306a36Sopenharmony_ci "Allocated OwnerId: 0x%3.3X\n", 9962306a36Sopenharmony_ci (unsigned int)*owner_id)); 10062306a36Sopenharmony_ci goto exit; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci acpi_gbl_next_owner_id_offset = 0; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* 10862306a36Sopenharmony_ci * All owner_ids have been allocated. This typically should 10962306a36Sopenharmony_ci * not happen since the IDs are reused after deallocation. The IDs are 11062306a36Sopenharmony_ci * allocated upon table load (one per table) and method execution, and 11162306a36Sopenharmony_ci * they are released when a table is unloaded or a method completes 11262306a36Sopenharmony_ci * execution. 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * If this error happens, there may be very deep nesting of invoked 11562306a36Sopenharmony_ci * control methods, or there may be a bug where the IDs are not released. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci status = AE_OWNER_ID_LIMIT; 11862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 11962306a36Sopenharmony_ci "Could not allocate new OwnerId (4095 max), AE_OWNER_ID_LIMIT")); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciexit: 12262306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); 12362306a36Sopenharmony_ci return_ACPI_STATUS(status); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/******************************************************************************* 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * FUNCTION: acpi_ut_release_owner_id 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * PARAMETERS: owner_id_ptr - Pointer to a previously allocated owner_ID 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * RETURN: None. No error is returned because we are either exiting a 13362306a36Sopenharmony_ci * control method or unloading a table. Either way, we would 13462306a36Sopenharmony_ci * ignore any error anyway. 13562306a36Sopenharmony_ci * 13662306a36Sopenharmony_ci * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci ******************************************************************************/ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_civoid acpi_ut_release_owner_id(acpi_owner_id *owner_id_ptr) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci acpi_owner_id owner_id = *owner_id_ptr; 14362306a36Sopenharmony_ci acpi_status status; 14462306a36Sopenharmony_ci u32 index; 14562306a36Sopenharmony_ci u32 bit; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Always clear the input owner_id (zero is an invalid ID) */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci *owner_id_ptr = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Zero is not a valid owner_ID */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (owner_id == 0) { 15662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%3.3X", owner_id)); 15762306a36Sopenharmony_ci return_VOID; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Mutex for the global ID mask */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 16362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 16462306a36Sopenharmony_ci return_VOID; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Normalize the ID to zero */ 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci owner_id--; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Decode ID to index/offset pair */ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci index = ACPI_DIV_32(owner_id); 17462306a36Sopenharmony_ci bit = (u32)1 << ACPI_MOD_32(owner_id); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Free the owner ID only if it is valid */ 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (acpi_gbl_owner_id_mask[index] & bit) { 17962306a36Sopenharmony_ci acpi_gbl_owner_id_mask[index] ^= bit; 18062306a36Sopenharmony_ci } else { 18162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 18262306a36Sopenharmony_ci "Attempted release of non-allocated OwnerId: 0x%3.3X", 18362306a36Sopenharmony_ci owner_id + 1)); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); 18762306a36Sopenharmony_ci return_VOID; 18862306a36Sopenharmony_ci} 189