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