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