162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: tbutils - ACPI Table utilities 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 "actables.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _COMPONENT ACPI_TABLES 1562306a36Sopenharmony_ciACPI_MODULE_NAME("tbutils") 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Local prototypes */ 1862306a36Sopenharmony_cistatic acpi_physical_address 1962306a36Sopenharmony_ciacpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE) 2262306a36Sopenharmony_ci/******************************************************************************* 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * FUNCTION: acpi_tb_initialize_facs 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * PARAMETERS: None 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * RETURN: Status 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global 3162306a36Sopenharmony_ci * for accessing the Global Lock and Firmware Waking Vector 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci ******************************************************************************/ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciacpi_status acpi_tb_initialize_facs(void) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct acpi_table_facs *facs; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* If Hardware Reduced flag is set, there is no FACS */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (acpi_gbl_reduced_hardware) { 4262306a36Sopenharmony_ci acpi_gbl_FACS = NULL; 4362306a36Sopenharmony_ci return (AE_OK); 4462306a36Sopenharmony_ci } else if (acpi_gbl_FADT.Xfacs && 4562306a36Sopenharmony_ci (!acpi_gbl_FADT.facs 4662306a36Sopenharmony_ci || !acpi_gbl_use32_bit_facs_addresses)) { 4762306a36Sopenharmony_ci (void)acpi_get_table_by_index(acpi_gbl_xfacs_index, 4862306a36Sopenharmony_ci ACPI_CAST_INDIRECT_PTR(struct 4962306a36Sopenharmony_ci acpi_table_header, 5062306a36Sopenharmony_ci &facs)); 5162306a36Sopenharmony_ci acpi_gbl_FACS = facs; 5262306a36Sopenharmony_ci } else if (acpi_gbl_FADT.facs) { 5362306a36Sopenharmony_ci (void)acpi_get_table_by_index(acpi_gbl_facs_index, 5462306a36Sopenharmony_ci ACPI_CAST_INDIRECT_PTR(struct 5562306a36Sopenharmony_ci acpi_table_header, 5662306a36Sopenharmony_ci &facs)); 5762306a36Sopenharmony_ci acpi_gbl_FACS = facs; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* If there is no FACS, just continue. There was already an error msg */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return (AE_OK); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci#endif /* !ACPI_REDUCED_HARDWARE */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/******************************************************************************* 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * FUNCTION: acpi_tb_check_dsdt_header 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * PARAMETERS: None 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * RETURN: None 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect 7562306a36Sopenharmony_ci * if the DSDT has been replaced from outside the OS and/or if 7662306a36Sopenharmony_ci * the DSDT header has been corrupted. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci ******************************************************************************/ 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid acpi_tb_check_dsdt_header(void) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Compare original length and checksum to current values */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length || 8662306a36Sopenharmony_ci acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) { 8762306a36Sopenharmony_ci ACPI_BIOS_ERROR((AE_INFO, 8862306a36Sopenharmony_ci "The DSDT has been corrupted or replaced - " 8962306a36Sopenharmony_ci "old, new headers below")); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header); 9262306a36Sopenharmony_ci acpi_tb_print_table_header(0, acpi_gbl_DSDT); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 9562306a36Sopenharmony_ci "Please send DMI info to linux-acpi@vger.kernel.org\n" 9662306a36Sopenharmony_ci "If system does not work as expected, please boot with acpi=copy_dsdt")); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Disable further error messages */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length; 10162306a36Sopenharmony_ci acpi_gbl_original_dsdt_header.checksum = 10262306a36Sopenharmony_ci acpi_gbl_DSDT->checksum; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/******************************************************************************* 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * FUNCTION: acpi_tb_copy_dsdt 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * PARAMETERS: table_index - Index of installed table to copy 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * RETURN: The copied DSDT 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. 11562306a36Sopenharmony_ci * Some very bad BIOSs are known to either corrupt the DSDT or 11662306a36Sopenharmony_ci * install a new, bad DSDT. This copy works around the problem. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci ******************************************************************************/ 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistruct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct acpi_table_header *new_table; 12362306a36Sopenharmony_ci struct acpi_table_desc *table_desc; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci table_desc = &acpi_gbl_root_table_list.tables[table_index]; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci new_table = ACPI_ALLOCATE(table_desc->length); 12862306a36Sopenharmony_ci if (!new_table) { 12962306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X", 13062306a36Sopenharmony_ci table_desc->length)); 13162306a36Sopenharmony_ci return (NULL); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci memcpy(new_table, table_desc->pointer, table_desc->length); 13562306a36Sopenharmony_ci acpi_tb_uninstall_table(table_desc); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. 13862306a36Sopenharmony_ci tables[acpi_gbl_dsdt_index], 13962306a36Sopenharmony_ci ACPI_PTR_TO_PHYSADDR(new_table), 14062306a36Sopenharmony_ci ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, 14162306a36Sopenharmony_ci new_table); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return (new_table); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/******************************************************************************* 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * FUNCTION: acpi_tb_get_root_table_entry 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry 15362306a36Sopenharmony_ci * table_entry_size - sizeof 32 or 64 (RSDT or XSDT) 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * RETURN: Physical address extracted from the root table 15662306a36Sopenharmony_ci * 15762306a36Sopenharmony_ci * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on 15862306a36Sopenharmony_ci * both 32-bit and 64-bit platforms 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on 16162306a36Sopenharmony_ci * 64-bit platforms. 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci ******************************************************************************/ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic acpi_physical_address 16662306a36Sopenharmony_ciacpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci u32 address32; 16962306a36Sopenharmony_ci u64 address64; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* 17262306a36Sopenharmony_ci * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): 17362306a36Sopenharmony_ci * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) { 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * 32-bit platform, RSDT: Return 32-bit table entry 17862306a36Sopenharmony_ci * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci ACPI_MOVE_32_TO_32(&address32, table_entry); 18162306a36Sopenharmony_ci return address32; 18262306a36Sopenharmony_ci } else { 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return 18562306a36Sopenharmony_ci * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, 18662306a36Sopenharmony_ci * return 64-bit 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci ACPI_MOVE_64_TO_64(&address64, table_entry); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci#if ACPI_MACHINE_WIDTH == 32 19162306a36Sopenharmony_ci if (address64 > ACPI_UINT32_MAX) { 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Will truncate 64-bit address to 32 bits, issue warning */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ACPI_BIOS_WARNING((AE_INFO, 19662306a36Sopenharmony_ci "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X)," 19762306a36Sopenharmony_ci " truncating", 19862306a36Sopenharmony_ci ACPI_FORMAT_UINT64(address64))); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci#endif 20162306a36Sopenharmony_ci return ((acpi_physical_address)(address64)); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/******************************************************************************* 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * FUNCTION: acpi_tb_parse_root_table 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * PARAMETERS: rsdp_address - Pointer to the RSDP 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * RETURN: Status 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * DESCRIPTION: This function is called to parse the Root System Description 21462306a36Sopenharmony_ci * Table (RSDT or XSDT) 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * NOTE: Tables are mapped (not copied) for efficiency. The FACS must 21762306a36Sopenharmony_ci * be mapped and cannot be copied because it contains the actual 21862306a36Sopenharmony_ci * memory location of the ACPI Global Lock. 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci ******************************************************************************/ 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciacpi_status ACPI_INIT_FUNCTION 22362306a36Sopenharmony_ciacpi_tb_parse_root_table(acpi_physical_address rsdp_address) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct acpi_table_rsdp *rsdp; 22662306a36Sopenharmony_ci u32 table_entry_size; 22762306a36Sopenharmony_ci u32 i; 22862306a36Sopenharmony_ci u32 table_count; 22962306a36Sopenharmony_ci struct acpi_table_header *table; 23062306a36Sopenharmony_ci acpi_physical_address address; 23162306a36Sopenharmony_ci u32 length; 23262306a36Sopenharmony_ci u8 *table_entry; 23362306a36Sopenharmony_ci acpi_status status; 23462306a36Sopenharmony_ci u32 table_index; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_parse_root_table); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Map the entire RSDP and extract the address of the RSDT or XSDT */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); 24162306a36Sopenharmony_ci if (!rsdp) { 24262306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci acpi_tb_print_table_header(rsdp_address, 24662306a36Sopenharmony_ci ACPI_CAST_PTR(struct acpi_table_header, 24762306a36Sopenharmony_ci rsdp)); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Use XSDT if present and not overridden. Otherwise, use RSDT */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if ((rsdp->revision > 1) && 25262306a36Sopenharmony_ci rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) { 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * RSDP contains an XSDT (64-bit physical addresses). We must use 25562306a36Sopenharmony_ci * the XSDT if the revision is > 1 and the XSDT pointer is present, 25662306a36Sopenharmony_ci * as per the ACPI specification. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci address = (acpi_physical_address)rsdp->xsdt_physical_address; 25962306a36Sopenharmony_ci table_entry_size = ACPI_XSDT_ENTRY_SIZE; 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci /* Root table is an RSDT (32-bit physical addresses) */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci address = (acpi_physical_address)rsdp->rsdt_physical_address; 26462306a36Sopenharmony_ci table_entry_size = ACPI_RSDT_ENTRY_SIZE; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * It is not possible to map more than one entry in some environments, 26962306a36Sopenharmony_ci * so unmap the RSDP here before mapping other tables 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Map the RSDT/XSDT table header to get the full table length */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); 27662306a36Sopenharmony_ci if (!table) { 27762306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci acpi_tb_print_table_header(address, table); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * Validate length of the table, and map entire table. 28462306a36Sopenharmony_ci * Minimum length table must contain at least one entry. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci length = table->length; 28762306a36Sopenharmony_ci acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (length < (sizeof(struct acpi_table_header) + table_entry_size)) { 29062306a36Sopenharmony_ci ACPI_BIOS_ERROR((AE_INFO, 29162306a36Sopenharmony_ci "Invalid table length 0x%X in RSDT/XSDT", 29262306a36Sopenharmony_ci length)); 29362306a36Sopenharmony_ci return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci table = acpi_os_map_memory(address, length); 29762306a36Sopenharmony_ci if (!table) { 29862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Validate the root table checksum */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci status = acpi_ut_verify_checksum(table, length); 30462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 30562306a36Sopenharmony_ci acpi_os_unmap_memory(table, length); 30662306a36Sopenharmony_ci return_ACPI_STATUS(status); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Get the number of entries and pointer to first entry */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci table_count = (u32)((table->length - sizeof(struct acpi_table_header)) / 31262306a36Sopenharmony_ci table_entry_size); 31362306a36Sopenharmony_ci table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Initialize the root table array from the RSDT/XSDT */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci for (i = 0; i < table_count; i++) { 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci address = 32262306a36Sopenharmony_ci acpi_tb_get_root_table_entry(table_entry, table_entry_size); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Skip NULL entries in RSDT/XSDT */ 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!address) { 32762306a36Sopenharmony_ci goto next_table; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci status = acpi_tb_install_standard_table(address, 33162306a36Sopenharmony_ci ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 33262306a36Sopenharmony_ci NULL, FALSE, TRUE, 33362306a36Sopenharmony_ci &table_index); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (ACPI_SUCCESS(status) && 33662306a36Sopenharmony_ci ACPI_COMPARE_NAMESEG(&acpi_gbl_root_table_list. 33762306a36Sopenharmony_ci tables[table_index].signature, 33862306a36Sopenharmony_ci ACPI_SIG_FADT)) { 33962306a36Sopenharmony_ci acpi_gbl_fadt_index = table_index; 34062306a36Sopenharmony_ci acpi_tb_parse_fadt(); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cinext_table: 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci table_entry += table_entry_size; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci acpi_os_unmap_memory(table, length); 34962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/******************************************************************************* 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci * FUNCTION: acpi_tb_get_table 35562306a36Sopenharmony_ci * 35662306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 35762306a36Sopenharmony_ci * out_table - Where the pointer to the table is returned 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * RETURN: Status and pointer to the requested table 36062306a36Sopenharmony_ci * 36162306a36Sopenharmony_ci * DESCRIPTION: Increase a reference to a table descriptor and return the 36262306a36Sopenharmony_ci * validated table pointer. 36362306a36Sopenharmony_ci * If the table descriptor is an entry of the root table list, 36462306a36Sopenharmony_ci * this API must be invoked with ACPI_MTX_TABLES acquired. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci ******************************************************************************/ 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ciacpi_status 36962306a36Sopenharmony_ciacpi_tb_get_table(struct acpi_table_desc *table_desc, 37062306a36Sopenharmony_ci struct acpi_table_header **out_table) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci acpi_status status; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(acpi_tb_get_table); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (table_desc->validation_count == 0) { 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Table need to be "VALIDATED" */ 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci status = acpi_tb_validate_table(table_desc); 38162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 38262306a36Sopenharmony_ci return_ACPI_STATUS(status); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) { 38762306a36Sopenharmony_ci table_desc->validation_count++; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * Detect validation_count overflows to ensure that the warning 39162306a36Sopenharmony_ci * message will only be printed once. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) { 39462306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, 39562306a36Sopenharmony_ci "Table %p, Validation count overflows\n", 39662306a36Sopenharmony_ci table_desc)); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci *out_table = table_desc->pointer; 40162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci/******************************************************************************* 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * FUNCTION: acpi_tb_put_table 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 40962306a36Sopenharmony_ci * 41062306a36Sopenharmony_ci * RETURN: None 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * DESCRIPTION: Decrease a reference to a table descriptor and release the 41362306a36Sopenharmony_ci * validated table pointer if no references. 41462306a36Sopenharmony_ci * If the table descriptor is an entry of the root table list, 41562306a36Sopenharmony_ci * this API must be invoked with ACPI_MTX_TABLES acquired. 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci ******************************************************************************/ 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_civoid acpi_tb_put_table(struct acpi_table_desc *table_desc) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(acpi_tb_put_table); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) { 42562306a36Sopenharmony_ci table_desc->validation_count--; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* 42862306a36Sopenharmony_ci * Detect validation_count underflows to ensure that the warning 42962306a36Sopenharmony_ci * message will only be printed once. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) { 43262306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, 43362306a36Sopenharmony_ci "Table %p, Validation count underflows\n", 43462306a36Sopenharmony_ci table_desc)); 43562306a36Sopenharmony_ci return_VOID; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (table_desc->validation_count == 0) { 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* Table need to be "INVALIDATED" */ 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci acpi_tb_invalidate_table(table_desc); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return_VOID; 44762306a36Sopenharmony_ci} 448