1229982Sjkim/******************************************************************************
2229982Sjkim *
3229982Sjkim * Module Name: utaddress - OpRegion address range check
4229982Sjkim *
5229982Sjkim *****************************************************************************/
6229982Sjkim
7229982Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9229982Sjkim * All rights reserved.
10229982Sjkim *
11229982Sjkim * Redistribution and use in source and binary forms, with or without
12229982Sjkim * modification, are permitted provided that the following conditions
13229982Sjkim * are met:
14229982Sjkim * 1. Redistributions of source code must retain the above copyright
15229982Sjkim *    notice, this list of conditions, and the following disclaimer,
16229982Sjkim *    without modification.
17229982Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18229982Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19229982Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20229982Sjkim *    including a substantially similar Disclaimer requirement for further
21229982Sjkim *    binary redistribution.
22229982Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23229982Sjkim *    of any contributors may be used to endorse or promote products derived
24229982Sjkim *    from this software without specific prior written permission.
25229982Sjkim *
26229982Sjkim * Alternatively, this software may be distributed under the terms of the
27229982Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28229982Sjkim * Software Foundation.
29229982Sjkim *
30229982Sjkim * NO WARRANTY
31229982Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32229982Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33229982Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34229982Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35229982Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36229982Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37229982Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38229982Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39229982Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40229982Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41229982Sjkim * POSSIBILITY OF SUCH DAMAGES.
42229982Sjkim */
43229982Sjkim
44229989Sjkim#include <contrib/dev/acpica/include/acpi.h>
45229989Sjkim#include <contrib/dev/acpica/include/accommon.h>
46229989Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
47229982Sjkim
48229982Sjkim
49229982Sjkim#define _COMPONENT          ACPI_UTILITIES
50229982Sjkim        ACPI_MODULE_NAME    ("utaddress")
51229982Sjkim
52229982Sjkim
53229982Sjkim/*******************************************************************************
54229982Sjkim *
55229982Sjkim * FUNCTION:    AcpiUtAddAddressRange
56229982Sjkim *
57229982Sjkim * PARAMETERS:  SpaceId             - Address space ID
58229982Sjkim *              Address             - OpRegion start address
59229982Sjkim *              Length              - OpRegion length
60229982Sjkim *              RegionNode          - OpRegion namespace node
61229982Sjkim *
62229982Sjkim * RETURN:      Status
63229982Sjkim *
64229982Sjkim * DESCRIPTION: Add the Operation Region address range to the global list.
65229982Sjkim *              The only supported Space IDs are Memory and I/O. Called when
66229982Sjkim *              the OpRegion address/length operands are fully evaluated.
67229982Sjkim *
68229982Sjkim * MUTEX:       Locks the namespace
69229982Sjkim *
70229982Sjkim * NOTE: Because this interface is only called when an OpRegion argument
71229982Sjkim * list is evaluated, there cannot be any duplicate RegionNodes.
72229982Sjkim * Duplicate Address/Length values are allowed, however, so that multiple
73229982Sjkim * address conflicts can be detected.
74229982Sjkim *
75229982Sjkim ******************************************************************************/
76229982Sjkim
77229982SjkimACPI_STATUS
78229982SjkimAcpiUtAddAddressRange (
79229982Sjkim    ACPI_ADR_SPACE_TYPE     SpaceId,
80229982Sjkim    ACPI_PHYSICAL_ADDRESS   Address,
81229982Sjkim    UINT32                  Length,
82229982Sjkim    ACPI_NAMESPACE_NODE     *RegionNode)
83229982Sjkim{
84229982Sjkim    ACPI_ADDRESS_RANGE      *RangeInfo;
85229982Sjkim    ACPI_STATUS             Status;
86229982Sjkim
87229982Sjkim
88229982Sjkim    ACPI_FUNCTION_TRACE (UtAddAddressRange);
89229982Sjkim
90229982Sjkim
91229982Sjkim    if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
92229982Sjkim        (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
93229982Sjkim    {
94229982Sjkim        return_ACPI_STATUS (AE_OK);
95229982Sjkim    }
96229982Sjkim
97229982Sjkim    /* Allocate/init a new info block, add it to the appropriate list */
98229982Sjkim
99229982Sjkim    RangeInfo = ACPI_ALLOCATE (sizeof (ACPI_ADDRESS_RANGE));
100229982Sjkim    if (!RangeInfo)
101229982Sjkim    {
102229982Sjkim        return_ACPI_STATUS (AE_NO_MEMORY);
103229982Sjkim    }
104229982Sjkim
105229982Sjkim    RangeInfo->StartAddress = Address;
106229982Sjkim    RangeInfo->EndAddress = (Address + Length - 1);
107229982Sjkim    RangeInfo->RegionNode = RegionNode;
108229982Sjkim
109229982Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
110229982Sjkim    if (ACPI_FAILURE (Status))
111229982Sjkim    {
112229982Sjkim        ACPI_FREE (RangeInfo);
113229982Sjkim        return_ACPI_STATUS (Status);
114229982Sjkim    }
115229982Sjkim
116229982Sjkim    RangeInfo->Next = AcpiGbl_AddressRangeList[SpaceId];
117229982Sjkim    AcpiGbl_AddressRangeList[SpaceId] = RangeInfo;
118229982Sjkim
119229982Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
120281687Sjkim        "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
121229982Sjkim        AcpiUtGetNodeName (RangeInfo->RegionNode),
122281687Sjkim        ACPI_FORMAT_UINT64 (Address),
123281687Sjkim        ACPI_FORMAT_UINT64 (RangeInfo->EndAddress)));
124229982Sjkim
125229982Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
126229982Sjkim    return_ACPI_STATUS (AE_OK);
127229982Sjkim}
128229982Sjkim
129229982Sjkim
130229982Sjkim/*******************************************************************************
131229982Sjkim *
132229982Sjkim * FUNCTION:    AcpiUtRemoveAddressRange
133229982Sjkim *
134229982Sjkim * PARAMETERS:  SpaceId             - Address space ID
135229982Sjkim *              RegionNode          - OpRegion namespace node
136229982Sjkim *
137229982Sjkim * RETURN:      None
138229982Sjkim *
139229982Sjkim * DESCRIPTION: Remove the Operation Region from the global list. The only
140229982Sjkim *              supported Space IDs are Memory and I/O. Called when an
141229982Sjkim *              OpRegion is deleted.
142229982Sjkim *
143229982Sjkim * MUTEX:       Assumes the namespace is locked
144229982Sjkim *
145229982Sjkim ******************************************************************************/
146229982Sjkim
147229982Sjkimvoid
148229982SjkimAcpiUtRemoveAddressRange (
149229982Sjkim    ACPI_ADR_SPACE_TYPE     SpaceId,
150229982Sjkim    ACPI_NAMESPACE_NODE     *RegionNode)
151229982Sjkim{
152229982Sjkim    ACPI_ADDRESS_RANGE      *RangeInfo;
153229982Sjkim    ACPI_ADDRESS_RANGE      *Prev;
154229982Sjkim
155229982Sjkim
156229982Sjkim    ACPI_FUNCTION_TRACE (UtRemoveAddressRange);
157229982Sjkim
158229982Sjkim
159229982Sjkim    if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
160229982Sjkim        (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
161229982Sjkim    {
162229982Sjkim        return_VOID;
163229982Sjkim    }
164229982Sjkim
165229982Sjkim    /* Get the appropriate list head and check the list */
166229982Sjkim
167229982Sjkim    RangeInfo = Prev = AcpiGbl_AddressRangeList[SpaceId];
168229982Sjkim    while (RangeInfo)
169229982Sjkim    {
170229982Sjkim        if (RangeInfo->RegionNode == RegionNode)
171229982Sjkim        {
172229982Sjkim            if (RangeInfo == Prev) /* Found at list head */
173229982Sjkim            {
174229982Sjkim                AcpiGbl_AddressRangeList[SpaceId] = RangeInfo->Next;
175229982Sjkim            }
176229982Sjkim            else
177229982Sjkim            {
178229982Sjkim                Prev->Next = RangeInfo->Next;
179229982Sjkim            }
180229982Sjkim
181229982Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
182281687Sjkim                "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
183229982Sjkim                AcpiUtGetNodeName (RangeInfo->RegionNode),
184281687Sjkim                ACPI_FORMAT_UINT64 (RangeInfo->StartAddress),
185281687Sjkim                ACPI_FORMAT_UINT64 (RangeInfo->EndAddress)));
186229982Sjkim
187229982Sjkim            ACPI_FREE (RangeInfo);
188229982Sjkim            return_VOID;
189229982Sjkim        }
190229982Sjkim
191229982Sjkim        Prev = RangeInfo;
192229982Sjkim        RangeInfo = RangeInfo->Next;
193229982Sjkim    }
194229982Sjkim
195229982Sjkim    return_VOID;
196229982Sjkim}
197229982Sjkim
198229982Sjkim
199229982Sjkim/*******************************************************************************
200229982Sjkim *
201229982Sjkim * FUNCTION:    AcpiUtCheckAddressRange
202229982Sjkim *
203229982Sjkim * PARAMETERS:  SpaceId             - Address space ID
204229982Sjkim *              Address             - Start address
205229982Sjkim *              Length              - Length of address range
206229982Sjkim *              Warn                - TRUE if warning on overlap desired
207229982Sjkim *
208229982Sjkim * RETURN:      Count of the number of conflicts detected. Zero is always
209229982Sjkim *              returned for Space IDs other than Memory or I/O.
210229982Sjkim *
211229982Sjkim * DESCRIPTION: Check if the input address range overlaps any of the
212229982Sjkim *              ASL operation region address ranges. The only supported
213229982Sjkim *              Space IDs are Memory and I/O.
214229982Sjkim *
215229982Sjkim * MUTEX:       Assumes the namespace is locked.
216229982Sjkim *
217229982Sjkim ******************************************************************************/
218229982Sjkim
219229982SjkimUINT32
220229982SjkimAcpiUtCheckAddressRange (
221229982Sjkim    ACPI_ADR_SPACE_TYPE     SpaceId,
222229982Sjkim    ACPI_PHYSICAL_ADDRESS   Address,
223229982Sjkim    UINT32                  Length,
224229982Sjkim    BOOLEAN                 Warn)
225229982Sjkim{
226229982Sjkim    ACPI_ADDRESS_RANGE      *RangeInfo;
227229982Sjkim    ACPI_PHYSICAL_ADDRESS   EndAddress;
228229982Sjkim    char                    *Pathname;
229229982Sjkim    UINT32                  OverlapCount = 0;
230229982Sjkim
231229982Sjkim
232229982Sjkim    ACPI_FUNCTION_TRACE (UtCheckAddressRange);
233229982Sjkim
234229982Sjkim
235229982Sjkim    if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
236229982Sjkim        (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
237229982Sjkim    {
238246849Sjkim        return_UINT32 (0);
239229982Sjkim    }
240229982Sjkim
241229982Sjkim    RangeInfo = AcpiGbl_AddressRangeList[SpaceId];
242229982Sjkim    EndAddress = Address + Length - 1;
243229982Sjkim
244229982Sjkim    /* Check entire list for all possible conflicts */
245229982Sjkim
246229982Sjkim    while (RangeInfo)
247229982Sjkim    {
248229982Sjkim        /*
249281075Sdim         * Check if the requested address/length overlaps this
250281075Sdim         * address range. There are four cases to consider:
251229982Sjkim         *
252281075Sdim         * 1) Input address/length is contained completely in the
253281075Sdim         *    address range
254229982Sjkim         * 2) Input address/length overlaps range at the range start
255229982Sjkim         * 3) Input address/length overlaps range at the range end
256229982Sjkim         * 4) Input address/length completely encompasses the range
257229982Sjkim         */
258229982Sjkim        if ((Address <= RangeInfo->EndAddress) &&
259229982Sjkim            (EndAddress >= RangeInfo->StartAddress))
260229982Sjkim        {
261229982Sjkim            /* Found an address range overlap */
262229982Sjkim
263229982Sjkim            OverlapCount++;
264229982Sjkim            if (Warn)   /* Optional warning message */
265229982Sjkim            {
266306536Sjkim                Pathname = AcpiNsGetNormalizedPathname (RangeInfo->RegionNode, TRUE);
267229982Sjkim
268229982Sjkim                ACPI_WARNING ((AE_INFO,
269281687Sjkim                    "%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)",
270281075Sdim                    AcpiUtGetRegionName (SpaceId),
271281687Sjkim                    ACPI_FORMAT_UINT64 (Address),
272281687Sjkim                    ACPI_FORMAT_UINT64 (EndAddress),
273281687Sjkim                    ACPI_FORMAT_UINT64 (RangeInfo->StartAddress),
274281687Sjkim                    ACPI_FORMAT_UINT64 (RangeInfo->EndAddress),
275281075Sdim                    Pathname));
276229982Sjkim                ACPI_FREE (Pathname);
277229982Sjkim            }
278229982Sjkim        }
279229982Sjkim
280229982Sjkim        RangeInfo = RangeInfo->Next;
281229982Sjkim    }
282229982Sjkim
283246849Sjkim    return_UINT32 (OverlapCount);
284229982Sjkim}
285229982Sjkim
286229982Sjkim
287229982Sjkim/*******************************************************************************
288229982Sjkim *
289229982Sjkim * FUNCTION:    AcpiUtDeleteAddressLists
290229982Sjkim *
291229982Sjkim * PARAMETERS:  None
292229982Sjkim *
293229982Sjkim * RETURN:      None
294229982Sjkim *
295229982Sjkim * DESCRIPTION: Delete all global address range lists (called during
296229982Sjkim *              subsystem shutdown).
297229982Sjkim *
298229982Sjkim ******************************************************************************/
299229982Sjkim
300229982Sjkimvoid
301229982SjkimAcpiUtDeleteAddressLists (
302229982Sjkim    void)
303229982Sjkim{
304229982Sjkim    ACPI_ADDRESS_RANGE      *Next;
305229982Sjkim    ACPI_ADDRESS_RANGE      *RangeInfo;
306229982Sjkim    int                     i;
307229982Sjkim
308229982Sjkim
309229982Sjkim    /* Delete all elements in all address range lists */
310229982Sjkim
311229982Sjkim    for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++)
312229982Sjkim    {
313229982Sjkim        Next = AcpiGbl_AddressRangeList[i];
314229982Sjkim
315229982Sjkim        while (Next)
316229982Sjkim        {
317229982Sjkim            RangeInfo = Next;
318229982Sjkim            Next = RangeInfo->Next;
319229982Sjkim            ACPI_FREE (RangeInfo);
320229982Sjkim        }
321229982Sjkim
322229982Sjkim        AcpiGbl_AddressRangeList[i] = NULL;
323229982Sjkim    }
324229982Sjkim}
325