162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: tbdata - Table manager data structure functions 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acnamesp.h" 1362306a36Sopenharmony_ci#include "actables.h" 1462306a36Sopenharmony_ci#include "acevents.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define _COMPONENT ACPI_TABLES 1762306a36Sopenharmony_ciACPI_MODULE_NAME("tbdata") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Local prototypes */ 2062306a36Sopenharmony_cistatic acpi_status 2162306a36Sopenharmony_ciacpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic u8 2462306a36Sopenharmony_ciacpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/******************************************************************************* 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * FUNCTION: acpi_tb_compare_tables 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * PARAMETERS: table_desc - Table 1 descriptor to be compared 3162306a36Sopenharmony_ci * table_index - Index of table 2 to be compared 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * RETURN: TRUE if both tables are identical. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * DESCRIPTION: This function compares a table with another table that has 3662306a36Sopenharmony_ci * already been installed in the root table list. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci ******************************************************************************/ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic u8 4162306a36Sopenharmony_ciacpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci acpi_status status = AE_OK; 4462306a36Sopenharmony_ci u8 is_identical; 4562306a36Sopenharmony_ci struct acpi_table_header *table; 4662306a36Sopenharmony_ci u32 table_length; 4762306a36Sopenharmony_ci u8 table_flags; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci status = 5062306a36Sopenharmony_ci acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index], 5162306a36Sopenharmony_ci &table, &table_length, &table_flags); 5262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 5362306a36Sopenharmony_ci return (FALSE); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * Check for a table match on the entire table length, 5862306a36Sopenharmony_ci * not just the header. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci is_identical = (u8)((table_desc->length != table_length || 6162306a36Sopenharmony_ci memcmp(table_desc->pointer, table, table_length)) ? 6262306a36Sopenharmony_ci FALSE : TRUE); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* Release the acquired table */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci acpi_tb_release_table(table, table_length, table_flags); 6762306a36Sopenharmony_ci return (is_identical); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/******************************************************************************* 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * FUNCTION: acpi_tb_init_table_descriptor 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 7562306a36Sopenharmony_ci * address - Physical address of the table 7662306a36Sopenharmony_ci * flags - Allocation flags of the table 7762306a36Sopenharmony_ci * table - Pointer to the table 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * RETURN: None 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * DESCRIPTION: Initialize a new table descriptor 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci ******************************************************************************/ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_civoid 8662306a36Sopenharmony_ciacpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, 8762306a36Sopenharmony_ci acpi_physical_address address, 8862306a36Sopenharmony_ci u8 flags, struct acpi_table_header *table) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * Initialize the table descriptor. Set the pointer to NULL for external 9362306a36Sopenharmony_ci * tables, since the table is not fully mapped at this time. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci memset(table_desc, 0, sizeof(struct acpi_table_desc)); 9662306a36Sopenharmony_ci table_desc->address = address; 9762306a36Sopenharmony_ci table_desc->length = table->length; 9862306a36Sopenharmony_ci table_desc->flags = flags; 9962306a36Sopenharmony_ci ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { 10262306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 10362306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci table_desc->pointer = table; 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 10962306a36Sopenharmony_ci default: 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/******************************************************************************* 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * FUNCTION: acpi_tb_acquire_table 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 12062306a36Sopenharmony_ci * table_ptr - Where table is returned 12162306a36Sopenharmony_ci * table_length - Where table length is returned 12262306a36Sopenharmony_ci * table_flags - Where table allocation flags are returned 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * RETURN: Status 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * DESCRIPTION: Acquire an ACPI table. It can be used for tables not 12762306a36Sopenharmony_ci * maintained in the acpi_gbl_root_table_list. 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci ******************************************************************************/ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciacpi_status 13262306a36Sopenharmony_ciacpi_tb_acquire_table(struct acpi_table_desc *table_desc, 13362306a36Sopenharmony_ci struct acpi_table_header **table_ptr, 13462306a36Sopenharmony_ci u32 *table_length, u8 *table_flags) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct acpi_table_header *table = NULL; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { 13962306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci table = 14262306a36Sopenharmony_ci acpi_os_map_memory(table_desc->address, table_desc->length); 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 14662306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci table = table_desc->pointer; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci default: 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Table is not valid yet */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!table) { 15962306a36Sopenharmony_ci return (AE_NO_MEMORY); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Fill the return values */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci *table_ptr = table; 16562306a36Sopenharmony_ci *table_length = table_desc->length; 16662306a36Sopenharmony_ci *table_flags = table_desc->flags; 16762306a36Sopenharmony_ci return (AE_OK); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/******************************************************************************* 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * FUNCTION: acpi_tb_release_table 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * PARAMETERS: table - Pointer for the table 17562306a36Sopenharmony_ci * table_length - Length for the table 17662306a36Sopenharmony_ci * table_flags - Allocation flags for the table 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * RETURN: None 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table(). 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci ******************************************************************************/ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_civoid 18562306a36Sopenharmony_ciacpi_tb_release_table(struct acpi_table_header *table, 18662306a36Sopenharmony_ci u32 table_length, u8 table_flags) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { 19062306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci acpi_os_unmap_memory(table, table_length); 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 19662306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/******************************************************************************* 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * FUNCTION: acpi_tb_acquire_temp_table 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor to be acquired 20862306a36Sopenharmony_ci * address - Address of the table 20962306a36Sopenharmony_ci * flags - Allocation flags of the table 21062306a36Sopenharmony_ci * table - Pointer to the table (required for virtual 21162306a36Sopenharmony_ci * origins, optional for physical) 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * RETURN: Status 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * DESCRIPTION: This function validates the table header to obtain the length 21662306a36Sopenharmony_ci * of a table and fills the table descriptor to make its state as 21762306a36Sopenharmony_ci * "INSTALLED". Such a table descriptor is only used for verified 21862306a36Sopenharmony_ci * installation. 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci ******************************************************************************/ 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciacpi_status 22362306a36Sopenharmony_ciacpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, 22462306a36Sopenharmony_ci acpi_physical_address address, 22562306a36Sopenharmony_ci u8 flags, struct acpi_table_header *table) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci u8 mapped_table = FALSE; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci switch (flags & ACPI_TABLE_ORIGIN_MASK) { 23062306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Get the length of the full table from the header */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!table) { 23562306a36Sopenharmony_ci table = 23662306a36Sopenharmony_ci acpi_os_map_memory(address, 23762306a36Sopenharmony_ci sizeof(struct 23862306a36Sopenharmony_ci acpi_table_header)); 23962306a36Sopenharmony_ci if (!table) { 24062306a36Sopenharmony_ci return (AE_NO_MEMORY); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci mapped_table = TRUE; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 24962306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!table) { 25262306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Table is not valid yet */ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return (AE_NO_MEMORY); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci acpi_tb_init_table_descriptor(table_desc, address, flags, table); 26562306a36Sopenharmony_ci if (mapped_table) { 26662306a36Sopenharmony_ci acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return (AE_OK); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/******************************************************************************* 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * FUNCTION: acpi_tb_release_temp_table 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor to be released 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * RETURN: Status 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table(). 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci *****************************************************************************/ 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_civoid acpi_tb_release_temp_table(struct acpi_table_desc *table_desc) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* 28862306a36Sopenharmony_ci * Note that the .Address is maintained by the callers of 28962306a36Sopenharmony_ci * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table() 29062306a36Sopenharmony_ci * where .Address will be freed. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci acpi_tb_invalidate_table(table_desc); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/****************************************************************************** 29662306a36Sopenharmony_ci * 29762306a36Sopenharmony_ci * FUNCTION: acpi_tb_validate_table 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * RETURN: Status 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * DESCRIPTION: This function is called to validate the table, the returned 30462306a36Sopenharmony_ci * table descriptor is in "VALIDATED" state. 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci *****************************************************************************/ 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciacpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci acpi_status status = AE_OK; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_validate_table); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Validate the table if necessary */ 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!table_desc->pointer) { 31762306a36Sopenharmony_ci status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, 31862306a36Sopenharmony_ci &table_desc->length, 31962306a36Sopenharmony_ci &table_desc->flags); 32062306a36Sopenharmony_ci if (!table_desc->pointer) { 32162306a36Sopenharmony_ci status = AE_NO_MEMORY; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return_ACPI_STATUS(status); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/******************************************************************************* 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * FUNCTION: acpi_tb_invalidate_table 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 33362306a36Sopenharmony_ci * 33462306a36Sopenharmony_ci * RETURN: None 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of 33762306a36Sopenharmony_ci * acpi_tb_validate_table(). 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci ******************************************************************************/ 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_civoid acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_invalidate_table); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Table must be validated */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (!table_desc->pointer) { 34962306a36Sopenharmony_ci return_VOID; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci acpi_tb_release_table(table_desc->pointer, table_desc->length, 35362306a36Sopenharmony_ci table_desc->flags); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { 35662306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci table_desc->pointer = NULL; 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 36262306a36Sopenharmony_ci case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 36362306a36Sopenharmony_ci default: 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return_VOID; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/****************************************************************************** 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * FUNCTION: acpi_tb_validate_temp_table 37462306a36Sopenharmony_ci * 37562306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * RETURN: Status 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * DESCRIPTION: This function is called to validate the table, the returned 38062306a36Sopenharmony_ci * table descriptor is in "VALIDATED" state. 38162306a36Sopenharmony_ci * 38262306a36Sopenharmony_ci *****************************************************************************/ 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ciacpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (!table_desc->pointer && !acpi_gbl_enable_table_validation) { 38862306a36Sopenharmony_ci /* 38962306a36Sopenharmony_ci * Only validates the header of the table. 39062306a36Sopenharmony_ci * Note that Length contains the size of the mapping after invoking 39162306a36Sopenharmony_ci * this work around, this value is required by 39262306a36Sopenharmony_ci * acpi_tb_release_temp_table(). 39362306a36Sopenharmony_ci * We can do this because in acpi_init_table_descriptor(), the Length 39462306a36Sopenharmony_ci * field of the installed descriptor is filled with the actual 39562306a36Sopenharmony_ci * table length obtaining from the table header. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci table_desc->length = sizeof(struct acpi_table_header); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return (acpi_tb_validate_table(table_desc)); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/******************************************************************************* 40462306a36Sopenharmony_ci * 40562306a36Sopenharmony_ci * FUNCTION: acpi_tb_check_duplication 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 40862306a36Sopenharmony_ci * table_index - Where the table index is returned 40962306a36Sopenharmony_ci * 41062306a36Sopenharmony_ci * RETURN: Status 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * DESCRIPTION: Avoid installing duplicated tables. However table override and 41362306a36Sopenharmony_ci * user aided dynamic table load is allowed, thus comparing the 41462306a36Sopenharmony_ci * address of the table is not sufficient, and checking the entire 41562306a36Sopenharmony_ci * table content is required. 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci ******************************************************************************/ 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic acpi_status 42062306a36Sopenharmony_ciacpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci u32 i; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_check_duplication); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Check if table is already registered */ 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Do not compare with unverified tables */ 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (! 43362306a36Sopenharmony_ci (acpi_gbl_root_table_list.tables[i]. 43462306a36Sopenharmony_ci flags & ACPI_TABLE_IS_VERIFIED)) { 43562306a36Sopenharmony_ci continue; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * Check for a table match on the entire table length, 44062306a36Sopenharmony_ci * not just the header. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (!acpi_tb_compare_tables(table_desc, i)) { 44362306a36Sopenharmony_ci continue; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* 44762306a36Sopenharmony_ci * Note: the current mechanism does not unregister a table if it is 44862306a36Sopenharmony_ci * dynamically unloaded. The related namespace entries are deleted, 44962306a36Sopenharmony_ci * but the table remains in the root table list. 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * The assumption here is that the number of different tables that 45262306a36Sopenharmony_ci * will be loaded is actually small, and there is minimal overhead 45362306a36Sopenharmony_ci * in just keeping the table in case it is needed again. 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * If this assumption changes in the future (perhaps on large 45662306a36Sopenharmony_ci * machines with many table load/unload operations), tables will 45762306a36Sopenharmony_ci * need to be unregistered when they are unloaded, and slots in the 45862306a36Sopenharmony_ci * root table list should be reused when empty. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci if (acpi_gbl_root_table_list.tables[i].flags & 46162306a36Sopenharmony_ci ACPI_TABLE_IS_LOADED) { 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Table is still loaded, this is an error */ 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return_ACPI_STATUS(AE_ALREADY_EXISTS); 46662306a36Sopenharmony_ci } else { 46762306a36Sopenharmony_ci *table_index = i; 46862306a36Sopenharmony_ci return_ACPI_STATUS(AE_CTRL_TERMINATE); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* Indicate no duplication to the caller */ 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/****************************************************************************** 47862306a36Sopenharmony_ci * 47962306a36Sopenharmony_ci * FUNCTION: acpi_tb_verify_temp_table 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 48262306a36Sopenharmony_ci * signature - Table signature to verify 48362306a36Sopenharmony_ci * table_index - Where the table index is returned 48462306a36Sopenharmony_ci * 48562306a36Sopenharmony_ci * RETURN: Status 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * DESCRIPTION: This function is called to validate and verify the table, the 48862306a36Sopenharmony_ci * returned table descriptor is in "VALIDATED" state. 48962306a36Sopenharmony_ci * Note that 'TableIndex' is required to be set to !NULL to 49062306a36Sopenharmony_ci * enable duplication check. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci *****************************************************************************/ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciacpi_status 49562306a36Sopenharmony_ciacpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, 49662306a36Sopenharmony_ci char *signature, u32 *table_index) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci acpi_status status = AE_OK; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_verify_temp_table); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Validate the table */ 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci status = acpi_tb_validate_temp_table(table_desc); 50562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 50662306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* If a particular signature is expected (DSDT/FACS), it must match */ 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (signature && 51262306a36Sopenharmony_ci !ACPI_COMPARE_NAMESEG(&table_desc->signature, signature)) { 51362306a36Sopenharmony_ci ACPI_BIOS_ERROR((AE_INFO, 51462306a36Sopenharmony_ci "Invalid signature 0x%X for ACPI table, expected [%s]", 51562306a36Sopenharmony_ci table_desc->signature.integer, signature)); 51662306a36Sopenharmony_ci status = AE_BAD_SIGNATURE; 51762306a36Sopenharmony_ci goto invalidate_and_exit; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (acpi_gbl_enable_table_validation) { 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Verify the checksum */ 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci status = 52562306a36Sopenharmony_ci acpi_ut_verify_checksum(table_desc->pointer, 52662306a36Sopenharmony_ci table_desc->length); 52762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 52862306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, 52962306a36Sopenharmony_ci "%4.4s 0x%8.8X%8.8X" 53062306a36Sopenharmony_ci " Attempted table install failed", 53162306a36Sopenharmony_ci acpi_ut_valid_nameseg(table_desc-> 53262306a36Sopenharmony_ci signature. 53362306a36Sopenharmony_ci ascii) ? 53462306a36Sopenharmony_ci table_desc->signature.ascii : "????", 53562306a36Sopenharmony_ci ACPI_FORMAT_UINT64(table_desc-> 53662306a36Sopenharmony_ci address))); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci goto invalidate_and_exit; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Avoid duplications */ 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (table_index) { 54462306a36Sopenharmony_ci status = 54562306a36Sopenharmony_ci acpi_tb_check_duplication(table_desc, table_index); 54662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 54762306a36Sopenharmony_ci if (status != AE_CTRL_TERMINATE) { 54862306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 54962306a36Sopenharmony_ci "%4.4s 0x%8.8X%8.8X" 55062306a36Sopenharmony_ci " Table is already loaded", 55162306a36Sopenharmony_ci acpi_ut_valid_nameseg 55262306a36Sopenharmony_ci (table_desc->signature. 55362306a36Sopenharmony_ci ascii) ? table_desc-> 55462306a36Sopenharmony_ci signature. 55562306a36Sopenharmony_ci ascii : "????", 55662306a36Sopenharmony_ci ACPI_FORMAT_UINT64 55762306a36Sopenharmony_ci (table_desc->address))); 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci goto invalidate_and_exit; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci table_desc->flags |= ACPI_TABLE_IS_VERIFIED; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return_ACPI_STATUS(status); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ciinvalidate_and_exit: 57062306a36Sopenharmony_ci acpi_tb_invalidate_table(table_desc); 57162306a36Sopenharmony_ci return_ACPI_STATUS(status); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/******************************************************************************* 57562306a36Sopenharmony_ci * 57662306a36Sopenharmony_ci * FUNCTION: acpi_tb_resize_root_table_list 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * PARAMETERS: None 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * RETURN: Status 58162306a36Sopenharmony_ci * 58262306a36Sopenharmony_ci * DESCRIPTION: Expand the size of global table array 58362306a36Sopenharmony_ci * 58462306a36Sopenharmony_ci ******************************************************************************/ 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ciacpi_status acpi_tb_resize_root_table_list(void) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct acpi_table_desc *tables; 58962306a36Sopenharmony_ci u32 table_count; 59062306a36Sopenharmony_ci u32 current_table_count, max_table_count; 59162306a36Sopenharmony_ci u32 i; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_resize_root_table_list); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* allow_resize flag is a parameter to acpi_initialize_tables */ 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { 59862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 59962306a36Sopenharmony_ci "Resize of Root Table Array is not allowed")); 60062306a36Sopenharmony_ci return_ACPI_STATUS(AE_SUPPORT); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Increase the Table Array size */ 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { 60662306a36Sopenharmony_ci table_count = acpi_gbl_root_table_list.max_table_count; 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci table_count = acpi_gbl_root_table_list.current_table_count; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci max_table_count = table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; 61262306a36Sopenharmony_ci tables = ACPI_ALLOCATE_ZEROED(((acpi_size)max_table_count) * 61362306a36Sopenharmony_ci sizeof(struct acpi_table_desc)); 61462306a36Sopenharmony_ci if (!tables) { 61562306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 61662306a36Sopenharmony_ci "Could not allocate new root table array")); 61762306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Copy and free the previous table array */ 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci current_table_count = 0; 62362306a36Sopenharmony_ci if (acpi_gbl_root_table_list.tables) { 62462306a36Sopenharmony_ci for (i = 0; i < table_count; i++) { 62562306a36Sopenharmony_ci if (acpi_gbl_root_table_list.tables[i].address) { 62662306a36Sopenharmony_ci memcpy(tables + current_table_count, 62762306a36Sopenharmony_ci acpi_gbl_root_table_list.tables + i, 62862306a36Sopenharmony_ci sizeof(struct acpi_table_desc)); 62962306a36Sopenharmony_ci current_table_count++; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { 63462306a36Sopenharmony_ci ACPI_FREE(acpi_gbl_root_table_list.tables); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci acpi_gbl_root_table_list.tables = tables; 63962306a36Sopenharmony_ci acpi_gbl_root_table_list.max_table_count = max_table_count; 64062306a36Sopenharmony_ci acpi_gbl_root_table_list.current_table_count = current_table_count; 64162306a36Sopenharmony_ci acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/******************************************************************************* 64762306a36Sopenharmony_ci * 64862306a36Sopenharmony_ci * FUNCTION: acpi_tb_get_next_table_descriptor 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * PARAMETERS: table_index - Where table index is returned 65162306a36Sopenharmony_ci * table_desc - Where table descriptor is returned 65262306a36Sopenharmony_ci * 65362306a36Sopenharmony_ci * RETURN: Status and table index/descriptor. 65462306a36Sopenharmony_ci * 65562306a36Sopenharmony_ci * DESCRIPTION: Allocate a new ACPI table entry to the global table list 65662306a36Sopenharmony_ci * 65762306a36Sopenharmony_ci ******************************************************************************/ 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ciacpi_status 66062306a36Sopenharmony_ciacpi_tb_get_next_table_descriptor(u32 *table_index, 66162306a36Sopenharmony_ci struct acpi_table_desc **table_desc) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci acpi_status status; 66462306a36Sopenharmony_ci u32 i; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* Ensure that there is room for the table in the Root Table List */ 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (acpi_gbl_root_table_list.current_table_count >= 66962306a36Sopenharmony_ci acpi_gbl_root_table_list.max_table_count) { 67062306a36Sopenharmony_ci status = acpi_tb_resize_root_table_list(); 67162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 67262306a36Sopenharmony_ci return (status); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci i = acpi_gbl_root_table_list.current_table_count; 67762306a36Sopenharmony_ci acpi_gbl_root_table_list.current_table_count++; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (table_index) { 68062306a36Sopenharmony_ci *table_index = i; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci if (table_desc) { 68362306a36Sopenharmony_ci *table_desc = &acpi_gbl_root_table_list.tables[i]; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return (AE_OK); 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/******************************************************************************* 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * FUNCTION: acpi_tb_terminate 69262306a36Sopenharmony_ci * 69362306a36Sopenharmony_ci * PARAMETERS: None 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * RETURN: None 69662306a36Sopenharmony_ci * 69762306a36Sopenharmony_ci * DESCRIPTION: Delete all internal ACPI tables 69862306a36Sopenharmony_ci * 69962306a36Sopenharmony_ci ******************************************************************************/ 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_civoid acpi_tb_terminate(void) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci u32 i; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_terminate); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* Delete the individual tables */ 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { 71262306a36Sopenharmony_ci acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* 71662306a36Sopenharmony_ci * Delete the root table array if allocated locally. Array cannot be 71762306a36Sopenharmony_ci * mapped, so we don't need to check for that flag. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { 72062306a36Sopenharmony_ci ACPI_FREE(acpi_gbl_root_table_list.tables); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci acpi_gbl_root_table_list.tables = NULL; 72462306a36Sopenharmony_ci acpi_gbl_root_table_list.flags = 0; 72562306a36Sopenharmony_ci acpi_gbl_root_table_list.current_table_count = 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 73062306a36Sopenharmony_ci return_VOID; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci/******************************************************************************* 73462306a36Sopenharmony_ci * 73562306a36Sopenharmony_ci * FUNCTION: acpi_tb_delete_namespace_by_owner 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 73862306a36Sopenharmony_ci * 73962306a36Sopenharmony_ci * RETURN: Status 74062306a36Sopenharmony_ci * 74162306a36Sopenharmony_ci * DESCRIPTION: Delete all namespace objects created when this table was loaded. 74262306a36Sopenharmony_ci * 74362306a36Sopenharmony_ci ******************************************************************************/ 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ciacpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci acpi_owner_id owner_id; 74862306a36Sopenharmony_ci acpi_status status; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 75362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 75462306a36Sopenharmony_ci return_ACPI_STATUS(status); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (table_index >= acpi_gbl_root_table_list.current_table_count) { 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* The table index does not exist */ 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 76262306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Get the owner ID for this table, used to delete namespace nodes */ 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; 76862306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* 77162306a36Sopenharmony_ci * Need to acquire the namespace writer lock to prevent interference 77262306a36Sopenharmony_ci * with any concurrent namespace walks. The interpreter must be 77362306a36Sopenharmony_ci * released during the deletion since the acquisition of the deletion 77462306a36Sopenharmony_ci * lock may block, and also since the execution of a namespace walk 77562306a36Sopenharmony_ci * must be allowed to use the interpreter. 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_ci status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); 77862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 77962306a36Sopenharmony_ci return_ACPI_STATUS(status); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci acpi_ns_delete_namespace_by_owner(owner_id); 78362306a36Sopenharmony_ci acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); 78462306a36Sopenharmony_ci return_ACPI_STATUS(status); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci/******************************************************************************* 78862306a36Sopenharmony_ci * 78962306a36Sopenharmony_ci * FUNCTION: acpi_tb_allocate_owner_id 79062306a36Sopenharmony_ci * 79162306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 79262306a36Sopenharmony_ci * 79362306a36Sopenharmony_ci * RETURN: Status 79462306a36Sopenharmony_ci * 79562306a36Sopenharmony_ci * DESCRIPTION: Allocates owner_id in table_desc 79662306a36Sopenharmony_ci * 79762306a36Sopenharmony_ci ******************************************************************************/ 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ciacpi_status acpi_tb_allocate_owner_id(u32 table_index) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci acpi_status status = AE_BAD_PARAMETER; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_allocate_owner_id); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 80662306a36Sopenharmony_ci if (table_index < acpi_gbl_root_table_list.current_table_count) { 80762306a36Sopenharmony_ci status = 80862306a36Sopenharmony_ci acpi_ut_allocate_owner_id(& 80962306a36Sopenharmony_ci (acpi_gbl_root_table_list. 81062306a36Sopenharmony_ci tables[table_index].owner_id)); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 81462306a36Sopenharmony_ci return_ACPI_STATUS(status); 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/******************************************************************************* 81862306a36Sopenharmony_ci * 81962306a36Sopenharmony_ci * FUNCTION: acpi_tb_release_owner_id 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 82262306a36Sopenharmony_ci * 82362306a36Sopenharmony_ci * RETURN: Status 82462306a36Sopenharmony_ci * 82562306a36Sopenharmony_ci * DESCRIPTION: Releases owner_id in table_desc 82662306a36Sopenharmony_ci * 82762306a36Sopenharmony_ci ******************************************************************************/ 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciacpi_status acpi_tb_release_owner_id(u32 table_index) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci acpi_status status = AE_BAD_PARAMETER; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_release_owner_id); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 83662306a36Sopenharmony_ci if (table_index < acpi_gbl_root_table_list.current_table_count) { 83762306a36Sopenharmony_ci acpi_ut_release_owner_id(& 83862306a36Sopenharmony_ci (acpi_gbl_root_table_list. 83962306a36Sopenharmony_ci tables[table_index].owner_id)); 84062306a36Sopenharmony_ci status = AE_OK; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 84462306a36Sopenharmony_ci return_ACPI_STATUS(status); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/******************************************************************************* 84862306a36Sopenharmony_ci * 84962306a36Sopenharmony_ci * FUNCTION: acpi_tb_get_owner_id 85062306a36Sopenharmony_ci * 85162306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 85262306a36Sopenharmony_ci * owner_id - Where the table owner_id is returned 85362306a36Sopenharmony_ci * 85462306a36Sopenharmony_ci * RETURN: Status 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * DESCRIPTION: returns owner_id for the ACPI table 85762306a36Sopenharmony_ci * 85862306a36Sopenharmony_ci ******************************************************************************/ 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ciacpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci acpi_status status = AE_BAD_PARAMETER; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_get_owner_id); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 86762306a36Sopenharmony_ci if (table_index < acpi_gbl_root_table_list.current_table_count) { 86862306a36Sopenharmony_ci *owner_id = 86962306a36Sopenharmony_ci acpi_gbl_root_table_list.tables[table_index].owner_id; 87062306a36Sopenharmony_ci status = AE_OK; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 87462306a36Sopenharmony_ci return_ACPI_STATUS(status); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/******************************************************************************* 87862306a36Sopenharmony_ci * 87962306a36Sopenharmony_ci * FUNCTION: acpi_tb_is_table_loaded 88062306a36Sopenharmony_ci * 88162306a36Sopenharmony_ci * PARAMETERS: table_index - Index into the root table 88262306a36Sopenharmony_ci * 88362306a36Sopenharmony_ci * RETURN: Table Loaded Flag 88462306a36Sopenharmony_ci * 88562306a36Sopenharmony_ci ******************************************************************************/ 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciu8 acpi_tb_is_table_loaded(u32 table_index) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci u8 is_loaded = FALSE; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 89262306a36Sopenharmony_ci if (table_index < acpi_gbl_root_table_list.current_table_count) { 89362306a36Sopenharmony_ci is_loaded = (u8) 89462306a36Sopenharmony_ci (acpi_gbl_root_table_list.tables[table_index].flags & 89562306a36Sopenharmony_ci ACPI_TABLE_IS_LOADED); 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 89962306a36Sopenharmony_ci return (is_loaded); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci/******************************************************************************* 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * FUNCTION: acpi_tb_set_table_loaded_flag 90562306a36Sopenharmony_ci * 90662306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 90762306a36Sopenharmony_ci * is_loaded - TRUE if table is loaded, FALSE otherwise 90862306a36Sopenharmony_ci * 90962306a36Sopenharmony_ci * RETURN: None 91062306a36Sopenharmony_ci * 91162306a36Sopenharmony_ci * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. 91262306a36Sopenharmony_ci * 91362306a36Sopenharmony_ci ******************************************************************************/ 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_civoid acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 91962306a36Sopenharmony_ci if (table_index < acpi_gbl_root_table_list.current_table_count) { 92062306a36Sopenharmony_ci if (is_loaded) { 92162306a36Sopenharmony_ci acpi_gbl_root_table_list.tables[table_index].flags |= 92262306a36Sopenharmony_ci ACPI_TABLE_IS_LOADED; 92362306a36Sopenharmony_ci } else { 92462306a36Sopenharmony_ci acpi_gbl_root_table_list.tables[table_index].flags &= 92562306a36Sopenharmony_ci ~ACPI_TABLE_IS_LOADED; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci/******************************************************************************* 93362306a36Sopenharmony_ci * 93462306a36Sopenharmony_ci * FUNCTION: acpi_tb_load_table 93562306a36Sopenharmony_ci * 93662306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 93762306a36Sopenharmony_ci * parent_node - Where table index is returned 93862306a36Sopenharmony_ci * 93962306a36Sopenharmony_ci * RETURN: Status 94062306a36Sopenharmony_ci * 94162306a36Sopenharmony_ci * DESCRIPTION: Load an ACPI table 94262306a36Sopenharmony_ci * 94362306a36Sopenharmony_ci ******************************************************************************/ 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ciacpi_status 94662306a36Sopenharmony_ciacpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci struct acpi_table_header *table; 94962306a36Sopenharmony_ci acpi_status status; 95062306a36Sopenharmony_ci acpi_owner_id owner_id; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_load_table); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * Note: Now table is "INSTALLED", it must be validated before 95662306a36Sopenharmony_ci * using. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci status = acpi_get_table_by_index(table_index, &table); 95962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 96062306a36Sopenharmony_ci return_ACPI_STATUS(status); 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci status = acpi_ns_load_table(table_index, parent_node); 96462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 96562306a36Sopenharmony_ci return_ACPI_STATUS(status); 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is 97062306a36Sopenharmony_ci * responsible for discovering any new wake GPEs by running _PRW methods 97162306a36Sopenharmony_ci * that may have been loaded by this table. 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ci status = acpi_tb_get_owner_id(table_index, &owner_id); 97462306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 97562306a36Sopenharmony_ci acpi_ev_update_gpes(owner_id); 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* Invoke table handler */ 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci acpi_tb_notify_table(ACPI_TABLE_EVENT_LOAD, table); 98162306a36Sopenharmony_ci return_ACPI_STATUS(status); 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci/******************************************************************************* 98562306a36Sopenharmony_ci * 98662306a36Sopenharmony_ci * FUNCTION: acpi_tb_install_and_load_table 98762306a36Sopenharmony_ci * 98862306a36Sopenharmony_ci * PARAMETERS: address - Physical address of the table 98962306a36Sopenharmony_ci * flags - Allocation flags of the table 99062306a36Sopenharmony_ci * table - Pointer to the table (required for 99162306a36Sopenharmony_ci * virtual origins, optional for 99262306a36Sopenharmony_ci * physical) 99362306a36Sopenharmony_ci * override - Whether override should be performed 99462306a36Sopenharmony_ci * table_index - Where table index is returned 99562306a36Sopenharmony_ci * 99662306a36Sopenharmony_ci * RETURN: Status 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * DESCRIPTION: Install and load an ACPI table 99962306a36Sopenharmony_ci * 100062306a36Sopenharmony_ci ******************************************************************************/ 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ciacpi_status 100362306a36Sopenharmony_ciacpi_tb_install_and_load_table(acpi_physical_address address, 100462306a36Sopenharmony_ci u8 flags, 100562306a36Sopenharmony_ci struct acpi_table_header *table, 100662306a36Sopenharmony_ci u8 override, u32 *table_index) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci acpi_status status; 100962306a36Sopenharmony_ci u32 i; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_install_and_load_table); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* Install the table and load it into the namespace */ 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci status = acpi_tb_install_standard_table(address, flags, table, TRUE, 101662306a36Sopenharmony_ci override, &i); 101762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 101862306a36Sopenharmony_ci goto exit; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci status = acpi_tb_load_table(i, acpi_gbl_root_node); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ciexit: 102462306a36Sopenharmony_ci *table_index = i; 102562306a36Sopenharmony_ci return_ACPI_STATUS(status); 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_tb_install_and_load_table) 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci/******************************************************************************* 103162306a36Sopenharmony_ci * 103262306a36Sopenharmony_ci * FUNCTION: acpi_tb_unload_table 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * PARAMETERS: table_index - Table index 103562306a36Sopenharmony_ci * 103662306a36Sopenharmony_ci * RETURN: Status 103762306a36Sopenharmony_ci * 103862306a36Sopenharmony_ci * DESCRIPTION: Unload an ACPI table 103962306a36Sopenharmony_ci * 104062306a36Sopenharmony_ci ******************************************************************************/ 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ciacpi_status acpi_tb_unload_table(u32 table_index) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci acpi_status status = AE_OK; 104562306a36Sopenharmony_ci struct acpi_table_header *table; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_unload_table); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* Ensure the table is still loaded */ 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (!acpi_tb_is_table_loaded(table_index)) { 105262306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Invoke table handler */ 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci status = acpi_get_table_by_index(table_index, &table); 105862306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 105962306a36Sopenharmony_ci acpi_tb_notify_table(ACPI_TABLE_EVENT_UNLOAD, table); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* Delete the portion of the namespace owned by this table */ 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci status = acpi_tb_delete_namespace_by_owner(table_index); 106562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 106662306a36Sopenharmony_ci return_ACPI_STATUS(status); 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci (void)acpi_tb_release_owner_id(table_index); 107062306a36Sopenharmony_ci acpi_tb_set_table_loaded_flag(table_index, FALSE); 107162306a36Sopenharmony_ci return_ACPI_STATUS(status); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_tb_unload_table) 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci/******************************************************************************* 107762306a36Sopenharmony_ci * 107862306a36Sopenharmony_ci * FUNCTION: acpi_tb_notify_table 107962306a36Sopenharmony_ci * 108062306a36Sopenharmony_ci * PARAMETERS: event - Table event 108162306a36Sopenharmony_ci * table - Validated table pointer 108262306a36Sopenharmony_ci * 108362306a36Sopenharmony_ci * RETURN: None 108462306a36Sopenharmony_ci * 108562306a36Sopenharmony_ci * DESCRIPTION: Notify a table event to the users. 108662306a36Sopenharmony_ci * 108762306a36Sopenharmony_ci ******************************************************************************/ 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_civoid acpi_tb_notify_table(u32 event, void *table) 109062306a36Sopenharmony_ci{ 109162306a36Sopenharmony_ci /* Invoke table handler if present */ 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (acpi_gbl_table_handler) { 109462306a36Sopenharmony_ci (void)acpi_gbl_table_handler(event, table, 109562306a36Sopenharmony_ci acpi_gbl_table_handler_context); 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci} 1098