xref: /openbmc/linux/drivers/acpi/acpica/tbinstal.c (revision 5599fb69355d7a558f32206dac7539e945a1f604)
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  *
6840c02caSBob Moore  * Copyright (C) 2000 - 2019, 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
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
8286dfc6f3SLv Zheng  *              reload              - Whether reload should be performed
83caf4a15cSLv Zheng  *              override            - Whether override should be performed
8486dfc6f3SLv Zheng  *              table_index         - Where the table index is returned
8586dfc6f3SLv Zheng  *
8686dfc6f3SLv Zheng  * RETURN:      Status
8786dfc6f3SLv Zheng  *
88752db101SLv Zheng  * DESCRIPTION: This function is called to verify and install an ACPI table.
8986dfc6f3SLv Zheng  *              When this function is called by "Load" or "LoadTable" opcodes,
9086dfc6f3SLv Zheng  *              or by acpi_load_table() API, the "Reload" parameter is set.
91c2fa79b8SColin Ian King  *              After successfully returning from this function, table is
9286dfc6f3SLv Zheng  *              "INSTALLED" but not "VALIDATED".
9386dfc6f3SLv Zheng  *
9486dfc6f3SLv Zheng  ******************************************************************************/
9586dfc6f3SLv Zheng 
9686dfc6f3SLv Zheng acpi_status
97ed6f1d44SBob Moore acpi_tb_install_standard_table(acpi_physical_address address,
98caf4a15cSLv Zheng 			       u8 flags,
99caf4a15cSLv Zheng 			       u8 reload, u8 override, u32 *table_index)
10095b482a8SLen Brown {
10195b482a8SLen Brown 	u32 i;
10295b482a8SLen Brown 	acpi_status status = AE_OK;
10386dfc6f3SLv Zheng 	struct acpi_table_desc new_table_desc;
10495b482a8SLen Brown 
105ed6f1d44SBob Moore 	ACPI_FUNCTION_TRACE(tb_install_standard_table);
10695b482a8SLen Brown 
107ed6f1d44SBob Moore 	/* Acquire a temporary table descriptor for validation */
10886dfc6f3SLv Zheng 
109ed6f1d44SBob Moore 	status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags);
11086dfc6f3SLv Zheng 	if (ACPI_FAILURE(status)) {
111cc2080b0SLv Zheng 		ACPI_ERROR((AE_INFO,
112cc2080b0SLv Zheng 			    "Could not acquire table length at %8.8X%8.8X",
113cc2080b0SLv Zheng 			    ACPI_FORMAT_UINT64(address)));
11495b482a8SLen Brown 		return_ACPI_STATUS(status);
11595b482a8SLen Brown 	}
11686dfc6f3SLv Zheng 
117a94e88cdSLv Zheng 	/*
118a94e88cdSLv Zheng 	 * Optionally do not load any SSDTs from the RSDT/XSDT. This can
119a94e88cdSLv Zheng 	 * be useful for debugging ACPI problems on some machines.
120a94e88cdSLv Zheng 	 */
121ed6f1d44SBob Moore 	if (!reload &&
122ed6f1d44SBob Moore 	    acpi_gbl_disable_ssdt_table_install &&
123*5599fb69SBob Moore 	    ACPI_COMPARE_NAMESEG(&new_table_desc.signature, ACPI_SIG_SSDT)) {
12405fb04b5SBob Moore 		ACPI_INFO(("Ignoring installation of %4.4s at %8.8X%8.8X",
1256d3fd3ccSLv Zheng 			   new_table_desc.signature.ascii,
126cc2080b0SLv Zheng 			   ACPI_FORMAT_UINT64(address)));
127a94e88cdSLv Zheng 		goto release_and_exit;
128a94e88cdSLv Zheng 	}
129a94e88cdSLv Zheng 
1307a37052aSLv Zheng 	/* Acquire the table lock */
1317a37052aSLv Zheng 
1327a37052aSLv Zheng 	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
1337a37052aSLv Zheng 
134f9d472eeSLv Zheng 	/* Validate and verify a table before installation */
13595b482a8SLen Brown 
136f9d472eeSLv Zheng 	status = acpi_tb_verify_temp_table(&new_table_desc, NULL, &i);
137f9d472eeSLv Zheng 	if (ACPI_FAILURE(status)) {
138f9d472eeSLv Zheng 		if (status == AE_CTRL_TERMINATE) {
139d3ccaff8SBob Moore 			/*
14086dfc6f3SLv Zheng 			 * Table was unloaded, allow it to be reloaded.
14186dfc6f3SLv Zheng 			 * As we are going to return AE_OK to the caller, we should
14286dfc6f3SLv Zheng 			 * take the responsibility of freeing the input descriptor.
14386dfc6f3SLv Zheng 			 * Refill the input descriptor to ensure
144ed6f1d44SBob Moore 			 * acpi_tb_install_table_with_override() can be called again to
14586dfc6f3SLv Zheng 			 * indicate the re-installation.
146d3ccaff8SBob Moore 			 */
14786dfc6f3SLv Zheng 			acpi_tb_uninstall_table(&new_table_desc);
1487a37052aSLv Zheng 			(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
14986dfc6f3SLv Zheng 			*table_index = i;
15086dfc6f3SLv Zheng 			return_ACPI_STATUS(AE_OK);
15186dfc6f3SLv Zheng 		}
152f9d472eeSLv Zheng 		goto unlock_and_exit;
1537f9fc99cSLv Zheng 	}
154d3ccaff8SBob Moore 
15595b482a8SLen Brown 	/* Add the table to the global root table list */
15695b482a8SLen Brown 
1578ec3f459SLv Zheng 	acpi_tb_install_table_with_override(&new_table_desc, override,
1588ec3f459SLv Zheng 					    table_index);
15995b482a8SLen Brown 
1609b019b0fSLv Zheng 	/* Invoke table handler */
161bdbe5df0SLv Zheng 
1627a37052aSLv Zheng 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
1639b019b0fSLv Zheng 	acpi_tb_notify_table(ACPI_TABLE_EVENT_INSTALL, new_table_desc.pointer);
1647a37052aSLv Zheng 	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
1657a37052aSLv Zheng 
1667a37052aSLv Zheng unlock_and_exit:
1677a37052aSLv Zheng 
1687a37052aSLv Zheng 	/* Release the table lock */
1697a37052aSLv Zheng 
1707a37052aSLv Zheng 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
171bdbe5df0SLv Zheng 
17286dfc6f3SLv Zheng release_and_exit:
17395b482a8SLen Brown 
174ed6f1d44SBob Moore 	/* Release the temporary table descriptor */
17586dfc6f3SLv Zheng 
176ed6f1d44SBob Moore 	acpi_tb_release_temp_table(&new_table_desc);
17795b482a8SLen Brown 	return_ACPI_STATUS(status);
17895b482a8SLen Brown }
17995b482a8SLen Brown 
18095b482a8SLen Brown /*******************************************************************************
18195b482a8SLen Brown  *
1827f9fc99cSLv Zheng  * FUNCTION:    acpi_tb_override_table
183f7b004a1SBob Moore  *
18486dfc6f3SLv Zheng  * PARAMETERS:  old_table_desc      - Validated table descriptor to be
18586dfc6f3SLv Zheng  *                                    overridden
186f7b004a1SBob Moore  *
18786dfc6f3SLv Zheng  * RETURN:      None
188f7b004a1SBob Moore  *
189f7b004a1SBob Moore  * DESCRIPTION: Attempt table override by calling the OSL override functions.
190f7b004a1SBob Moore  *              Note: If the table is overridden, then the entire new table
1917f9fc99cSLv Zheng  *              is acquired and returned by this function.
19286dfc6f3SLv Zheng  *              Before/after invocation, the table descriptor is in a state
19386dfc6f3SLv Zheng  *              that is "VALIDATED".
194f7b004a1SBob Moore  *
195f7b004a1SBob Moore  ******************************************************************************/
196f7b004a1SBob Moore 
19786dfc6f3SLv Zheng void acpi_tb_override_table(struct acpi_table_desc *old_table_desc)
198f7b004a1SBob Moore {
199f7b004a1SBob Moore 	acpi_status status;
2007f9fc99cSLv Zheng 	struct acpi_table_desc new_table_desc;
20186dfc6f3SLv Zheng 	struct acpi_table_header *table;
20286dfc6f3SLv Zheng 	acpi_physical_address address;
20386dfc6f3SLv Zheng 	u32 length;
2040fe0bebfSErik Schmauss 	ACPI_ERROR_ONLY(char *override_type);
205f7b004a1SBob Moore 
206f7b004a1SBob Moore 	/* (1) Attempt logical override (returns a logical address) */
207f7b004a1SBob Moore 
20886dfc6f3SLv Zheng 	status = acpi_os_table_override(old_table_desc->pointer, &table);
20986dfc6f3SLv Zheng 	if (ACPI_SUCCESS(status) && table) {
210ed6f1d44SBob Moore 		acpi_tb_acquire_temp_table(&new_table_desc,
21186dfc6f3SLv Zheng 					   ACPI_PTR_TO_PHYSADDR(table),
212ed6f1d44SBob Moore 					   ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL);
2130fe0bebfSErik Schmauss 		ACPI_ERROR_ONLY(override_type = "Logical");
214f7b004a1SBob Moore 		goto finish_override;
215f7b004a1SBob Moore 	}
216f7b004a1SBob Moore 
217f7b004a1SBob Moore 	/* (2) Attempt physical override (returns a physical address) */
218f7b004a1SBob Moore 
21986dfc6f3SLv Zheng 	status = acpi_os_physical_table_override(old_table_desc->pointer,
22086dfc6f3SLv Zheng 						 &address, &length);
22186dfc6f3SLv Zheng 	if (ACPI_SUCCESS(status) && address && length) {
222ed6f1d44SBob Moore 		acpi_tb_acquire_temp_table(&new_table_desc, address,
223ed6f1d44SBob Moore 					   ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL);
2240fe0bebfSErik Schmauss 		ACPI_ERROR_ONLY(override_type = "Physical");
225f7b004a1SBob Moore 		goto finish_override;
226f7b004a1SBob Moore 	}
227f7b004a1SBob Moore 
22886dfc6f3SLv Zheng 	return;			/* There was no override */
229f7b004a1SBob Moore 
230f7b004a1SBob Moore finish_override:
231f7b004a1SBob Moore 
232f9d472eeSLv Zheng 	/*
233f9d472eeSLv Zheng 	 * Validate and verify a table before overriding, no nested table
234f9d472eeSLv Zheng 	 * duplication check as it's too complicated and unnecessary.
235f9d472eeSLv Zheng 	 */
236f9d472eeSLv Zheng 	status = acpi_tb_verify_temp_table(&new_table_desc, NULL, NULL);
2377f9fc99cSLv Zheng 	if (ACPI_FAILURE(status)) {
23886dfc6f3SLv Zheng 		return;
2397f9fc99cSLv Zheng 	}
2407f9fc99cSLv Zheng 
24105fb04b5SBob Moore 	ACPI_INFO(("%4.4s 0x%8.8X%8.8X"
2421d0a0b2fSLv Zheng 		   " %s table override, new table: 0x%8.8X%8.8X",
24386dfc6f3SLv Zheng 		   old_table_desc->signature.ascii,
2441d0a0b2fSLv Zheng 		   ACPI_FORMAT_UINT64(old_table_desc->address),
2451d0a0b2fSLv Zheng 		   override_type, ACPI_FORMAT_UINT64(new_table_desc.address)));
246f7b004a1SBob Moore 
24786dfc6f3SLv Zheng 	/* We can now uninstall the original table */
248f7b004a1SBob Moore 
24986dfc6f3SLv Zheng 	acpi_tb_uninstall_table(old_table_desc);
250f7b004a1SBob Moore 
25186dfc6f3SLv Zheng 	/*
25286dfc6f3SLv Zheng 	 * Replace the original table descriptor and keep its state as
25386dfc6f3SLv Zheng 	 * "VALIDATED".
25486dfc6f3SLv Zheng 	 */
255ed6f1d44SBob Moore 	acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address,
256ed6f1d44SBob Moore 				      new_table_desc.flags,
257ed6f1d44SBob Moore 				      new_table_desc.pointer);
25847d68c7fSLv Zheng 	acpi_tb_validate_temp_table(old_table_desc);
259f7b004a1SBob Moore 
260ed6f1d44SBob Moore 	/* Release the temporary table descriptor */
261f7b004a1SBob Moore 
262ed6f1d44SBob Moore 	acpi_tb_release_temp_table(&new_table_desc);
263f7b004a1SBob Moore }
264f7b004a1SBob Moore 
265f7b004a1SBob Moore /*******************************************************************************
266f7b004a1SBob Moore  *
2677f9fc99cSLv Zheng  * FUNCTION:    acpi_tb_uninstall_table
26895b482a8SLen Brown  *
2697f9fc99cSLv Zheng  * PARAMETERS:  table_desc          - Table descriptor
27095b482a8SLen Brown  *
27195b482a8SLen Brown  * RETURN:      None
27295b482a8SLen Brown  *
27395b482a8SLen Brown  * DESCRIPTION: Delete one internal ACPI table
27495b482a8SLen Brown  *
27595b482a8SLen Brown  ******************************************************************************/
27695b482a8SLen Brown 
2777f9fc99cSLv Zheng void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc)
27895b482a8SLen Brown {
2795582982dSLv Zheng 
2807f9fc99cSLv Zheng 	ACPI_FUNCTION_TRACE(tb_uninstall_table);
2815582982dSLv Zheng 
2827f9fc99cSLv Zheng 	/* Table must be installed */
2837f9fc99cSLv Zheng 
2847f9fc99cSLv Zheng 	if (!table_desc->address) {
2857f9fc99cSLv Zheng 		return_VOID;
28695b482a8SLen Brown 	}
2875582982dSLv Zheng 
2887f9fc99cSLv Zheng 	acpi_tb_invalidate_table(table_desc);
2891d1ea1b7SChao Guan 
2907f9fc99cSLv Zheng 	if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
291ed6f1d44SBob Moore 	    ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) {
2926d3fd3ccSLv Zheng 		ACPI_FREE(ACPI_PHYSADDR_TO_PTR(table_desc->address));
2937f9fc99cSLv Zheng 	}
2941d1ea1b7SChao Guan 
295dc156adfSLv Zheng 	table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL);
2967f9fc99cSLv Zheng 	return_VOID;
29795b482a8SLen Brown }
298