162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: tbxface - ACPI table-oriented external interfaces
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define EXPORT_ACPI_INTERFACES
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <acpi/acpi.h>
1362306a36Sopenharmony_ci#include "accommon.h"
1462306a36Sopenharmony_ci#include "actables.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define _COMPONENT          ACPI_TABLES
1762306a36Sopenharmony_ciACPI_MODULE_NAME("tbxface")
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*******************************************************************************
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * FUNCTION:    acpi_allocate_root_table
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * PARAMETERS:  initial_table_count - Size of initial_table_array, in number of
2462306a36Sopenharmony_ci *                                    struct acpi_table_desc structures
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * RETURN:      Status
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * DESCRIPTION: Allocate a root table array. Used by iASL compiler and
2962306a36Sopenharmony_ci *              acpi_initialize_tables.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci ******************************************************************************/
3262306a36Sopenharmony_ciacpi_status acpi_allocate_root_table(u32 initial_table_count)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	acpi_gbl_root_table_list.max_table_count = initial_table_count;
3662306a36Sopenharmony_ci	acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return (acpi_tb_resize_root_table_list());
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*******************************************************************************
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * FUNCTION:    acpi_initialize_tables
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * PARAMETERS:  initial_table_array - Pointer to an array of pre-allocated
4662306a36Sopenharmony_ci *                                    struct acpi_table_desc structures. If NULL, the
4762306a36Sopenharmony_ci *                                    array is dynamically allocated.
4862306a36Sopenharmony_ci *              initial_table_count - Size of initial_table_array, in number of
4962306a36Sopenharmony_ci *                                    struct acpi_table_desc structures
5062306a36Sopenharmony_ci *              allow_resize        - Flag to tell Table Manager if resize of
5162306a36Sopenharmony_ci *                                    pre-allocated array is allowed. Ignored
5262306a36Sopenharmony_ci *                                    if initial_table_array is NULL.
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * RETURN:      Status
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * NOTE:        Allows static allocation of the initial table array in order
5962306a36Sopenharmony_ci *              to avoid the use of dynamic memory in confined environments
6062306a36Sopenharmony_ci *              such as the kernel boot sequence where it may not be available.
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci *              If the host OS memory managers are initialized, use NULL for
6362306a36Sopenharmony_ci *              initial_table_array, and the table will be dynamically allocated.
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci ******************************************************************************/
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciacpi_status ACPI_INIT_FUNCTION
6862306a36Sopenharmony_ciacpi_initialize_tables(struct acpi_table_desc *initial_table_array,
6962306a36Sopenharmony_ci		       u32 initial_table_count, u8 allow_resize)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	acpi_physical_address rsdp_address;
7262306a36Sopenharmony_ci	acpi_status status;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_initialize_tables);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/*
7762306a36Sopenharmony_ci	 * Setup the Root Table Array and allocate the table array
7862306a36Sopenharmony_ci	 * if requested
7962306a36Sopenharmony_ci	 */
8062306a36Sopenharmony_ci	if (!initial_table_array) {
8162306a36Sopenharmony_ci		status = acpi_allocate_root_table(initial_table_count);
8262306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
8362306a36Sopenharmony_ci			return_ACPI_STATUS(status);
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci	} else {
8662306a36Sopenharmony_ci		/* Root Table Array has been statically allocated by the host */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		memset(initial_table_array, 0,
8962306a36Sopenharmony_ci		       (acpi_size)initial_table_count *
9062306a36Sopenharmony_ci		       sizeof(struct acpi_table_desc));
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		acpi_gbl_root_table_list.tables = initial_table_array;
9362306a36Sopenharmony_ci		acpi_gbl_root_table_list.max_table_count = initial_table_count;
9462306a36Sopenharmony_ci		acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
9562306a36Sopenharmony_ci		if (allow_resize) {
9662306a36Sopenharmony_ci			acpi_gbl_root_table_list.flags |=
9762306a36Sopenharmony_ci			    ACPI_ROOT_ALLOW_RESIZE;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Get the address of the RSDP */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	rsdp_address = acpi_os_get_root_pointer();
10462306a36Sopenharmony_ci	if (!rsdp_address) {
10562306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NOT_FOUND);
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/*
10962306a36Sopenharmony_ci	 * Get the root table (RSDT or XSDT) and extract all entries to the local
11062306a36Sopenharmony_ci	 * Root Table Array. This array contains the information of the RSDT/XSDT
11162306a36Sopenharmony_ci	 * in a common, more usable format.
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	status = acpi_tb_parse_root_table(rsdp_address);
11462306a36Sopenharmony_ci	return_ACPI_STATUS(status);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ciACPI_EXPORT_SYMBOL_INIT(acpi_initialize_tables)
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*******************************************************************************
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * FUNCTION:    acpi_reallocate_root_table
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * PARAMETERS:  None
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * RETURN:      Status
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
12862306a36Sopenharmony_ci *              root list from the previously provided scratch area. Should
12962306a36Sopenharmony_ci *              be called once dynamic memory allocation is available in the
13062306a36Sopenharmony_ci *              kernel.
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci ******************************************************************************/
13362306a36Sopenharmony_ciacpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	acpi_status status;
13662306a36Sopenharmony_ci	struct acpi_table_desc *table_desc;
13762306a36Sopenharmony_ci	u32 i, j;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/*
14262306a36Sopenharmony_ci	 * If there are tables unverified, it is required to reallocate the
14362306a36Sopenharmony_ci	 * root table list to clean up invalid table entries. Otherwise only
14462306a36Sopenharmony_ci	 * reallocate the root table list if the host provided a static buffer
14562306a36Sopenharmony_ci	 * for the table array in the call to acpi_initialize_tables().
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	if ((acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) &&
14862306a36Sopenharmony_ci	    acpi_gbl_enable_table_validation) {
14962306a36Sopenharmony_ci		return_ACPI_STATUS(AE_SUPPORT);
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/*
15562306a36Sopenharmony_ci	 * Ensure OS early boot logic, which is required by some hosts. If the
15662306a36Sopenharmony_ci	 * table state is reported to be wrong, developers should fix the
15762306a36Sopenharmony_ci	 * issue by invoking acpi_put_table() for the reported table during the
15862306a36Sopenharmony_ci	 * early stage.
15962306a36Sopenharmony_ci	 */
16062306a36Sopenharmony_ci	for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
16162306a36Sopenharmony_ci		table_desc = &acpi_gbl_root_table_list.tables[i];
16262306a36Sopenharmony_ci		if (table_desc->pointer) {
16362306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
16462306a36Sopenharmony_ci				    "Table [%4.4s] is not invalidated during early boot stage",
16562306a36Sopenharmony_ci				    table_desc->signature.ascii));
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (!acpi_gbl_enable_table_validation) {
17062306a36Sopenharmony_ci		/*
17162306a36Sopenharmony_ci		 * Now it's safe to do full table validation. We can do deferred
17262306a36Sopenharmony_ci		 * table initialization here once the flag is set.
17362306a36Sopenharmony_ci		 */
17462306a36Sopenharmony_ci		acpi_gbl_enable_table_validation = TRUE;
17562306a36Sopenharmony_ci		for (i = 0; i < acpi_gbl_root_table_list.current_table_count;
17662306a36Sopenharmony_ci		     ++i) {
17762306a36Sopenharmony_ci			table_desc = &acpi_gbl_root_table_list.tables[i];
17862306a36Sopenharmony_ci			if (!(table_desc->flags & ACPI_TABLE_IS_VERIFIED)) {
17962306a36Sopenharmony_ci				status =
18062306a36Sopenharmony_ci				    acpi_tb_verify_temp_table(table_desc, NULL,
18162306a36Sopenharmony_ci							      &j);
18262306a36Sopenharmony_ci				if (ACPI_FAILURE(status)) {
18362306a36Sopenharmony_ci					acpi_tb_uninstall_table(table_desc);
18462306a36Sopenharmony_ci				}
18562306a36Sopenharmony_ci			}
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE;
19062306a36Sopenharmony_ci	status = acpi_tb_resize_root_table_list();
19162306a36Sopenharmony_ci	acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
19462306a36Sopenharmony_ci	return_ACPI_STATUS(status);
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciACPI_EXPORT_SYMBOL_INIT(acpi_reallocate_root_table)
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/*******************************************************************************
20062306a36Sopenharmony_ci *
20162306a36Sopenharmony_ci * FUNCTION:    acpi_get_table_header
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * PARAMETERS:  signature           - ACPI signature of needed table
20462306a36Sopenharmony_ci *              instance            - Which instance (for SSDTs)
20562306a36Sopenharmony_ci *              out_table_header    - The pointer to the where the table header
20662306a36Sopenharmony_ci *                                    is returned
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci * RETURN:      Status and a copy of the table header
20962306a36Sopenharmony_ci *
21062306a36Sopenharmony_ci * DESCRIPTION: Finds and returns an ACPI table header. Caller provides the
21162306a36Sopenharmony_ci *              memory where a copy of the header is to be returned
21262306a36Sopenharmony_ci *              (fixed length).
21362306a36Sopenharmony_ci *
21462306a36Sopenharmony_ci ******************************************************************************/
21562306a36Sopenharmony_ciacpi_status
21662306a36Sopenharmony_ciacpi_get_table_header(char *signature,
21762306a36Sopenharmony_ci		      u32 instance, struct acpi_table_header *out_table_header)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	u32 i;
22062306a36Sopenharmony_ci	u32 j;
22162306a36Sopenharmony_ci	struct acpi_table_header *header;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* Parameter validation */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (!signature || !out_table_header) {
22662306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* Walk the root table list */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
23262306a36Sopenharmony_ci	     i++) {
23362306a36Sopenharmony_ci		if (!ACPI_COMPARE_NAMESEG
23462306a36Sopenharmony_ci		    (&(acpi_gbl_root_table_list.tables[i].signature),
23562306a36Sopenharmony_ci		     signature)) {
23662306a36Sopenharmony_ci			continue;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		if (++j < instance) {
24062306a36Sopenharmony_ci			continue;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		if (!acpi_gbl_root_table_list.tables[i].pointer) {
24462306a36Sopenharmony_ci			if ((acpi_gbl_root_table_list.tables[i].flags &
24562306a36Sopenharmony_ci			     ACPI_TABLE_ORIGIN_MASK) ==
24662306a36Sopenharmony_ci			    ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) {
24762306a36Sopenharmony_ci				header =
24862306a36Sopenharmony_ci				    acpi_os_map_memory(acpi_gbl_root_table_list.
24962306a36Sopenharmony_ci						       tables[i].address,
25062306a36Sopenharmony_ci						       sizeof(struct
25162306a36Sopenharmony_ci							      acpi_table_header));
25262306a36Sopenharmony_ci				if (!header) {
25362306a36Sopenharmony_ci					return (AE_NO_MEMORY);
25462306a36Sopenharmony_ci				}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci				memcpy(out_table_header, header,
25762306a36Sopenharmony_ci				       sizeof(struct acpi_table_header));
25862306a36Sopenharmony_ci				acpi_os_unmap_memory(header,
25962306a36Sopenharmony_ci						     sizeof(struct
26062306a36Sopenharmony_ci							    acpi_table_header));
26162306a36Sopenharmony_ci			} else {
26262306a36Sopenharmony_ci				return (AE_NOT_FOUND);
26362306a36Sopenharmony_ci			}
26462306a36Sopenharmony_ci		} else {
26562306a36Sopenharmony_ci			memcpy(out_table_header,
26662306a36Sopenharmony_ci			       acpi_gbl_root_table_list.tables[i].pointer,
26762306a36Sopenharmony_ci			       sizeof(struct acpi_table_header));
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci		return (AE_OK);
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return (AE_NOT_FOUND);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_table_header)
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/*******************************************************************************
27862306a36Sopenharmony_ci *
27962306a36Sopenharmony_ci * FUNCTION:    acpi_get_table
28062306a36Sopenharmony_ci *
28162306a36Sopenharmony_ci * PARAMETERS:  signature           - ACPI signature of needed table
28262306a36Sopenharmony_ci *              instance            - Which instance (for SSDTs)
28362306a36Sopenharmony_ci *              out_table           - Where the pointer to the table is returned
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci * RETURN:      Status and pointer to the requested table
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
28862306a36Sopenharmony_ci *              RSDT/XSDT.
28962306a36Sopenharmony_ci *              Note that an early stage acpi_get_table() call must be paired
29062306a36Sopenharmony_ci *              with an early stage acpi_put_table() call. otherwise the table
29162306a36Sopenharmony_ci *              pointer mapped by the early stage mapping implementation may be
29262306a36Sopenharmony_ci *              erroneously unmapped by the late stage unmapping implementation
29362306a36Sopenharmony_ci *              in an acpi_put_table() invoked during the late stage.
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci ******************************************************************************/
29662306a36Sopenharmony_ciacpi_status
29762306a36Sopenharmony_ciacpi_get_table(char *signature,
29862306a36Sopenharmony_ci	       u32 instance, struct acpi_table_header ** out_table)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	u32 i;
30162306a36Sopenharmony_ci	u32 j;
30262306a36Sopenharmony_ci	acpi_status status = AE_NOT_FOUND;
30362306a36Sopenharmony_ci	struct acpi_table_desc *table_desc;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* Parameter validation */
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (!signature || !out_table) {
30862306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/*
31262306a36Sopenharmony_ci	 * Note that the following line is required by some OSPMs, they only
31362306a36Sopenharmony_ci	 * check if the returned table is NULL instead of the returned status
31462306a36Sopenharmony_ci	 * to determined if this function is succeeded.
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	*out_table = NULL;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Walk the root table list */
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
32362306a36Sopenharmony_ci	     i++) {
32462306a36Sopenharmony_ci		table_desc = &acpi_gbl_root_table_list.tables[i];
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		if (!ACPI_COMPARE_NAMESEG(&table_desc->signature, signature)) {
32762306a36Sopenharmony_ci			continue;
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		if (++j < instance) {
33162306a36Sopenharmony_ci			continue;
33262306a36Sopenharmony_ci		}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		status = acpi_tb_get_table(table_desc, out_table);
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
33962306a36Sopenharmony_ci	return (status);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_table)
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci/*******************************************************************************
34562306a36Sopenharmony_ci *
34662306a36Sopenharmony_ci * FUNCTION:    acpi_put_table
34762306a36Sopenharmony_ci *
34862306a36Sopenharmony_ci * PARAMETERS:  table               - The pointer to the table
34962306a36Sopenharmony_ci *
35062306a36Sopenharmony_ci * RETURN:      None
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * DESCRIPTION: Release a table returned by acpi_get_table() and its clones.
35362306a36Sopenharmony_ci *              Note that it is not safe if this function was invoked after an
35462306a36Sopenharmony_ci *              uninstallation happened to the original table descriptor.
35562306a36Sopenharmony_ci *              Currently there is no OSPMs' requirement to handle such
35662306a36Sopenharmony_ci *              situations.
35762306a36Sopenharmony_ci *
35862306a36Sopenharmony_ci ******************************************************************************/
35962306a36Sopenharmony_civoid acpi_put_table(struct acpi_table_header *table)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	u32 i;
36262306a36Sopenharmony_ci	struct acpi_table_desc *table_desc;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_put_table);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (!table) {
36762306a36Sopenharmony_ci		return_VOID;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Walk the root table list */
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
37562306a36Sopenharmony_ci		table_desc = &acpi_gbl_root_table_list.tables[i];
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		if (table_desc->pointer != table) {
37862306a36Sopenharmony_ci			continue;
37962306a36Sopenharmony_ci		}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		acpi_tb_put_table(table_desc);
38262306a36Sopenharmony_ci		break;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
38662306a36Sopenharmony_ci	return_VOID;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_put_table)
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*******************************************************************************
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * FUNCTION:    acpi_get_table_by_index
39462306a36Sopenharmony_ci *
39562306a36Sopenharmony_ci * PARAMETERS:  table_index         - Table index
39662306a36Sopenharmony_ci *              out_table           - Where the pointer to the table is returned
39762306a36Sopenharmony_ci *
39862306a36Sopenharmony_ci * RETURN:      Status and pointer to the requested table
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * DESCRIPTION: Obtain a table by an index into the global table list. Used
40162306a36Sopenharmony_ci *              internally also.
40262306a36Sopenharmony_ci *
40362306a36Sopenharmony_ci ******************************************************************************/
40462306a36Sopenharmony_ciacpi_status
40562306a36Sopenharmony_ciacpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	acpi_status status;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* Parameter validation */
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!out_table) {
41462306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/*
41862306a36Sopenharmony_ci	 * Note that the following line is required by some OSPMs, they only
41962306a36Sopenharmony_ci	 * check if the returned table is NULL instead of the returned status
42062306a36Sopenharmony_ci	 * to determined if this function is succeeded.
42162306a36Sopenharmony_ci	 */
42262306a36Sopenharmony_ci	*out_table = NULL;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Validate index */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (table_index >= acpi_gbl_root_table_list.current_table_count) {
42962306a36Sopenharmony_ci		status = AE_BAD_PARAMETER;
43062306a36Sopenharmony_ci		goto unlock_and_exit;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	status =
43462306a36Sopenharmony_ci	    acpi_tb_get_table(&acpi_gbl_root_table_list.tables[table_index],
43562306a36Sopenharmony_ci			      out_table);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ciunlock_and_exit:
43862306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
43962306a36Sopenharmony_ci	return_ACPI_STATUS(status);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/*******************************************************************************
44562306a36Sopenharmony_ci *
44662306a36Sopenharmony_ci * FUNCTION:    acpi_install_table_handler
44762306a36Sopenharmony_ci *
44862306a36Sopenharmony_ci * PARAMETERS:  handler         - Table event handler
44962306a36Sopenharmony_ci *              context         - Value passed to the handler on each event
45062306a36Sopenharmony_ci *
45162306a36Sopenharmony_ci * RETURN:      Status
45262306a36Sopenharmony_ci *
45362306a36Sopenharmony_ci * DESCRIPTION: Install a global table event handler.
45462306a36Sopenharmony_ci *
45562306a36Sopenharmony_ci ******************************************************************************/
45662306a36Sopenharmony_ciacpi_status
45762306a36Sopenharmony_ciacpi_install_table_handler(acpi_table_handler handler, void *context)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	acpi_status status;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_table_handler);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (!handler) {
46462306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
46862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
46962306a36Sopenharmony_ci		return_ACPI_STATUS(status);
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Don't allow more than one handler */
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (acpi_gbl_table_handler) {
47562306a36Sopenharmony_ci		status = AE_ALREADY_EXISTS;
47662306a36Sopenharmony_ci		goto cleanup;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Install the handler */
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	acpi_gbl_table_handler = handler;
48262306a36Sopenharmony_ci	acpi_gbl_table_handler_context = context;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cicleanup:
48562306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
48662306a36Sopenharmony_ci	return_ACPI_STATUS(status);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_table_handler)
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/*******************************************************************************
49262306a36Sopenharmony_ci *
49362306a36Sopenharmony_ci * FUNCTION:    acpi_remove_table_handler
49462306a36Sopenharmony_ci *
49562306a36Sopenharmony_ci * PARAMETERS:  handler         - Table event handler that was installed
49662306a36Sopenharmony_ci *                                previously.
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * RETURN:      Status
49962306a36Sopenharmony_ci *
50062306a36Sopenharmony_ci * DESCRIPTION: Remove a table event handler
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci ******************************************************************************/
50362306a36Sopenharmony_ciacpi_status acpi_remove_table_handler(acpi_table_handler handler)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	acpi_status status;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_remove_table_handler);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
51062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
51162306a36Sopenharmony_ci		return_ACPI_STATUS(status);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/* Make sure that the installed handler is the same */
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (!handler || handler != acpi_gbl_table_handler) {
51762306a36Sopenharmony_ci		status = AE_BAD_PARAMETER;
51862306a36Sopenharmony_ci		goto cleanup;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* Remove the handler */
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	acpi_gbl_table_handler = NULL;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cicleanup:
52662306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
52762306a36Sopenharmony_ci	return_ACPI_STATUS(status);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_remove_table_handler)
531