1/******************************************************************************
2 *
3 * Module Name: utaddress - OpRegion address range check
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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#define __UTADDRESS_C__
45
46#include <contrib/dev/acpica/include/acpi.h>
47#include <contrib/dev/acpica/include/accommon.h>
48#include <contrib/dev/acpica/include/acnamesp.h>
49
50
51#define _COMPONENT          ACPI_UTILITIES
52        ACPI_MODULE_NAME    ("utaddress")
53
54
55/*******************************************************************************
56 *
57 * FUNCTION:    AcpiUtAddAddressRange
58 *
59 * PARAMETERS:  SpaceId             - Address space ID
60 *              Address             - OpRegion start address
61 *              Length              - OpRegion length
62 *              RegionNode          - OpRegion namespace node
63 *
64 * RETURN:      Status
65 *
66 * DESCRIPTION: Add the Operation Region address range to the global list.
67 *              The only supported Space IDs are Memory and I/O. Called when
68 *              the OpRegion address/length operands are fully evaluated.
69 *
70 * MUTEX:       Locks the namespace
71 *
72 * NOTE: Because this interface is only called when an OpRegion argument
73 * list is evaluated, there cannot be any duplicate RegionNodes.
74 * Duplicate Address/Length values are allowed, however, so that multiple
75 * address conflicts can be detected.
76 *
77 ******************************************************************************/
78
79ACPI_STATUS
80AcpiUtAddAddressRange (
81    ACPI_ADR_SPACE_TYPE     SpaceId,
82    ACPI_PHYSICAL_ADDRESS   Address,
83    UINT32                  Length,
84    ACPI_NAMESPACE_NODE     *RegionNode)
85{
86    ACPI_ADDRESS_RANGE      *RangeInfo;
87    ACPI_STATUS             Status;
88
89
90    ACPI_FUNCTION_TRACE (UtAddAddressRange);
91
92
93    if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
94        (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
95    {
96        return_ACPI_STATUS (AE_OK);
97    }
98
99    /* Allocate/init a new info block, add it to the appropriate list */
100
101    RangeInfo = ACPI_ALLOCATE (sizeof (ACPI_ADDRESS_RANGE));
102    if (!RangeInfo)
103    {
104        return_ACPI_STATUS (AE_NO_MEMORY);
105    }
106
107    RangeInfo->StartAddress = Address;
108    RangeInfo->EndAddress = (Address + Length - 1);
109    RangeInfo->RegionNode = RegionNode;
110
111    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
112    if (ACPI_FAILURE (Status))
113    {
114        ACPI_FREE (RangeInfo);
115        return_ACPI_STATUS (Status);
116    }
117
118    RangeInfo->Next = AcpiGbl_AddressRangeList[SpaceId];
119    AcpiGbl_AddressRangeList[SpaceId] = RangeInfo;
120
121    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
122        "\nAdded [%4.4s] address range: 0x%p-0x%p\n",
123        AcpiUtGetNodeName (RangeInfo->RegionNode),
124        ACPI_CAST_PTR (void, Address),
125        ACPI_CAST_PTR (void, RangeInfo->EndAddress)));
126
127    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
128    return_ACPI_STATUS (AE_OK);
129}
130
131
132/*******************************************************************************
133 *
134 * FUNCTION:    AcpiUtRemoveAddressRange
135 *
136 * PARAMETERS:  SpaceId             - Address space ID
137 *              RegionNode          - OpRegion namespace node
138 *
139 * RETURN:      None
140 *
141 * DESCRIPTION: Remove the Operation Region from the global list. The only
142 *              supported Space IDs are Memory and I/O. Called when an
143 *              OpRegion is deleted.
144 *
145 * MUTEX:       Assumes the namespace is locked
146 *
147 ******************************************************************************/
148
149void
150AcpiUtRemoveAddressRange (
151    ACPI_ADR_SPACE_TYPE     SpaceId,
152    ACPI_NAMESPACE_NODE     *RegionNode)
153{
154    ACPI_ADDRESS_RANGE      *RangeInfo;
155    ACPI_ADDRESS_RANGE      *Prev;
156
157
158    ACPI_FUNCTION_TRACE (UtRemoveAddressRange);
159
160
161    if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
162        (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
163    {
164        return_VOID;
165    }
166
167    /* Get the appropriate list head and check the list */
168
169    RangeInfo = Prev = AcpiGbl_AddressRangeList[SpaceId];
170    while (RangeInfo)
171    {
172        if (RangeInfo->RegionNode == RegionNode)
173        {
174            if (RangeInfo == Prev) /* Found at list head */
175            {
176                AcpiGbl_AddressRangeList[SpaceId] = RangeInfo->Next;
177            }
178            else
179            {
180                Prev->Next = RangeInfo->Next;
181            }
182
183            ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
184                "\nRemoved [%4.4s] address range: 0x%p-0x%p\n",
185                AcpiUtGetNodeName (RangeInfo->RegionNode),
186                ACPI_CAST_PTR (void, RangeInfo->StartAddress),
187                ACPI_CAST_PTR (void, RangeInfo->EndAddress)));
188
189            ACPI_FREE (RangeInfo);
190            return_VOID;
191        }
192
193        Prev = RangeInfo;
194        RangeInfo = RangeInfo->Next;
195    }
196
197    return_VOID;
198}
199
200
201/*******************************************************************************
202 *
203 * FUNCTION:    AcpiUtCheckAddressRange
204 *
205 * PARAMETERS:  SpaceId             - Address space ID
206 *              Address             - Start address
207 *              Length              - Length of address range
208 *              Warn                - TRUE if warning on overlap desired
209 *
210 * RETURN:      Count of the number of conflicts detected. Zero is always
211 *              returned for Space IDs other than Memory or I/O.
212 *
213 * DESCRIPTION: Check if the input address range overlaps any of the
214 *              ASL operation region address ranges. The only supported
215 *              Space IDs are Memory and I/O.
216 *
217 * MUTEX:       Assumes the namespace is locked.
218 *
219 ******************************************************************************/
220
221UINT32
222AcpiUtCheckAddressRange (
223    ACPI_ADR_SPACE_TYPE     SpaceId,
224    ACPI_PHYSICAL_ADDRESS   Address,
225    UINT32                  Length,
226    BOOLEAN                 Warn)
227{
228    ACPI_ADDRESS_RANGE      *RangeInfo;
229    ACPI_PHYSICAL_ADDRESS   EndAddress;
230    char                    *Pathname;
231    UINT32                  OverlapCount = 0;
232
233
234    ACPI_FUNCTION_TRACE (UtCheckAddressRange);
235
236
237    if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
238        (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
239    {
240        return_UINT32 (0);
241    }
242
243    RangeInfo = AcpiGbl_AddressRangeList[SpaceId];
244    EndAddress = Address + Length - 1;
245
246    /* Check entire list for all possible conflicts */
247
248    while (RangeInfo)
249    {
250        /*
251         * Check if the requested Address/Length overlaps this AddressRange.
252         * Four cases to consider:
253         *
254         * 1) Input address/length is contained completely in the address range
255         * 2) Input address/length overlaps range at the range start
256         * 3) Input address/length overlaps range at the range end
257         * 4) Input address/length completely encompasses the range
258         */
259        if ((Address <= RangeInfo->EndAddress) &&
260            (EndAddress >= RangeInfo->StartAddress))
261        {
262            /* Found an address range overlap */
263
264            OverlapCount++;
265            if (Warn)   /* Optional warning message */
266            {
267                Pathname = AcpiNsGetExternalPathname (RangeInfo->RegionNode);
268
269                ACPI_WARNING ((AE_INFO,
270                    "0x%p-0x%p %s conflicts with Region %s %d",
271                    ACPI_CAST_PTR (void, Address),
272                    ACPI_CAST_PTR (void, EndAddress),
273                    AcpiUtGetRegionName (SpaceId), Pathname, OverlapCount));
274                ACPI_FREE (Pathname);
275            }
276        }
277
278        RangeInfo = RangeInfo->Next;
279    }
280
281    return_UINT32 (OverlapCount);
282}
283
284
285/*******************************************************************************
286 *
287 * FUNCTION:    AcpiUtDeleteAddressLists
288 *
289 * PARAMETERS:  None
290 *
291 * RETURN:      None
292 *
293 * DESCRIPTION: Delete all global address range lists (called during
294 *              subsystem shutdown).
295 *
296 ******************************************************************************/
297
298void
299AcpiUtDeleteAddressLists (
300    void)
301{
302    ACPI_ADDRESS_RANGE      *Next;
303    ACPI_ADDRESS_RANGE      *RangeInfo;
304    int                     i;
305
306
307    /* Delete all elements in all address range lists */
308
309    for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++)
310    {
311        Next = AcpiGbl_AddressRangeList[i];
312
313        while (Next)
314        {
315            RangeInfo = Next;
316            Next = RangeInfo->Next;
317            ACPI_FREE (RangeInfo);
318        }
319
320        AcpiGbl_AddressRangeList[i] = NULL;
321    }
322}
323