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