linux/drivers/acpi/acpica/utaddress.c
<<
>>
Prefs
   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
  49ACPI_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 ******************************************************************************/
  74acpi_status
  75acpi_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        acpi_status status;
  81
  82        ACPI_FUNCTION_TRACE(ut_add_address_range);
  83
  84        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
  85            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
  86                return_ACPI_STATUS(AE_OK);
  87        }
  88
  89        /* Allocate/init a new info block, add it to the appropriate list */
  90
  91        range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
  92        if (!range_info) {
  93                return_ACPI_STATUS(AE_NO_MEMORY);
  94        }
  95
  96        range_info->start_address = address;
  97        range_info->end_address = (address + length - 1);
  98        range_info->region_node = region_node;
  99
 100        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 101        if (ACPI_FAILURE(status)) {
 102                ACPI_FREE(range_info);
 103                return_ACPI_STATUS(status);
 104        }
 105
 106        range_info->next = acpi_gbl_address_range_list[space_id];
 107        acpi_gbl_address_range_list[space_id] = range_info;
 108
 109        ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
 110                          "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
 111                          acpi_ut_get_node_name(range_info->region_node),
 112                          ACPI_FORMAT_UINT64(address),
 113                          ACPI_FORMAT_UINT64(range_info->end_address)));
 114
 115        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 116        return_ACPI_STATUS(AE_OK);
 117}
 118
 119/*******************************************************************************
 120 *
 121 * FUNCTION:    acpi_ut_remove_address_range
 122 *
 123 * PARAMETERS:  space_id            - Address space ID
 124 *              region_node         - op_region namespace node
 125 *
 126 * RETURN:      None
 127 *
 128 * DESCRIPTION: Remove the Operation Region from the global list. The only
 129 *              supported Space IDs are Memory and I/O. Called when an
 130 *              op_region is deleted.
 131 *
 132 * MUTEX:       Assumes the namespace is locked
 133 *
 134 ******************************************************************************/
 135
 136void
 137acpi_ut_remove_address_range(acpi_adr_space_type space_id,
 138                             struct acpi_namespace_node *region_node)
 139{
 140        struct acpi_address_range *range_info;
 141        struct acpi_address_range *prev;
 142
 143        ACPI_FUNCTION_TRACE(ut_remove_address_range);
 144
 145        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
 146            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
 147                return_VOID;
 148        }
 149
 150        /* Get the appropriate list head and check the list */
 151
 152        range_info = prev = acpi_gbl_address_range_list[space_id];
 153        while (range_info) {
 154                if (range_info->region_node == region_node) {
 155                        if (range_info == prev) {       /* Found at list head */
 156                                acpi_gbl_address_range_list[space_id] =
 157                                    range_info->next;
 158                        } else {
 159                                prev->next = range_info->next;
 160                        }
 161
 162                        ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
 163                                          "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
 164                                          acpi_ut_get_node_name(range_info->
 165                                                                region_node),
 166                                          ACPI_FORMAT_UINT64(range_info->
 167                                                             start_address),
 168                                          ACPI_FORMAT_UINT64(range_info->
 169                                                             end_address)));
 170
 171                        ACPI_FREE(range_info);
 172                        return_VOID;
 173                }
 174
 175                prev = range_info;
 176                range_info = range_info->next;
 177        }
 178
 179        return_VOID;
 180}
 181
 182/*******************************************************************************
 183 *
 184 * FUNCTION:    acpi_ut_check_address_range
 185 *
 186 * PARAMETERS:  space_id            - Address space ID
 187 *              address             - Start address
 188 *              length              - Length of address range
 189 *              warn                - TRUE if warning on overlap desired
 190 *
 191 * RETURN:      Count of the number of conflicts detected. Zero is always
 192 *              returned for Space IDs other than Memory or I/O.
 193 *
 194 * DESCRIPTION: Check if the input address range overlaps any of the
 195 *              ASL operation region address ranges. The only supported
 196 *              Space IDs are Memory and I/O.
 197 *
 198 * MUTEX:       Assumes the namespace is locked.
 199 *
 200 ******************************************************************************/
 201
 202u32
 203acpi_ut_check_address_range(acpi_adr_space_type space_id,
 204                            acpi_physical_address address, u32 length, u8 warn)
 205{
 206        struct acpi_address_range *range_info;
 207        acpi_physical_address end_address;
 208        char *pathname;
 209        u32 overlap_count = 0;
 210
 211        ACPI_FUNCTION_TRACE(ut_check_address_range);
 212
 213        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
 214            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
 215                return_UINT32(0);
 216        }
 217
 218        range_info = acpi_gbl_address_range_list[space_id];
 219        end_address = address + length - 1;
 220
 221        /* Check entire list for all possible conflicts */
 222
 223        while (range_info) {
 224                /*
 225                 * Check if the requested address/length overlaps this
 226                 * address range. There are four cases to consider:
 227                 *
 228                 * 1) Input address/length is contained completely in the
 229                 *    address range
 230                 * 2) Input address/length overlaps range at the range start
 231                 * 3) Input address/length overlaps range at the range end
 232                 * 4) Input address/length completely encompasses the range
 233                 */
 234                if ((address <= range_info->end_address) &&
 235                    (end_address >= range_info->start_address)) {
 236
 237                        /* Found an address range overlap */
 238
 239                        overlap_count++;
 240                        if (warn) {     /* Optional warning message */
 241                                pathname =
 242                                    acpi_ns_get_normalized_pathname(range_info->
 243                                                                    region_node,
 244                                                                    TRUE);
 245
 246                                ACPI_WARNING((AE_INFO,
 247                                              "%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)",
 248                                              acpi_ut_get_region_name(space_id),
 249                                              ACPI_FORMAT_UINT64(address),
 250                                              ACPI_FORMAT_UINT64(end_address),
 251                                              ACPI_FORMAT_UINT64(range_info->
 252                                                                 start_address),
 253                                              ACPI_FORMAT_UINT64(range_info->
 254                                                                 end_address),
 255                                              pathname));
 256                                ACPI_FREE(pathname);
 257                        }
 258                }
 259
 260                range_info = range_info->next;
 261        }
 262
 263        return_UINT32(overlap_count);
 264}
 265
 266/*******************************************************************************
 267 *
 268 * FUNCTION:    acpi_ut_delete_address_lists
 269 *
 270 * PARAMETERS:  None
 271 *
 272 * RETURN:      None
 273 *
 274 * DESCRIPTION: Delete all global address range lists (called during
 275 *              subsystem shutdown).
 276 *
 277 ******************************************************************************/
 278
 279void acpi_ut_delete_address_lists(void)
 280{
 281        struct acpi_address_range *next;
 282        struct acpi_address_range *range_info;
 283        int i;
 284
 285        /* Delete all elements in all address range lists */
 286
 287        for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
 288                next = acpi_gbl_address_range_list[i];
 289
 290                while (next) {
 291                        range_info = next;
 292                        next = range_info->next;
 293                        ACPI_FREE(range_info);
 294                }
 295
 296                acpi_gbl_address_range_list[i] = NULL;
 297        }
 298}
 299