xref: /openbmc/linux/drivers/acpi/acpica/tbinstal.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: tbinstal - ACPI table installation and removal
595b482a8SLen Brown  *
6*612c2932SBob 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("tbinstal")
1695b482a8SLen Brown 
1786dfc6f3SLv Zheng /*******************************************************************************
1886dfc6f3SLv Zheng  *
19ed6f1d44SBob Moore  * FUNCTION:    acpi_tb_install_table_with_override
2086dfc6f3SLv Zheng  *
218ec3f459SLv Zheng  * PARAMETERS:  new_table_desc          - New table descriptor to install
22caf4a15cSLv Zheng  *              override                - Whether override should be performed
238ec3f459SLv Zheng  *              table_index             - Where the table index is returned
2486dfc6f3SLv Zheng  *
2586dfc6f3SLv Zheng  * RETURN:      None
2686dfc6f3SLv Zheng  *
2786dfc6f3SLv Zheng  * DESCRIPTION: Install an ACPI table into the global data structure. The
2886dfc6f3SLv Zheng  *              table override mechanism is called to allow the host
2986dfc6f3SLv Zheng  *              OS to replace any table before it is installed in the root
3086dfc6f3SLv Zheng  *              table array.
3186dfc6f3SLv Zheng  *
3286dfc6f3SLv Zheng  ******************************************************************************/
3386dfc6f3SLv Zheng void
acpi_tb_install_table_with_override(struct acpi_table_desc * new_table_desc,u8 override,u32 * table_index)348ec3f459SLv Zheng acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc,
358ec3f459SLv Zheng 				    u8 override, u32 *table_index)
3686dfc6f3SLv Zheng {
378ec3f459SLv Zheng 	u32 i;
388ec3f459SLv Zheng 	acpi_status status;
39ed6f1d44SBob Moore 
408ec3f459SLv Zheng 	status = acpi_tb_get_next_table_descriptor(&i, NULL);
418ec3f459SLv Zheng 	if (ACPI_FAILURE(status)) {
4286dfc6f3SLv Zheng 		return;
4386dfc6f3SLv Zheng 	}
4486dfc6f3SLv Zheng 
4586dfc6f3SLv Zheng 	/*
4686dfc6f3SLv Zheng 	 * ACPI Table Override:
4786dfc6f3SLv Zheng 	 *
4886dfc6f3SLv Zheng 	 * Before we install the table, let the host OS override it with a new
4986dfc6f3SLv Zheng 	 * one if desired. Any table within the RSDT/XSDT can be replaced,
5086dfc6f3SLv Zheng 	 * including the DSDT which is pointed to by the FADT.
5186dfc6f3SLv Zheng 	 */
52caf4a15cSLv Zheng 	if (override) {
5386dfc6f3SLv Zheng 		acpi_tb_override_table(new_table_desc);
54caf4a15cSLv Zheng 	}
5586dfc6f3SLv Zheng 
568ec3f459SLv Zheng 	acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.tables[i],
57ed6f1d44SBob Moore 				      new_table_desc->address,
58ed6f1d44SBob Moore 				      new_table_desc->flags,
5986dfc6f3SLv Zheng 				      new_table_desc->pointer);
6086dfc6f3SLv Zheng 
6186dfc6f3SLv Zheng 	acpi_tb_print_table_header(new_table_desc->address,
6286dfc6f3SLv Zheng 				   new_table_desc->pointer);
6386dfc6f3SLv Zheng 
648ec3f459SLv Zheng 	/* This synchronizes acpi_gbl_dsdt_index */
658ec3f459SLv Zheng 
668ec3f459SLv Zheng 	*table_index = i;
678ec3f459SLv Zheng 
6886dfc6f3SLv Zheng 	/* Set the global integer width (based upon revision of the DSDT) */
6986dfc6f3SLv Zheng 
708ec3f459SLv Zheng 	if (i == acpi_gbl_dsdt_index) {
7186dfc6f3SLv Zheng 		acpi_ut_set_integer_width(new_table_desc->pointer->revision);
7286dfc6f3SLv Zheng 	}
7386dfc6f3SLv Zheng }
7486dfc6f3SLv Zheng 
7586dfc6f3SLv Zheng /*******************************************************************************
7686dfc6f3SLv Zheng  *
77ed6f1d44SBob Moore  * FUNCTION:    acpi_tb_install_standard_table
7886dfc6f3SLv Zheng  *
798a216d7fSLv Zheng  * PARAMETERS:  address             - Address of the table (might be a virtual
8086dfc6f3SLv Zheng  *                                    address depending on the table_flags)
8186dfc6f3SLv Zheng  *              flags               - Flags for the table
825d6e5966SJessica Clarke  *              table               - Pointer to the table (required for virtual
835d6e5966SJessica Clarke  *                                    origins, optional for physical)
8486dfc6f3SLv Zheng  *              reload              - Whether reload should be performed
85caf4a15cSLv Zheng  *              override            - Whether override should be performed
8686dfc6f3SLv Zheng  *              table_index         - Where the table index is returned
8786dfc6f3SLv Zheng  *
8886dfc6f3SLv Zheng  * RETURN:      Status
8986dfc6f3SLv Zheng  *
90752db101SLv Zheng  * DESCRIPTION: This function is called to verify and install an ACPI table.
9186dfc6f3SLv Zheng  *              When this function is called by "Load" or "LoadTable" opcodes,
9286dfc6f3SLv Zheng  *              or by acpi_load_table() API, the "Reload" parameter is set.
93c2fa79b8SColin Ian King  *              After successfully returning from this function, table is
9486dfc6f3SLv Zheng  *              "INSTALLED" but not "VALIDATED".
9586dfc6f3SLv Zheng  *
9686dfc6f3SLv Zheng  ******************************************************************************/
9786dfc6f3SLv Zheng 
9886dfc6f3SLv Zheng acpi_status
acpi_tb_install_standard_table(acpi_physical_address address,u8 flags,struct acpi_table_header * table,u8 reload,u8 override,u32 * table_index)99ed6f1d44SBob Moore acpi_tb_install_standard_table(acpi_physical_address address,
100caf4a15cSLv Zheng 			       u8 flags,
1015d6e5966SJessica Clarke 			       struct acpi_table_header *table,
102caf4a15cSLv Zheng 			       u8 reload, u8 override, u32 *table_index)
10395b482a8SLen Brown {
10495b482a8SLen Brown 	u32 i;
10595b482a8SLen Brown 	acpi_status status = AE_OK;
10686dfc6f3SLv Zheng 	struct acpi_table_desc new_table_desc;
10795b482a8SLen Brown 
108ed6f1d44SBob Moore 	ACPI_FUNCTION_TRACE(tb_install_standard_table);
10995b482a8SLen Brown 
110ed6f1d44SBob Moore 	/* Acquire a temporary table descriptor for validation */
11186dfc6f3SLv Zheng 
1125d6e5966SJessica Clarke 	status =
1135d6e5966SJessica Clarke 	    acpi_tb_acquire_temp_table(&new_table_desc, address, flags, table);
11486dfc6f3SLv Zheng 	if (ACPI_FAILURE(status)) {
115cc2080b0SLv Zheng 		ACPI_ERROR((AE_INFO,
116cc2080b0SLv Zheng 			    "Could not acquire table length at %8.8X%8.8X",
117cc2080b0SLv Zheng 			    ACPI_FORMAT_UINT64(address)));
11895b482a8SLen Brown 		return_ACPI_STATUS(status);
11995b482a8SLen Brown 	}
12086dfc6f3SLv Zheng 
121a94e88cdSLv Zheng 	/*
122a94e88cdSLv Zheng 	 * Optionally do not load any SSDTs from the RSDT/XSDT. This can
123a94e88cdSLv Zheng 	 * be useful for debugging ACPI problems on some machines.
124a94e88cdSLv Zheng 	 */
125ed6f1d44SBob Moore 	if (!reload &&
126ed6f1d44SBob Moore 	    acpi_gbl_disable_ssdt_table_install &&
1275599fb69SBob Moore 	    ACPI_COMPARE_NAMESEG(&new_table_desc.signature, ACPI_SIG_SSDT)) {
12805fb04b5SBob Moore 		ACPI_INFO(("Ignoring installation of %4.4s at %8.8X%8.8X",
1296d3fd3ccSLv Zheng 			   new_table_desc.signature.ascii,
130cc2080b0SLv Zheng 			   ACPI_FORMAT_UINT64(address)));
131a94e88cdSLv Zheng 		goto release_and_exit;
132a94e88cdSLv Zheng 	}
133a94e88cdSLv Zheng 
1347a37052aSLv Zheng 	/* Acquire the table lock */
1357a37052aSLv Zheng 
1367a37052aSLv Zheng 	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
1377a37052aSLv Zheng 
138f9d472eeSLv Zheng 	/* Validate and verify a table before installation */
13995b482a8SLen Brown 
140f9d472eeSLv Zheng 	status = acpi_tb_verify_temp_table(&new_table_desc, NULL, &i);
141f9d472eeSLv Zheng 	if (ACPI_FAILURE(status)) {
142f9d472eeSLv Zheng 		if (status == AE_CTRL_TERMINATE) {
143d3ccaff8SBob Moore 			/*
14486dfc6f3SLv Zheng 			 * Table was unloaded, allow it to be reloaded.
14586dfc6f3SLv Zheng 			 * As we are going to return AE_OK to the caller, we should
14686dfc6f3SLv Zheng 			 * take the responsibility of freeing the input descriptor.
14786dfc6f3SLv Zheng 			 * Refill the input descriptor to ensure
148ed6f1d44SBob Moore 			 * acpi_tb_install_table_with_override() can be called again to
14986dfc6f3SLv Zheng 			 * indicate the re-installation.
150d3ccaff8SBob Moore 			 */
15186dfc6f3SLv Zheng 			acpi_tb_uninstall_table(&new_table_desc);
1527a37052aSLv Zheng 			(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
15386dfc6f3SLv Zheng 			*table_index = i;
15486dfc6f3SLv Zheng 			return_ACPI_STATUS(AE_OK);
15586dfc6f3SLv Zheng 		}
156f9d472eeSLv Zheng 		goto unlock_and_exit;
1577f9fc99cSLv Zheng 	}
158d3ccaff8SBob Moore 
15995b482a8SLen Brown 	/* Add the table to the global root table list */
16095b482a8SLen Brown 
1618ec3f459SLv Zheng 	acpi_tb_install_table_with_override(&new_table_desc, override,
1628ec3f459SLv Zheng 					    table_index);
16395b482a8SLen Brown 
1649b019b0fSLv Zheng 	/* Invoke table handler */
165bdbe5df0SLv Zheng 
1667a37052aSLv Zheng 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
1679b019b0fSLv Zheng 	acpi_tb_notify_table(ACPI_TABLE_EVENT_INSTALL, new_table_desc.pointer);
1687a37052aSLv Zheng 	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
1697a37052aSLv Zheng 
1707a37052aSLv Zheng unlock_and_exit:
1717a37052aSLv Zheng 
1727a37052aSLv Zheng 	/* Release the table lock */
1737a37052aSLv Zheng 
1747a37052aSLv Zheng 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
175bdbe5df0SLv Zheng 
17686dfc6f3SLv Zheng release_and_exit:
17795b482a8SLen Brown 
178ed6f1d44SBob Moore 	/* Release the temporary table descriptor */
17986dfc6f3SLv Zheng 
180ed6f1d44SBob Moore 	acpi_tb_release_temp_table(&new_table_desc);
18195b482a8SLen Brown 	return_ACPI_STATUS(status);
18295b482a8SLen Brown }
18395b482a8SLen Brown 
18495b482a8SLen Brown /*******************************************************************************
18595b482a8SLen Brown  *
1867f9fc99cSLv Zheng  * FUNCTION:    acpi_tb_override_table
187f7b004a1SBob Moore  *
18886dfc6f3SLv Zheng  * PARAMETERS:  old_table_desc      - Validated table descriptor to be
18986dfc6f3SLv Zheng  *                                    overridden
190f7b004a1SBob Moore  *
19186dfc6f3SLv Zheng  * RETURN:      None
192f7b004a1SBob Moore  *
193f7b004a1SBob Moore  * DESCRIPTION: Attempt table override by calling the OSL override functions.
194f7b004a1SBob Moore  *              Note: If the table is overridden, then the entire new table
1957f9fc99cSLv Zheng  *              is acquired and returned by this function.
19686dfc6f3SLv Zheng  *              Before/after invocation, the table descriptor is in a state
19786dfc6f3SLv Zheng  *              that is "VALIDATED".
198f7b004a1SBob Moore  *
199f7b004a1SBob Moore  ******************************************************************************/
200f7b004a1SBob Moore 
acpi_tb_override_table(struct acpi_table_desc * old_table_desc)20186dfc6f3SLv Zheng void acpi_tb_override_table(struct acpi_table_desc *old_table_desc)
202f7b004a1SBob Moore {
203f7b004a1SBob Moore 	acpi_status status;
2047f9fc99cSLv Zheng 	struct acpi_table_desc new_table_desc;
20586dfc6f3SLv Zheng 	struct acpi_table_header *table;
20686dfc6f3SLv Zheng 	acpi_physical_address address;
20786dfc6f3SLv Zheng 	u32 length;
2080fe0bebfSErik Schmauss 	ACPI_ERROR_ONLY(char *override_type);
209f7b004a1SBob Moore 
210f7b004a1SBob Moore 	/* (1) Attempt logical override (returns a logical address) */
211f7b004a1SBob Moore 
21286dfc6f3SLv Zheng 	status = acpi_os_table_override(old_table_desc->pointer, &table);
21386dfc6f3SLv Zheng 	if (ACPI_SUCCESS(status) && table) {
214ed6f1d44SBob Moore 		acpi_tb_acquire_temp_table(&new_table_desc,
21586dfc6f3SLv Zheng 					   ACPI_PTR_TO_PHYSADDR(table),
2165d6e5966SJessica Clarke 					   ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
2175d6e5966SJessica Clarke 					   table);
2180fe0bebfSErik Schmauss 		ACPI_ERROR_ONLY(override_type = "Logical");
219f7b004a1SBob Moore 		goto finish_override;
220f7b004a1SBob Moore 	}
221f7b004a1SBob Moore 
222f7b004a1SBob Moore 	/* (2) Attempt physical override (returns a physical address) */
223f7b004a1SBob Moore 
22486dfc6f3SLv Zheng 	status = acpi_os_physical_table_override(old_table_desc->pointer,
22586dfc6f3SLv Zheng 						 &address, &length);
22686dfc6f3SLv Zheng 	if (ACPI_SUCCESS(status) && address && length) {
227ed6f1d44SBob Moore 		acpi_tb_acquire_temp_table(&new_table_desc, address,
2285d6e5966SJessica Clarke 					   ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
2295d6e5966SJessica Clarke 					   NULL);
2300fe0bebfSErik Schmauss 		ACPI_ERROR_ONLY(override_type = "Physical");
231f7b004a1SBob Moore 		goto finish_override;
232f7b004a1SBob Moore 	}
233f7b004a1SBob Moore 
23486dfc6f3SLv Zheng 	return;			/* There was no override */
235f7b004a1SBob Moore 
236f7b004a1SBob Moore finish_override:
237f7b004a1SBob Moore 
238f9d472eeSLv Zheng 	/*
239f9d472eeSLv Zheng 	 * Validate and verify a table before overriding, no nested table
240f9d472eeSLv Zheng 	 * duplication check as it's too complicated and unnecessary.
241f9d472eeSLv Zheng 	 */
242f9d472eeSLv Zheng 	status = acpi_tb_verify_temp_table(&new_table_desc, NULL, NULL);
2437f9fc99cSLv Zheng 	if (ACPI_FAILURE(status)) {
24486dfc6f3SLv Zheng 		return;
2457f9fc99cSLv Zheng 	}
2467f9fc99cSLv Zheng 
24705fb04b5SBob Moore 	ACPI_INFO(("%4.4s 0x%8.8X%8.8X"
2481d0a0b2fSLv Zheng 		   " %s table override, new table: 0x%8.8X%8.8X",
24986dfc6f3SLv Zheng 		   old_table_desc->signature.ascii,
2501d0a0b2fSLv Zheng 		   ACPI_FORMAT_UINT64(old_table_desc->address),
2511d0a0b2fSLv Zheng 		   override_type, ACPI_FORMAT_UINT64(new_table_desc.address)));
252f7b004a1SBob Moore 
25386dfc6f3SLv Zheng 	/* We can now uninstall the original table */
254f7b004a1SBob Moore 
25586dfc6f3SLv Zheng 	acpi_tb_uninstall_table(old_table_desc);
256f7b004a1SBob Moore 
25786dfc6f3SLv Zheng 	/*
25886dfc6f3SLv Zheng 	 * Replace the original table descriptor and keep its state as
25986dfc6f3SLv Zheng 	 * "VALIDATED".
26086dfc6f3SLv Zheng 	 */
261ed6f1d44SBob Moore 	acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address,
262ed6f1d44SBob Moore 				      new_table_desc.flags,
263ed6f1d44SBob Moore 				      new_table_desc.pointer);
26447d68c7fSLv Zheng 	acpi_tb_validate_temp_table(old_table_desc);
265f7b004a1SBob Moore 
266ed6f1d44SBob Moore 	/* Release the temporary table descriptor */
267f7b004a1SBob Moore 
268ed6f1d44SBob Moore 	acpi_tb_release_temp_table(&new_table_desc);
269f7b004a1SBob Moore }
270f7b004a1SBob Moore 
271f7b004a1SBob Moore /*******************************************************************************
272f7b004a1SBob Moore  *
2737f9fc99cSLv Zheng  * FUNCTION:    acpi_tb_uninstall_table
27495b482a8SLen Brown  *
2757f9fc99cSLv Zheng  * PARAMETERS:  table_desc          - Table descriptor
27695b482a8SLen Brown  *
27795b482a8SLen Brown  * RETURN:      None
27895b482a8SLen Brown  *
27995b482a8SLen Brown  * DESCRIPTION: Delete one internal ACPI table
28095b482a8SLen Brown  *
28195b482a8SLen Brown  ******************************************************************************/
28295b482a8SLen Brown 
acpi_tb_uninstall_table(struct acpi_table_desc * table_desc)2837f9fc99cSLv Zheng void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc)
28495b482a8SLen Brown {
2855582982dSLv Zheng 
2867f9fc99cSLv Zheng 	ACPI_FUNCTION_TRACE(tb_uninstall_table);
2875582982dSLv Zheng 
2887f9fc99cSLv Zheng 	/* Table must be installed */
2897f9fc99cSLv Zheng 
2907f9fc99cSLv Zheng 	if (!table_desc->address) {
2917f9fc99cSLv Zheng 		return_VOID;
29295b482a8SLen Brown 	}
2935582982dSLv Zheng 
2947f9fc99cSLv Zheng 	acpi_tb_invalidate_table(table_desc);
2951d1ea1b7SChao Guan 
2967f9fc99cSLv Zheng 	if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
297ed6f1d44SBob Moore 	    ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) {
2985d6e5966SJessica Clarke 		ACPI_FREE(table_desc->pointer);
2995d6e5966SJessica Clarke 		table_desc->pointer = NULL;
3007f9fc99cSLv Zheng 	}
3011d1ea1b7SChao Guan 
302dc156adfSLv Zheng 	table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL);
3037f9fc99cSLv Zheng 	return_VOID;
30495b482a8SLen Brown }
305