xref: /linux/drivers/acpi/acpica/utaddress.c (revision 25f044e64568dd83de34c16c837a96bbb2b0cecb)
1f654c0feSLin Ming /******************************************************************************
2f654c0feSLin Ming  *
3f654c0feSLin Ming  * Module Name: utaddress - op_region address range check
4f654c0feSLin Ming  *
5f654c0feSLin Ming  *****************************************************************************/
6f654c0feSLin Ming 
7f654c0feSLin Ming /*
8*25f044e6SBob Moore  * Copyright (C) 2000 - 2013, Intel Corp.
9f654c0feSLin Ming  * All rights reserved.
10f654c0feSLin Ming  *
11f654c0feSLin Ming  * Redistribution and use in source and binary forms, with or without
12f654c0feSLin Ming  * modification, are permitted provided that the following conditions
13f654c0feSLin Ming  * are met:
14f654c0feSLin Ming  * 1. Redistributions of source code must retain the above copyright
15f654c0feSLin Ming  *    notice, this list of conditions, and the following disclaimer,
16f654c0feSLin Ming  *    without modification.
17f654c0feSLin Ming  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18f654c0feSLin Ming  *    substantially similar to the "NO WARRANTY" disclaimer below
19f654c0feSLin Ming  *    ("Disclaimer") and any redistribution must be conditioned upon
20f654c0feSLin Ming  *    including a substantially similar Disclaimer requirement for further
21f654c0feSLin Ming  *    binary redistribution.
22f654c0feSLin Ming  * 3. Neither the names of the above-listed copyright holders nor the names
23f654c0feSLin Ming  *    of any contributors may be used to endorse or promote products derived
24f654c0feSLin Ming  *    from this software without specific prior written permission.
25f654c0feSLin Ming  *
26f654c0feSLin Ming  * Alternatively, this software may be distributed under the terms of the
27f654c0feSLin Ming  * GNU General Public License ("GPL") version 2 as published by the Free
28f654c0feSLin Ming  * Software Foundation.
29f654c0feSLin Ming  *
30f654c0feSLin Ming  * NO WARRANTY
31f654c0feSLin Ming  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32f654c0feSLin Ming  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33f654c0feSLin Ming  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34f654c0feSLin Ming  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35f654c0feSLin Ming  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36f654c0feSLin Ming  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37f654c0feSLin Ming  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38f654c0feSLin Ming  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39f654c0feSLin Ming  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40f654c0feSLin Ming  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41f654c0feSLin Ming  * POSSIBILITY OF SUCH DAMAGES.
42f654c0feSLin Ming  */
43f654c0feSLin Ming 
44f654c0feSLin Ming #include <acpi/acpi.h>
45f654c0feSLin Ming #include "accommon.h"
46f654c0feSLin Ming #include "acnamesp.h"
47f654c0feSLin Ming 
48f654c0feSLin Ming #define _COMPONENT          ACPI_UTILITIES
49f654c0feSLin Ming ACPI_MODULE_NAME("utaddress")
50f654c0feSLin Ming 
51f654c0feSLin Ming /*******************************************************************************
52f654c0feSLin Ming  *
53f654c0feSLin Ming  * FUNCTION:    acpi_ut_add_address_range
54f654c0feSLin Ming  *
55f654c0feSLin Ming  * PARAMETERS:  space_id            - Address space ID
56ba494beeSBob Moore  *              address             - op_region start address
57ba494beeSBob Moore  *              length              - op_region length
58f654c0feSLin Ming  *              region_node         - op_region namespace node
59f654c0feSLin Ming  *
60f654c0feSLin Ming  * RETURN:      Status
61f654c0feSLin Ming  *
62f654c0feSLin Ming  * DESCRIPTION: Add the Operation Region address range to the global list.
63f654c0feSLin Ming  *              The only supported Space IDs are Memory and I/O. Called when
64f654c0feSLin Ming  *              the op_region address/length operands are fully evaluated.
65f654c0feSLin Ming  *
66f654c0feSLin Ming  * MUTEX:       Locks the namespace
67f654c0feSLin Ming  *
68f654c0feSLin Ming  * NOTE: Because this interface is only called when an op_region argument
69f654c0feSLin Ming  * list is evaluated, there cannot be any duplicate region_nodes.
70f654c0feSLin Ming  * Duplicate Address/Length values are allowed, however, so that multiple
71f654c0feSLin Ming  * address conflicts can be detected.
72f654c0feSLin Ming  *
73f654c0feSLin Ming  ******************************************************************************/
74f654c0feSLin Ming acpi_status
75f654c0feSLin Ming acpi_ut_add_address_range(acpi_adr_space_type space_id,
76f654c0feSLin Ming 			  acpi_physical_address address,
77f654c0feSLin Ming 			  u32 length, struct acpi_namespace_node *region_node)
78f654c0feSLin Ming {
79f654c0feSLin Ming 	struct acpi_address_range *range_info;
80f654c0feSLin Ming 	acpi_status status;
81f654c0feSLin Ming 
82f654c0feSLin Ming 	ACPI_FUNCTION_TRACE(ut_add_address_range);
83f654c0feSLin Ming 
84f654c0feSLin Ming 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
85f654c0feSLin Ming 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
86f654c0feSLin Ming 		return_ACPI_STATUS(AE_OK);
87f654c0feSLin Ming 	}
88f654c0feSLin Ming 
89f654c0feSLin Ming 	/* Allocate/init a new info block, add it to the appropriate list */
90f654c0feSLin Ming 
91f654c0feSLin Ming 	range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
92f654c0feSLin Ming 	if (!range_info) {
93f654c0feSLin Ming 		return_ACPI_STATUS(AE_NO_MEMORY);
94f654c0feSLin Ming 	}
95f654c0feSLin Ming 
96f654c0feSLin Ming 	range_info->start_address = address;
97f654c0feSLin Ming 	range_info->end_address = (address + length - 1);
98f654c0feSLin Ming 	range_info->region_node = region_node;
99f654c0feSLin Ming 
100f654c0feSLin Ming 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
101f654c0feSLin Ming 	if (ACPI_FAILURE(status)) {
102f654c0feSLin Ming 		ACPI_FREE(range_info);
103f654c0feSLin Ming 		return_ACPI_STATUS(status);
104f654c0feSLin Ming 	}
105f654c0feSLin Ming 
106f654c0feSLin Ming 	range_info->next = acpi_gbl_address_range_list[space_id];
107f654c0feSLin Ming 	acpi_gbl_address_range_list[space_id] = range_info;
108f654c0feSLin Ming 
109f654c0feSLin Ming 	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
110f654c0feSLin Ming 			  "\nAdded [%4.4s] address range: 0x%p-0x%p\n",
111f654c0feSLin Ming 			  acpi_ut_get_node_name(range_info->region_node),
112f654c0feSLin Ming 			  ACPI_CAST_PTR(void, address),
113f654c0feSLin Ming 			  ACPI_CAST_PTR(void, range_info->end_address)));
114f654c0feSLin Ming 
115f654c0feSLin Ming 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
116f654c0feSLin Ming 	return_ACPI_STATUS(AE_OK);
117f654c0feSLin Ming }
118f654c0feSLin Ming 
119f654c0feSLin Ming /*******************************************************************************
120f654c0feSLin Ming  *
121f654c0feSLin Ming  * FUNCTION:    acpi_ut_remove_address_range
122f654c0feSLin Ming  *
123f654c0feSLin Ming  * PARAMETERS:  space_id            - Address space ID
124f654c0feSLin Ming  *              region_node         - op_region namespace node
125f654c0feSLin Ming  *
126f654c0feSLin Ming  * RETURN:      None
127f654c0feSLin Ming  *
128f654c0feSLin Ming  * DESCRIPTION: Remove the Operation Region from the global list. The only
129f654c0feSLin Ming  *              supported Space IDs are Memory and I/O. Called when an
130f654c0feSLin Ming  *              op_region is deleted.
131f654c0feSLin Ming  *
132f654c0feSLin Ming  * MUTEX:       Assumes the namespace is locked
133f654c0feSLin Ming  *
134f654c0feSLin Ming  ******************************************************************************/
135f654c0feSLin Ming 
136f654c0feSLin Ming void
137f654c0feSLin Ming acpi_ut_remove_address_range(acpi_adr_space_type space_id,
138f654c0feSLin Ming 			     struct acpi_namespace_node *region_node)
139f654c0feSLin Ming {
140f654c0feSLin Ming 	struct acpi_address_range *range_info;
141f654c0feSLin Ming 	struct acpi_address_range *prev;
142f654c0feSLin Ming 
143f654c0feSLin Ming 	ACPI_FUNCTION_TRACE(ut_remove_address_range);
144f654c0feSLin Ming 
145f654c0feSLin Ming 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
146f654c0feSLin Ming 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
147f654c0feSLin Ming 		return_VOID;
148f654c0feSLin Ming 	}
149f654c0feSLin Ming 
150f654c0feSLin Ming 	/* Get the appropriate list head and check the list */
151f654c0feSLin Ming 
152f654c0feSLin Ming 	range_info = prev = acpi_gbl_address_range_list[space_id];
153f654c0feSLin Ming 	while (range_info) {
154f654c0feSLin Ming 		if (range_info->region_node == region_node) {
155f654c0feSLin Ming 			if (range_info == prev) {	/* Found at list head */
156f654c0feSLin Ming 				acpi_gbl_address_range_list[space_id] =
157f654c0feSLin Ming 				    range_info->next;
158f654c0feSLin Ming 			} else {
159f654c0feSLin Ming 				prev->next = range_info->next;
160f654c0feSLin Ming 			}
161f654c0feSLin Ming 
162f654c0feSLin Ming 			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
163f654c0feSLin Ming 					  "\nRemoved [%4.4s] address range: 0x%p-0x%p\n",
164f654c0feSLin Ming 					  acpi_ut_get_node_name(range_info->
165f654c0feSLin Ming 								region_node),
166f654c0feSLin Ming 					  ACPI_CAST_PTR(void,
167f654c0feSLin Ming 							range_info->
168f654c0feSLin Ming 							start_address),
169f654c0feSLin Ming 					  ACPI_CAST_PTR(void,
170f654c0feSLin Ming 							range_info->
171f654c0feSLin Ming 							end_address)));
172f654c0feSLin Ming 
173f654c0feSLin Ming 			ACPI_FREE(range_info);
174f654c0feSLin Ming 			return_VOID;
175f654c0feSLin Ming 		}
176f654c0feSLin Ming 
177f654c0feSLin Ming 		prev = range_info;
178f654c0feSLin Ming 		range_info = range_info->next;
179f654c0feSLin Ming 	}
180f654c0feSLin Ming 
181f654c0feSLin Ming 	return_VOID;
182f654c0feSLin Ming }
183f654c0feSLin Ming 
184f654c0feSLin Ming /*******************************************************************************
185f654c0feSLin Ming  *
186f654c0feSLin Ming  * FUNCTION:    acpi_ut_check_address_range
187f654c0feSLin Ming  *
188f654c0feSLin Ming  * PARAMETERS:  space_id            - Address space ID
189ba494beeSBob Moore  *              address             - Start address
190ba494beeSBob Moore  *              length              - Length of address range
191ba494beeSBob Moore  *              warn                - TRUE if warning on overlap desired
192f654c0feSLin Ming  *
193f654c0feSLin Ming  * RETURN:      Count of the number of conflicts detected. Zero is always
194f654c0feSLin Ming  *              returned for Space IDs other than Memory or I/O.
195f654c0feSLin Ming  *
196f654c0feSLin Ming  * DESCRIPTION: Check if the input address range overlaps any of the
197f654c0feSLin Ming  *              ASL operation region address ranges. The only supported
198f654c0feSLin Ming  *              Space IDs are Memory and I/O.
199f654c0feSLin Ming  *
200f654c0feSLin Ming  * MUTEX:       Assumes the namespace is locked.
201f654c0feSLin Ming  *
202f654c0feSLin Ming  ******************************************************************************/
203f654c0feSLin Ming 
204f654c0feSLin Ming u32
205f654c0feSLin Ming acpi_ut_check_address_range(acpi_adr_space_type space_id,
206f654c0feSLin Ming 			    acpi_physical_address address, u32 length, u8 warn)
207f654c0feSLin Ming {
208f654c0feSLin Ming 	struct acpi_address_range *range_info;
209f654c0feSLin Ming 	acpi_physical_address end_address;
210f654c0feSLin Ming 	char *pathname;
211f654c0feSLin Ming 	u32 overlap_count = 0;
212f654c0feSLin Ming 
213f654c0feSLin Ming 	ACPI_FUNCTION_TRACE(ut_check_address_range);
214f654c0feSLin Ming 
215f654c0feSLin Ming 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
216f654c0feSLin Ming 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
2177b891693SBob Moore 		return_VALUE(0);
218f654c0feSLin Ming 	}
219f654c0feSLin Ming 
220f654c0feSLin Ming 	range_info = acpi_gbl_address_range_list[space_id];
221f654c0feSLin Ming 	end_address = address + length - 1;
222f654c0feSLin Ming 
223f654c0feSLin Ming 	/* Check entire list for all possible conflicts */
224f654c0feSLin Ming 
225f654c0feSLin Ming 	while (range_info) {
226f654c0feSLin Ming 		/*
227f654c0feSLin Ming 		 * Check if the requested Address/Length overlaps this address_range.
228f654c0feSLin Ming 		 * Four cases to consider:
229f654c0feSLin Ming 		 *
230f654c0feSLin Ming 		 * 1) Input address/length is contained completely in the address range
231f654c0feSLin Ming 		 * 2) Input address/length overlaps range at the range start
232f654c0feSLin Ming 		 * 3) Input address/length overlaps range at the range end
233f654c0feSLin Ming 		 * 4) Input address/length completely encompasses the range
234f654c0feSLin Ming 		 */
235f654c0feSLin Ming 		if ((address <= range_info->end_address) &&
236f654c0feSLin Ming 		    (end_address >= range_info->start_address)) {
237f654c0feSLin Ming 
238f654c0feSLin Ming 			/* Found an address range overlap */
239f654c0feSLin Ming 
240f654c0feSLin Ming 			overlap_count++;
241f654c0feSLin Ming 			if (warn) {	/* Optional warning message */
242f654c0feSLin Ming 				pathname =
243f654c0feSLin Ming 				    acpi_ns_get_external_pathname(range_info->
244f654c0feSLin Ming 								  region_node);
245f654c0feSLin Ming 
246f654c0feSLin Ming 				ACPI_WARNING((AE_INFO,
247f654c0feSLin Ming 					      "0x%p-0x%p %s conflicts with Region %s %d",
248f654c0feSLin Ming 					      ACPI_CAST_PTR(void, address),
249f654c0feSLin Ming 					      ACPI_CAST_PTR(void, end_address),
250f654c0feSLin Ming 					      acpi_ut_get_region_name(space_id),
251f654c0feSLin Ming 					      pathname, overlap_count));
252f654c0feSLin Ming 				ACPI_FREE(pathname);
253f654c0feSLin Ming 			}
254f654c0feSLin Ming 		}
255f654c0feSLin Ming 
256f654c0feSLin Ming 		range_info = range_info->next;
257f654c0feSLin Ming 	}
258f654c0feSLin Ming 
2597b891693SBob Moore 	return_VALUE(overlap_count);
260f654c0feSLin Ming }
261f654c0feSLin Ming 
262f654c0feSLin Ming /*******************************************************************************
263f654c0feSLin Ming  *
264f654c0feSLin Ming  * FUNCTION:    acpi_ut_delete_address_lists
265f654c0feSLin Ming  *
266f654c0feSLin Ming  * PARAMETERS:  None
267f654c0feSLin Ming  *
268f654c0feSLin Ming  * RETURN:      None
269f654c0feSLin Ming  *
270f654c0feSLin Ming  * DESCRIPTION: Delete all global address range lists (called during
271f654c0feSLin Ming  *              subsystem shutdown).
272f654c0feSLin Ming  *
273f654c0feSLin Ming  ******************************************************************************/
274f654c0feSLin Ming 
275f654c0feSLin Ming void acpi_ut_delete_address_lists(void)
276f654c0feSLin Ming {
277f654c0feSLin Ming 	struct acpi_address_range *next;
278f654c0feSLin Ming 	struct acpi_address_range *range_info;
279f654c0feSLin Ming 	int i;
280f654c0feSLin Ming 
281f654c0feSLin Ming 	/* Delete all elements in all address range lists */
282f654c0feSLin Ming 
283f654c0feSLin Ming 	for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
284f654c0feSLin Ming 		next = acpi_gbl_address_range_list[i];
285f654c0feSLin Ming 
286f654c0feSLin Ming 		while (next) {
287f654c0feSLin Ming 			range_info = next;
288f654c0feSLin Ming 			next = range_info->next;
289f654c0feSLin Ming 			ACPI_FREE(range_info);
290f654c0feSLin Ming 		}
291f654c0feSLin Ming 
292f654c0feSLin Ming 		acpi_gbl_address_range_list[i] = NULL;
293f654c0feSLin Ming 	}
294f654c0feSLin Ming }
295