xref: /linux/drivers/acpi/acpica/utaddress.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2f654c0feSLin Ming /******************************************************************************
3f654c0feSLin Ming  *
4f654c0feSLin Ming  * Module Name: utaddress - op_region address range check
5f654c0feSLin Ming  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
7f654c0feSLin Ming  *
895857638SErik Schmauss  *****************************************************************************/
9f654c0feSLin Ming 
10f654c0feSLin Ming #include <acpi/acpi.h>
11f654c0feSLin Ming #include "accommon.h"
12f654c0feSLin Ming #include "acnamesp.h"
13f654c0feSLin Ming 
14f654c0feSLin Ming #define _COMPONENT          ACPI_UTILITIES
15f654c0feSLin Ming ACPI_MODULE_NAME("utaddress")
16f654c0feSLin Ming 
17f654c0feSLin Ming /*******************************************************************************
18f654c0feSLin Ming  *
19f654c0feSLin Ming  * FUNCTION:    acpi_ut_add_address_range
20f654c0feSLin Ming  *
21f654c0feSLin Ming  * PARAMETERS:  space_id            - Address space ID
22ba494beeSBob Moore  *              address             - op_region start address
23ba494beeSBob Moore  *              length              - op_region length
24f654c0feSLin Ming  *              region_node         - op_region namespace node
25f654c0feSLin Ming  *
26f654c0feSLin Ming  * RETURN:      Status
27f654c0feSLin Ming  *
28f654c0feSLin Ming  * DESCRIPTION: Add the Operation Region address range to the global list.
29f654c0feSLin Ming  *              The only supported Space IDs are Memory and I/O. Called when
30f654c0feSLin Ming  *              the op_region address/length operands are fully evaluated.
31f654c0feSLin Ming  *
32f654c0feSLin Ming  * MUTEX:       Locks the namespace
33f654c0feSLin Ming  *
34f654c0feSLin Ming  * NOTE: Because this interface is only called when an op_region argument
35f654c0feSLin Ming  * list is evaluated, there cannot be any duplicate region_nodes.
36f654c0feSLin Ming  * Duplicate Address/Length values are allowed, however, so that multiple
37f654c0feSLin Ming  * address conflicts can be detected.
38f654c0feSLin Ming  *
39f654c0feSLin Ming  ******************************************************************************/
40f654c0feSLin Ming acpi_status
acpi_ut_add_address_range(acpi_adr_space_type space_id,acpi_physical_address address,u32 length,struct acpi_namespace_node * region_node)41f654c0feSLin Ming acpi_ut_add_address_range(acpi_adr_space_type space_id,
42f654c0feSLin Ming 			  acpi_physical_address address,
43f654c0feSLin Ming 			  u32 length, struct acpi_namespace_node *region_node)
44f654c0feSLin Ming {
45f654c0feSLin Ming 	struct acpi_address_range *range_info;
46f654c0feSLin Ming 
47f654c0feSLin Ming 	ACPI_FUNCTION_TRACE(ut_add_address_range);
48f654c0feSLin Ming 
49f654c0feSLin Ming 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
50f654c0feSLin Ming 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
51f654c0feSLin Ming 		return_ACPI_STATUS(AE_OK);
52f654c0feSLin Ming 	}
53f654c0feSLin Ming 
54f654c0feSLin Ming 	/* Allocate/init a new info block, add it to the appropriate list */
55f654c0feSLin Ming 
56f654c0feSLin Ming 	range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
57f654c0feSLin Ming 	if (!range_info) {
58f654c0feSLin Ming 		return_ACPI_STATUS(AE_NO_MEMORY);
59f654c0feSLin Ming 	}
60f654c0feSLin Ming 
61f654c0feSLin Ming 	range_info->start_address = address;
62f654c0feSLin Ming 	range_info->end_address = (address + length - 1);
63f654c0feSLin Ming 	range_info->region_node = region_node;
64f654c0feSLin Ming 
65f654c0feSLin Ming 	range_info->next = acpi_gbl_address_range_list[space_id];
66f654c0feSLin Ming 	acpi_gbl_address_range_list[space_id] = range_info;
67f654c0feSLin Ming 
68f654c0feSLin Ming 	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
69cc2080b0SLv Zheng 			  "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
70f654c0feSLin Ming 			  acpi_ut_get_node_name(range_info->region_node),
71cc2080b0SLv Zheng 			  ACPI_FORMAT_UINT64(address),
72cc2080b0SLv Zheng 			  ACPI_FORMAT_UINT64(range_info->end_address)));
73f654c0feSLin Ming 
74f654c0feSLin Ming 	return_ACPI_STATUS(AE_OK);
75f654c0feSLin Ming }
76f654c0feSLin Ming 
77f654c0feSLin Ming /*******************************************************************************
78f654c0feSLin Ming  *
79f654c0feSLin Ming  * FUNCTION:    acpi_ut_remove_address_range
80f654c0feSLin Ming  *
81f654c0feSLin Ming  * PARAMETERS:  space_id            - Address space ID
82f654c0feSLin Ming  *              region_node         - op_region namespace node
83f654c0feSLin Ming  *
84f654c0feSLin Ming  * RETURN:      None
85f654c0feSLin Ming  *
86f654c0feSLin Ming  * DESCRIPTION: Remove the Operation Region from the global list. The only
87f654c0feSLin Ming  *              supported Space IDs are Memory and I/O. Called when an
88f654c0feSLin Ming  *              op_region is deleted.
89f654c0feSLin Ming  *
90f654c0feSLin Ming  * MUTEX:       Assumes the namespace is locked
91f654c0feSLin Ming  *
92f654c0feSLin Ming  ******************************************************************************/
93f654c0feSLin Ming 
94f654c0feSLin Ming void
acpi_ut_remove_address_range(acpi_adr_space_type space_id,struct acpi_namespace_node * region_node)95f654c0feSLin Ming acpi_ut_remove_address_range(acpi_adr_space_type space_id,
96f654c0feSLin Ming 			     struct acpi_namespace_node *region_node)
97f654c0feSLin Ming {
98f654c0feSLin Ming 	struct acpi_address_range *range_info;
99f654c0feSLin Ming 	struct acpi_address_range *prev;
100f654c0feSLin Ming 
101f654c0feSLin Ming 	ACPI_FUNCTION_TRACE(ut_remove_address_range);
102f654c0feSLin Ming 
103f654c0feSLin Ming 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
104f654c0feSLin Ming 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
105f654c0feSLin Ming 		return_VOID;
106f654c0feSLin Ming 	}
107f654c0feSLin Ming 
108f654c0feSLin Ming 	/* Get the appropriate list head and check the list */
109f654c0feSLin Ming 
110f654c0feSLin Ming 	range_info = prev = acpi_gbl_address_range_list[space_id];
111f654c0feSLin Ming 	while (range_info) {
112f654c0feSLin Ming 		if (range_info->region_node == region_node) {
113f654c0feSLin Ming 			if (range_info == prev) {	/* Found at list head */
114f654c0feSLin Ming 				acpi_gbl_address_range_list[space_id] =
115f654c0feSLin Ming 				    range_info->next;
116f654c0feSLin Ming 			} else {
117f654c0feSLin Ming 				prev->next = range_info->next;
118f654c0feSLin Ming 			}
119f654c0feSLin Ming 
120f654c0feSLin Ming 			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
121cc2080b0SLv Zheng 					  "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
122f654c0feSLin Ming 					  acpi_ut_get_node_name(range_info->
123f654c0feSLin Ming 								region_node),
124cc2080b0SLv Zheng 					  ACPI_FORMAT_UINT64(range_info->
125f654c0feSLin Ming 							     start_address),
126cc2080b0SLv Zheng 					  ACPI_FORMAT_UINT64(range_info->
127f654c0feSLin Ming 							     end_address)));
128f654c0feSLin Ming 
129f654c0feSLin Ming 			ACPI_FREE(range_info);
130f654c0feSLin Ming 			return_VOID;
131f654c0feSLin Ming 		}
132f654c0feSLin Ming 
133f654c0feSLin Ming 		prev = range_info;
134f654c0feSLin Ming 		range_info = range_info->next;
135f654c0feSLin Ming 	}
136f654c0feSLin Ming 
137f654c0feSLin Ming 	return_VOID;
138f654c0feSLin Ming }
139f654c0feSLin Ming 
140f654c0feSLin Ming /*******************************************************************************
141f654c0feSLin Ming  *
142f654c0feSLin Ming  * FUNCTION:    acpi_ut_check_address_range
143f654c0feSLin Ming  *
144f654c0feSLin Ming  * PARAMETERS:  space_id            - Address space ID
145ba494beeSBob Moore  *              address             - Start address
146ba494beeSBob Moore  *              length              - Length of address range
147ba494beeSBob Moore  *              warn                - TRUE if warning on overlap desired
148f654c0feSLin Ming  *
149f654c0feSLin Ming  * RETURN:      Count of the number of conflicts detected. Zero is always
150f654c0feSLin Ming  *              returned for Space IDs other than Memory or I/O.
151f654c0feSLin Ming  *
152f654c0feSLin Ming  * DESCRIPTION: Check if the input address range overlaps any of the
153f654c0feSLin Ming  *              ASL operation region address ranges. The only supported
154f654c0feSLin Ming  *              Space IDs are Memory and I/O.
155f654c0feSLin Ming  *
156f654c0feSLin Ming  * MUTEX:       Assumes the namespace is locked.
157f654c0feSLin Ming  *
158f654c0feSLin Ming  ******************************************************************************/
159f654c0feSLin Ming 
160f654c0feSLin Ming u32
acpi_ut_check_address_range(acpi_adr_space_type space_id,acpi_physical_address address,u32 length,u8 warn)161f654c0feSLin Ming acpi_ut_check_address_range(acpi_adr_space_type space_id,
162f654c0feSLin Ming 			    acpi_physical_address address, u32 length, u8 warn)
163f654c0feSLin Ming {
164f654c0feSLin Ming 	struct acpi_address_range *range_info;
165f654c0feSLin Ming 	acpi_physical_address end_address;
166f654c0feSLin Ming 	char *pathname;
167f654c0feSLin Ming 	u32 overlap_count = 0;
168f654c0feSLin Ming 
169f654c0feSLin Ming 	ACPI_FUNCTION_TRACE(ut_check_address_range);
170f654c0feSLin Ming 
171f654c0feSLin Ming 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
172f654c0feSLin Ming 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
173fd1af712SBob Moore 		return_UINT32(0);
174f654c0feSLin Ming 	}
175f654c0feSLin Ming 
176f654c0feSLin Ming 	range_info = acpi_gbl_address_range_list[space_id];
177f654c0feSLin Ming 	end_address = address + length - 1;
178f654c0feSLin Ming 
179f654c0feSLin Ming 	/* Check entire list for all possible conflicts */
180f654c0feSLin Ming 
181f654c0feSLin Ming 	while (range_info) {
182f654c0feSLin Ming 		/*
1830f607cb5SBob Moore 		 * Check if the requested address/length overlaps this
1840f607cb5SBob Moore 		 * address range. There are four cases to consider:
185f654c0feSLin Ming 		 *
1860f607cb5SBob Moore 		 * 1) Input address/length is contained completely in the
1870f607cb5SBob Moore 		 *    address range
188f654c0feSLin Ming 		 * 2) Input address/length overlaps range at the range start
189f654c0feSLin Ming 		 * 3) Input address/length overlaps range at the range end
190f654c0feSLin Ming 		 * 4) Input address/length completely encompasses the range
191f654c0feSLin Ming 		 */
192f654c0feSLin Ming 		if ((address <= range_info->end_address) &&
193f654c0feSLin Ming 		    (end_address >= range_info->start_address)) {
194f654c0feSLin Ming 
195f654c0feSLin Ming 			/* Found an address range overlap */
196f654c0feSLin Ming 
197f654c0feSLin Ming 			overlap_count++;
198f654c0feSLin Ming 			if (warn) {	/* Optional warning message */
199f654c0feSLin Ming 				pathname =
2000e166e4fSLv Zheng 				    acpi_ns_get_normalized_pathname(range_info->
2010e166e4fSLv Zheng 								    region_node,
2020e166e4fSLv Zheng 								    TRUE);
203f654c0feSLin Ming 
204f654c0feSLin Ming 				ACPI_WARNING((AE_INFO,
205cc2080b0SLv Zheng 					      "%s range 0x%8.8X%8.8X-0x%8.8X%8.8X conflicts with OpRegion 0x%8.8X%8.8X-0x%8.8X%8.8X (%s)",
2060f607cb5SBob Moore 					      acpi_ut_get_region_name(space_id),
207cc2080b0SLv Zheng 					      ACPI_FORMAT_UINT64(address),
208cc2080b0SLv Zheng 					      ACPI_FORMAT_UINT64(end_address),
209cc2080b0SLv Zheng 					      ACPI_FORMAT_UINT64(range_info->
2100f607cb5SBob Moore 								 start_address),
211cc2080b0SLv Zheng 					      ACPI_FORMAT_UINT64(range_info->
2120f607cb5SBob Moore 								 end_address),
2130f607cb5SBob Moore 					      pathname));
214f654c0feSLin Ming 				ACPI_FREE(pathname);
215f654c0feSLin Ming 			}
216f654c0feSLin Ming 		}
217f654c0feSLin Ming 
218f654c0feSLin Ming 		range_info = range_info->next;
219f654c0feSLin Ming 	}
220f654c0feSLin Ming 
221fd1af712SBob Moore 	return_UINT32(overlap_count);
222f654c0feSLin Ming }
223f654c0feSLin Ming 
224f654c0feSLin Ming /*******************************************************************************
225f654c0feSLin Ming  *
226f654c0feSLin Ming  * FUNCTION:    acpi_ut_delete_address_lists
227f654c0feSLin Ming  *
228f654c0feSLin Ming  * PARAMETERS:  None
229f654c0feSLin Ming  *
230f654c0feSLin Ming  * RETURN:      None
231f654c0feSLin Ming  *
232f654c0feSLin Ming  * DESCRIPTION: Delete all global address range lists (called during
233f654c0feSLin Ming  *              subsystem shutdown).
234f654c0feSLin Ming  *
235f654c0feSLin Ming  ******************************************************************************/
236f654c0feSLin Ming 
acpi_ut_delete_address_lists(void)237f654c0feSLin Ming void acpi_ut_delete_address_lists(void)
238f654c0feSLin Ming {
239f654c0feSLin Ming 	struct acpi_address_range *next;
240f654c0feSLin Ming 	struct acpi_address_range *range_info;
241f654c0feSLin Ming 	int i;
242f654c0feSLin Ming 
243f654c0feSLin Ming 	/* Delete all elements in all address range lists */
244f654c0feSLin Ming 
245f654c0feSLin Ming 	for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
246f654c0feSLin Ming 		next = acpi_gbl_address_range_list[i];
247f654c0feSLin Ming 
248f654c0feSLin Ming 		while (next) {
249f654c0feSLin Ming 			range_info = next;
250f654c0feSLin Ming 			next = range_info->next;
251f654c0feSLin Ming 			ACPI_FREE(range_info);
252f654c0feSLin Ming 		}
253f654c0feSLin Ming 
254f654c0feSLin Ming 		acpi_gbl_address_range_list[i] = NULL;
255f654c0feSLin Ming 	}
256f654c0feSLin Ming }
257