195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown *
442f47869SBob Moore * Module Name: tbutils - ACPI Table utilities
595b482a8SLen Brown *
6612c2932SBob Moore * Copyright (C) 2000 - 2023, Intel Corp.
795b482a8SLen Brown *
895857638SErik Schmauss *****************************************************************************/
995b482a8SLen Brown
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "actables.h"
1395b482a8SLen Brown
1495b482a8SLen Brown #define _COMPONENT ACPI_TABLES
1595b482a8SLen Brown ACPI_MODULE_NAME("tbutils")
1695b482a8SLen Brown
1795b482a8SLen Brown /* Local prototypes */
1895b482a8SLen Brown static acpi_physical_address
1995b482a8SLen Brown acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
2095b482a8SLen Brown
2133620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE)
2295b482a8SLen Brown /*******************************************************************************
2395b482a8SLen Brown *
2495b482a8SLen Brown * FUNCTION: acpi_tb_initialize_facs
2595b482a8SLen Brown *
2695b482a8SLen Brown * PARAMETERS: None
2795b482a8SLen Brown *
2895b482a8SLen Brown * RETURN: Status
2995b482a8SLen Brown *
3095b482a8SLen Brown * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
3195b482a8SLen Brown * for accessing the Global Lock and Firmware Waking Vector
3295b482a8SLen Brown *
3395b482a8SLen Brown ******************************************************************************/
3495b482a8SLen Brown
acpi_tb_initialize_facs(void)3595b482a8SLen Brown acpi_status acpi_tb_initialize_facs(void)
3695b482a8SLen Brown {
377484619bSLv Zheng struct acpi_table_facs *facs;
3895b482a8SLen Brown
3922e5b40aSBob Moore /* If Hardware Reduced flag is set, there is no FACS */
4022e5b40aSBob Moore
4122e5b40aSBob Moore if (acpi_gbl_reduced_hardware) {
4222e5b40aSBob Moore acpi_gbl_FACS = NULL;
4322e5b40aSBob Moore return (AE_OK);
448ec3f459SLv Zheng } else if (acpi_gbl_FADT.Xfacs &&
458ec3f459SLv Zheng (!acpi_gbl_FADT.facs
468ec3f459SLv Zheng || !acpi_gbl_use32_bit_facs_addresses)) {
478ec3f459SLv Zheng (void)acpi_get_table_by_index(acpi_gbl_xfacs_index,
4895b482a8SLen Brown ACPI_CAST_INDIRECT_PTR(struct
4995b482a8SLen Brown acpi_table_header,
507484619bSLv Zheng &facs));
517484619bSLv Zheng acpi_gbl_FACS = facs;
528ec3f459SLv Zheng } else if (acpi_gbl_FADT.facs) {
538ec3f459SLv Zheng (void)acpi_get_table_by_index(acpi_gbl_facs_index,
54c04e1fb4SLv Zheng ACPI_CAST_INDIRECT_PTR(struct
55c04e1fb4SLv Zheng acpi_table_header,
567484619bSLv Zheng &facs));
577484619bSLv Zheng acpi_gbl_FACS = facs;
58c04e1fb4SLv Zheng }
59c04e1fb4SLv Zheng
60f06147f9SLv Zheng /* If there is no FACS, just continue. There was already an error msg */
61f06147f9SLv Zheng
62c04e1fb4SLv Zheng return (AE_OK);
6395b482a8SLen Brown }
6433620c54SBob Moore #endif /* !ACPI_REDUCED_HARDWARE */
6595b482a8SLen Brown
6695b482a8SLen Brown /*******************************************************************************
6795b482a8SLen Brown *
68729df0f8SLin Ming * FUNCTION: acpi_tb_check_dsdt_header
69729df0f8SLin Ming *
70729df0f8SLin Ming * PARAMETERS: None
71729df0f8SLin Ming *
72729df0f8SLin Ming * RETURN: None
73729df0f8SLin Ming *
74729df0f8SLin Ming * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
75729df0f8SLin Ming * if the DSDT has been replaced from outside the OS and/or if
76729df0f8SLin Ming * the DSDT header has been corrupted.
77729df0f8SLin Ming *
78729df0f8SLin Ming ******************************************************************************/
79729df0f8SLin Ming
acpi_tb_check_dsdt_header(void)80729df0f8SLin Ming void acpi_tb_check_dsdt_header(void)
81729df0f8SLin Ming {
82729df0f8SLin Ming
83729df0f8SLin Ming /* Compare original length and checksum to current values */
84729df0f8SLin Ming
8543323cb4SBob Moore if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length ||
8643323cb4SBob Moore acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) {
873b3ea775SBob Moore ACPI_BIOS_ERROR((AE_INFO,
883b3ea775SBob Moore "The DSDT has been corrupted or replaced - "
893b3ea775SBob Moore "old, new headers below"));
901fad8738SBob Moore
91729df0f8SLin Ming acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header);
9243323cb4SBob Moore acpi_tb_print_table_header(0, acpi_gbl_DSDT);
93729df0f8SLin Ming
94aa2110cbSLin Ming ACPI_ERROR((AE_INFO,
95aa2110cbSLin Ming "Please send DMI info to linux-acpi@vger.kernel.org\n"
96aa2110cbSLin Ming "If system does not work as expected, please boot with acpi=copy_dsdt"));
97aa2110cbSLin Ming
98729df0f8SLin Ming /* Disable further error messages */
99729df0f8SLin Ming
10043323cb4SBob Moore acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length;
101729df0f8SLin Ming acpi_gbl_original_dsdt_header.checksum =
10243323cb4SBob Moore acpi_gbl_DSDT->checksum;
103729df0f8SLin Ming }
104729df0f8SLin Ming }
105729df0f8SLin Ming
106729df0f8SLin Ming /*******************************************************************************
107729df0f8SLin Ming *
10869ec87efSLin Ming * FUNCTION: acpi_tb_copy_dsdt
10969ec87efSLin Ming *
11032d8004fSCao Jin * PARAMETERS: table_index - Index of installed table to copy
11169ec87efSLin Ming *
11232d8004fSCao Jin * RETURN: The copied DSDT
11369ec87efSLin Ming *
11469ec87efSLin Ming * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory.
11569ec87efSLin Ming * Some very bad BIOSs are known to either corrupt the DSDT or
11669ec87efSLin Ming * install a new, bad DSDT. This copy works around the problem.
11769ec87efSLin Ming *
11869ec87efSLin Ming ******************************************************************************/
11969ec87efSLin Ming
acpi_tb_copy_dsdt(u32 table_index)12043323cb4SBob Moore struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
12169ec87efSLin Ming {
12269ec87efSLin Ming struct acpi_table_header *new_table;
12343323cb4SBob Moore struct acpi_table_desc *table_desc;
12443323cb4SBob Moore
12543323cb4SBob Moore table_desc = &acpi_gbl_root_table_list.tables[table_index];
12669ec87efSLin Ming
12769ec87efSLin Ming new_table = ACPI_ALLOCATE(table_desc->length);
12869ec87efSLin Ming if (!new_table) {
12969ec87efSLin Ming ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X",
13069ec87efSLin Ming table_desc->length));
13143323cb4SBob Moore return (NULL);
13269ec87efSLin Ming }
13369ec87efSLin Ming
1344fa4616eSBob Moore memcpy(new_table, table_desc->pointer, table_desc->length);
1357f9fc99cSLv Zheng acpi_tb_uninstall_table(table_desc);
136ed6f1d44SBob Moore
137ed6f1d44SBob Moore acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
1388ec3f459SLv Zheng tables[acpi_gbl_dsdt_index],
13986dfc6f3SLv Zheng ACPI_PTR_TO_PHYSADDR(new_table),
140ed6f1d44SBob Moore ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
141ed6f1d44SBob Moore new_table);
14269ec87efSLin Ming
14305fb04b5SBob Moore ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length));
14443323cb4SBob Moore
14543323cb4SBob Moore return (new_table);
14669ec87efSLin Ming }
14769ec87efSLin Ming
14869ec87efSLin Ming /*******************************************************************************
14969ec87efSLin Ming *
15095b482a8SLen Brown * FUNCTION: acpi_tb_get_root_table_entry
15195b482a8SLen Brown *
15295b482a8SLen Brown * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
15395b482a8SLen Brown * table_entry_size - sizeof 32 or 64 (RSDT or XSDT)
15495b482a8SLen Brown *
15595b482a8SLen Brown * RETURN: Physical address extracted from the root table
15695b482a8SLen Brown *
15795b482a8SLen Brown * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
15895b482a8SLen Brown * both 32-bit and 64-bit platforms
15995b482a8SLen Brown *
16095b482a8SLen Brown * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
16195b482a8SLen Brown * 64-bit platforms.
16295b482a8SLen Brown *
16395b482a8SLen Brown ******************************************************************************/
16495b482a8SLen Brown
16595b482a8SLen Brown static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,u32 table_entry_size)16695b482a8SLen Brown acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
16795b482a8SLen Brown {
168*d56ba92bSTamir Duberstein u32 address32;
16995b482a8SLen Brown u64 address64;
17095b482a8SLen Brown
17195b482a8SLen Brown /*
17295b482a8SLen Brown * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
17395b482a8SLen Brown * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
17495b482a8SLen Brown */
175671cc68dSLv Zheng if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
17695b482a8SLen Brown /*
17795b482a8SLen Brown * 32-bit platform, RSDT: Return 32-bit table entry
17895b482a8SLen Brown * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
17995b482a8SLen Brown */
180*d56ba92bSTamir Duberstein ACPI_MOVE_32_TO_32(&address32, table_entry);
181*d56ba92bSTamir Duberstein return address32;
18295b482a8SLen Brown } else {
18395b482a8SLen Brown /*
18495b482a8SLen Brown * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
185ec41f193SBob Moore * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
186ec41f193SBob Moore * return 64-bit
18795b482a8SLen Brown */
18895b482a8SLen Brown ACPI_MOVE_64_TO_64(&address64, table_entry);
18995b482a8SLen Brown
19095b482a8SLen Brown #if ACPI_MACHINE_WIDTH == 32
19195b482a8SLen Brown if (address64 > ACPI_UINT32_MAX) {
19295b482a8SLen Brown
19395b482a8SLen Brown /* Will truncate 64-bit address to 32 bits, issue warning */
19495b482a8SLen Brown
1953b3ea775SBob Moore ACPI_BIOS_WARNING((AE_INFO,
196f6a22b0bSBob Moore "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
197ec41f193SBob Moore " truncating",
19895b482a8SLen Brown ACPI_FORMAT_UINT64(address64)));
19995b482a8SLen Brown }
20095b482a8SLen Brown #endif
20195b482a8SLen Brown return ((acpi_physical_address)(address64));
20295b482a8SLen Brown }
20395b482a8SLen Brown }
20495b482a8SLen Brown
20595b482a8SLen Brown /*******************************************************************************
20695b482a8SLen Brown *
20795b482a8SLen Brown * FUNCTION: acpi_tb_parse_root_table
20895b482a8SLen Brown *
20932d8004fSCao Jin * PARAMETERS: rsdp_address - Pointer to the RSDP
21095b482a8SLen Brown *
21195b482a8SLen Brown * RETURN: Status
21295b482a8SLen Brown *
21395b482a8SLen Brown * DESCRIPTION: This function is called to parse the Root System Description
21495b482a8SLen Brown * Table (RSDT or XSDT)
21595b482a8SLen Brown *
21695b482a8SLen Brown * NOTE: Tables are mapped (not copied) for efficiency. The FACS must
21795b482a8SLen Brown * be mapped and cannot be copied because it contains the actual
21895b482a8SLen Brown * memory location of the ACPI Global Lock.
21995b482a8SLen Brown *
22095b482a8SLen Brown ******************************************************************************/
22195b482a8SLen Brown
2222368b1a1SLv Zheng acpi_status ACPI_INIT_FUNCTION
acpi_tb_parse_root_table(acpi_physical_address rsdp_address)2232368b1a1SLv Zheng acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
22495b482a8SLen Brown {
22595b482a8SLen Brown struct acpi_table_rsdp *rsdp;
22695b482a8SLen Brown u32 table_entry_size;
22795b482a8SLen Brown u32 i;
22895b482a8SLen Brown u32 table_count;
22995b482a8SLen Brown struct acpi_table_header *table;
23095b482a8SLen Brown acpi_physical_address address;
23195b482a8SLen Brown u32 length;
23295b482a8SLen Brown u8 *table_entry;
23395b482a8SLen Brown acpi_status status;
23486dfc6f3SLv Zheng u32 table_index;
23595b482a8SLen Brown
23695b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_parse_root_table);
23795b482a8SLen Brown
238671cc68dSLv Zheng /* Map the entire RSDP and extract the address of the RSDT or XSDT */
239671cc68dSLv Zheng
24095b482a8SLen Brown rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
24195b482a8SLen Brown if (!rsdp) {
24295b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY);
24395b482a8SLen Brown }
24495b482a8SLen Brown
24595b482a8SLen Brown acpi_tb_print_table_header(rsdp_address,
24695b482a8SLen Brown ACPI_CAST_PTR(struct acpi_table_header,
24795b482a8SLen Brown rsdp));
24895b482a8SLen Brown
249fab46105SLv Zheng /* Use XSDT if present and not overridden. Otherwise, use RSDT */
25095b482a8SLen Brown
251fab46105SLv Zheng if ((rsdp->revision > 1) &&
252fab46105SLv Zheng rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) {
25395b482a8SLen Brown /*
254671cc68dSLv Zheng * RSDP contains an XSDT (64-bit physical addresses). We must use
255671cc68dSLv Zheng * the XSDT if the revision is > 1 and the XSDT pointer is present,
256671cc68dSLv Zheng * as per the ACPI specification.
25795b482a8SLen Brown */
25895b482a8SLen Brown address = (acpi_physical_address)rsdp->xsdt_physical_address;
259671cc68dSLv Zheng table_entry_size = ACPI_XSDT_ENTRY_SIZE;
26095b482a8SLen Brown } else {
26195b482a8SLen Brown /* Root table is an RSDT (32-bit physical addresses) */
26295b482a8SLen Brown
26395b482a8SLen Brown address = (acpi_physical_address)rsdp->rsdt_physical_address;
264671cc68dSLv Zheng table_entry_size = ACPI_RSDT_ENTRY_SIZE;
26595b482a8SLen Brown }
26695b482a8SLen Brown
26795b482a8SLen Brown /*
26895b482a8SLen Brown * It is not possible to map more than one entry in some environments,
26995b482a8SLen Brown * so unmap the RSDP here before mapping other tables
27095b482a8SLen Brown */
27195b482a8SLen Brown acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
27295b482a8SLen Brown
27395b482a8SLen Brown /* Map the RSDT/XSDT table header to get the full table length */
27495b482a8SLen Brown
27595b482a8SLen Brown table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
27695b482a8SLen Brown if (!table) {
27795b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY);
27895b482a8SLen Brown }
27995b482a8SLen Brown
28095b482a8SLen Brown acpi_tb_print_table_header(address, table);
28195b482a8SLen Brown
282671cc68dSLv Zheng /*
283671cc68dSLv Zheng * Validate length of the table, and map entire table.
284671cc68dSLv Zheng * Minimum length table must contain at least one entry.
285671cc68dSLv Zheng */
28695b482a8SLen Brown length = table->length;
28795b482a8SLen Brown acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
28895b482a8SLen Brown
289671cc68dSLv Zheng if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
2903b3ea775SBob Moore ACPI_BIOS_ERROR((AE_INFO,
2913b3ea775SBob Moore "Invalid table length 0x%X in RSDT/XSDT",
29295b482a8SLen Brown length));
29395b482a8SLen Brown return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
29495b482a8SLen Brown }
29595b482a8SLen Brown
29695b482a8SLen Brown table = acpi_os_map_memory(address, length);
29795b482a8SLen Brown if (!table) {
29895b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY);
29995b482a8SLen Brown }
30095b482a8SLen Brown
30195b482a8SLen Brown /* Validate the root table checksum */
30295b482a8SLen Brown
30351aad1a6SBob Moore status = acpi_ut_verify_checksum(table, length);
30495b482a8SLen Brown if (ACPI_FAILURE(status)) {
30595b482a8SLen Brown acpi_os_unmap_memory(table, length);
30695b482a8SLen Brown return_ACPI_STATUS(status);
30795b482a8SLen Brown }
30895b482a8SLen Brown
309671cc68dSLv Zheng /* Get the number of entries and pointer to first entry */
31095b482a8SLen Brown
311ec41f193SBob Moore table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
312ec41f193SBob Moore table_entry_size);
313671cc68dSLv Zheng table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
314671cc68dSLv Zheng
315671cc68dSLv Zheng /* Initialize the root table array from the RSDT/XSDT */
316671cc68dSLv Zheng
31795b482a8SLen Brown for (i = 0; i < table_count; i++) {
31895b482a8SLen Brown
31995b482a8SLen Brown /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
32095b482a8SLen Brown
3210f929fbfSLv Zheng address =
3220f929fbfSLv Zheng acpi_tb_get_root_table_entry(table_entry, table_entry_size);
3230f929fbfSLv Zheng
3240f929fbfSLv Zheng /* Skip NULL entries in RSDT/XSDT */
3250f929fbfSLv Zheng
3260f929fbfSLv Zheng if (!address) {
3270f929fbfSLv Zheng goto next_table;
3280f929fbfSLv Zheng }
3290f929fbfSLv Zheng
3300f929fbfSLv Zheng status = acpi_tb_install_standard_table(address,
331ed6f1d44SBob Moore ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
3325d6e5966SJessica Clarke NULL, FALSE, TRUE,
3330f929fbfSLv Zheng &table_index);
33486dfc6f3SLv Zheng
33586dfc6f3SLv Zheng if (ACPI_SUCCESS(status) &&
3365599fb69SBob Moore ACPI_COMPARE_NAMESEG(&acpi_gbl_root_table_list.
33786dfc6f3SLv Zheng tables[table_index].signature,
33886dfc6f3SLv Zheng ACPI_SIG_FADT)) {
33962fcce91SLv Zheng acpi_gbl_fadt_index = table_index;
34062fcce91SLv Zheng acpi_tb_parse_fadt();
34186dfc6f3SLv Zheng }
34295b482a8SLen Brown
3430f929fbfSLv Zheng next_table:
3440f929fbfSLv Zheng
34595b482a8SLen Brown table_entry += table_entry_size;
34695b482a8SLen Brown }
34795b482a8SLen Brown
34895b482a8SLen Brown acpi_os_unmap_memory(table, length);
34995b482a8SLen Brown return_ACPI_STATUS(AE_OK);
35095b482a8SLen Brown }
351174cc718SLv Zheng
352174cc718SLv Zheng /*******************************************************************************
353174cc718SLv Zheng *
354174cc718SLv Zheng * FUNCTION: acpi_tb_get_table
355174cc718SLv Zheng *
356174cc718SLv Zheng * PARAMETERS: table_desc - Table descriptor
357174cc718SLv Zheng * out_table - Where the pointer to the table is returned
358174cc718SLv Zheng *
359174cc718SLv Zheng * RETURN: Status and pointer to the requested table
360174cc718SLv Zheng *
361174cc718SLv Zheng * DESCRIPTION: Increase a reference to a table descriptor and return the
362174cc718SLv Zheng * validated table pointer.
363174cc718SLv Zheng * If the table descriptor is an entry of the root table list,
364174cc718SLv Zheng * this API must be invoked with ACPI_MTX_TABLES acquired.
365174cc718SLv Zheng *
366174cc718SLv Zheng ******************************************************************************/
367174cc718SLv Zheng
368174cc718SLv Zheng acpi_status
acpi_tb_get_table(struct acpi_table_desc * table_desc,struct acpi_table_header ** out_table)369174cc718SLv Zheng acpi_tb_get_table(struct acpi_table_desc *table_desc,
370174cc718SLv Zheng struct acpi_table_header **out_table)
371174cc718SLv Zheng {
372174cc718SLv Zheng acpi_status status;
373174cc718SLv Zheng
374174cc718SLv Zheng ACPI_FUNCTION_TRACE(acpi_tb_get_table);
375174cc718SLv Zheng
376174cc718SLv Zheng if (table_desc->validation_count == 0) {
377174cc718SLv Zheng
378174cc718SLv Zheng /* Table need to be "VALIDATED" */
379174cc718SLv Zheng
380174cc718SLv Zheng status = acpi_tb_validate_table(table_desc);
381174cc718SLv Zheng if (ACPI_FAILURE(status)) {
382174cc718SLv Zheng return_ACPI_STATUS(status);
383174cc718SLv Zheng }
384174cc718SLv Zheng }
385174cc718SLv Zheng
38683848fbeSLv Zheng if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
387174cc718SLv Zheng table_desc->validation_count++;
38883848fbeSLv Zheng
38983848fbeSLv Zheng /*
39083848fbeSLv Zheng * Detect validation_count overflows to ensure that the warning
39183848fbeSLv Zheng * message will only be printed once.
39283848fbeSLv Zheng */
39383848fbeSLv Zheng if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
39483848fbeSLv Zheng ACPI_WARNING((AE_INFO,
39583848fbeSLv Zheng "Table %p, Validation count overflows\n",
39683848fbeSLv Zheng table_desc));
39783848fbeSLv Zheng }
398174cc718SLv Zheng }
399174cc718SLv Zheng
400174cc718SLv Zheng *out_table = table_desc->pointer;
401174cc718SLv Zheng return_ACPI_STATUS(AE_OK);
402174cc718SLv Zheng }
403174cc718SLv Zheng
404174cc718SLv Zheng /*******************************************************************************
405174cc718SLv Zheng *
406174cc718SLv Zheng * FUNCTION: acpi_tb_put_table
407174cc718SLv Zheng *
408174cc718SLv Zheng * PARAMETERS: table_desc - Table descriptor
409174cc718SLv Zheng *
410174cc718SLv Zheng * RETURN: None
411174cc718SLv Zheng *
412174cc718SLv Zheng * DESCRIPTION: Decrease a reference to a table descriptor and release the
413174cc718SLv Zheng * validated table pointer if no references.
414174cc718SLv Zheng * If the table descriptor is an entry of the root table list,
415174cc718SLv Zheng * this API must be invoked with ACPI_MTX_TABLES acquired.
416174cc718SLv Zheng *
417174cc718SLv Zheng ******************************************************************************/
418174cc718SLv Zheng
acpi_tb_put_table(struct acpi_table_desc * table_desc)419174cc718SLv Zheng void acpi_tb_put_table(struct acpi_table_desc *table_desc)
420174cc718SLv Zheng {
421174cc718SLv Zheng
422174cc718SLv Zheng ACPI_FUNCTION_TRACE(acpi_tb_put_table);
423174cc718SLv Zheng
42483848fbeSLv Zheng if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
42583848fbeSLv Zheng table_desc->validation_count--;
42683848fbeSLv Zheng
42783848fbeSLv Zheng /*
42883848fbeSLv Zheng * Detect validation_count underflows to ensure that the warning
42983848fbeSLv Zheng * message will only be printed once.
43083848fbeSLv Zheng */
43183848fbeSLv Zheng if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
432174cc718SLv Zheng ACPI_WARNING((AE_INFO,
43383848fbeSLv Zheng "Table %p, Validation count underflows\n",
434174cc718SLv Zheng table_desc));
435174cc718SLv Zheng return_VOID;
436174cc718SLv Zheng }
43783848fbeSLv Zheng }
438174cc718SLv Zheng
439174cc718SLv Zheng if (table_desc->validation_count == 0) {
440174cc718SLv Zheng
441174cc718SLv Zheng /* Table need to be "INVALIDATED" */
442174cc718SLv Zheng
443174cc718SLv Zheng acpi_tb_invalidate_table(table_desc);
444174cc718SLv Zheng }
445174cc718SLv Zheng
446174cc718SLv Zheng return_VOID;
447174cc718SLv Zheng }
448