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 - 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#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%p-0x%p\n",
 111                          acpi_ut_get_node_name(range_info->region_node),
 112                          ACPI_CAST_PTR(void, address),
 113                          ACPI_CAST_PTR(void, 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%p-0x%p\n",
 164                                          acpi_ut_get_node_name(range_info->
 165                                                                region_node),
 166                                          ACPI_CAST_PTR(void,
 167                                                        range_info->
 168                                                        start_address),
 169                                          ACPI_CAST_PTR(void,
 170                                                        range_info->
 171                                                        end_address)));
 172
 173                        ACPI_FREE(range_info);
 174                        return_VOID;
 175                }
 176
 177                prev = range_info;
 178                range_info = range_info->next;
 179        }
 180
 181        return_VOID;
 182}
 183
 184/*******************************************************************************
 185 *
 186 * FUNCTION:    acpi_ut_check_address_range
 187 *
 188 * PARAMETERS:  space_id            - Address space ID
 189 *              address             - Start address
 190 *              length              - Length of address range
 191 *              warn                - TRUE if warning on overlap desired
 192 *
 193 * RETURN:      Count of the number of conflicts detected. Zero is always
 194 *              returned for Space IDs other than Memory or I/O.
 195 *
 196 * DESCRIPTION: Check if the input address range overlaps any of the
 197 *              ASL operation region address ranges. The only supported
 198 *              Space IDs are Memory and I/O.
 199 *
 200 * MUTEX:       Assumes the namespace is locked.
 201 *
 202 ******************************************************************************/
 203
 204u32
 205acpi_ut_check_address_range(acpi_adr_space_type space_id,
 206                            acpi_physical_address address, u32 length, u8 warn)
 207{
 208        struct acpi_address_range *range_info;
 209        acpi_physical_address end_address;
 210        char *pathname;
 211        u32 overlap_count = 0;
 212
 213        ACPI_FUNCTION_TRACE(ut_check_address_range);
 214
 215        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
 216            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
 217                return_UINT32(0);
 218        }
 219
 220        range_info = acpi_gbl_address_range_list[space_id];
 221        end_address = address + length - 1;
 222
 223        /* Check entire list for all possible conflicts */
 224
 225        while (range_info) {
 226                /*
 227                 * Check if the requested Address/Length overlaps this address_range.
 228                 * Four cases to consider:
 229                 *
 230                 * 1) Input address/length is contained completely in the address range
 231                 * 2) Input address/length overlaps range at the range start
 232                 * 3) Input address/length overlaps range at the range end
 233                 * 4) Input address/length completely encompasses the range
 234                 */
 235                if ((address <= range_info->end_address) &&
 236                    (end_address >= range_info->start_address)) {
 237
 238                        /* Found an address range overlap */
 239
 240                        overlap_count++;
 241                        if (warn) {     /* Optional warning message */
 242                                pathname =
 243                                    acpi_ns_get_external_pathname(range_info->
 244                                                                  region_node);
 245
 246                                ACPI_WARNING((AE_INFO,
 247                                              "0x%p-0x%p %s conflicts with Region %s %d",
 248                                              ACPI_CAST_PTR(void, address),
 249                                              ACPI_CAST_PTR(void, end_address),
 250                                              acpi_ut_get_region_name(space_id),
 251                                              pathname, overlap_count));
 252                                ACPI_FREE(pathname);
 253                        }
 254                }
 255
 256                range_info = range_info->next;
 257        }
 258
 259        return_UINT32(overlap_count);
 260}
 261
 262/*******************************************************************************
 263 *
 264 * FUNCTION:    acpi_ut_delete_address_lists
 265 *
 266 * PARAMETERS:  None
 267 *
 268 * RETURN:      None
 269 *
 270 * DESCRIPTION: Delete all global address range lists (called during
 271 *              subsystem shutdown).
 272 *
 273 ******************************************************************************/
 274
 275void acpi_ut_delete_address_lists(void)
 276{
 277        struct acpi_address_range *next;
 278        struct acpi_address_range *range_info;
 279        int i;
 280
 281        /* Delete all elements in all address range lists */
 282
 283        for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
 284                next = acpi_gbl_address_range_list[i];
 285
 286                while (next) {
 287                        range_info = next;
 288                        next = range_info->next;
 289                        ACPI_FREE(range_info);
 290                }
 291
 292                acpi_gbl_address_range_list[i] = NULL;
 293        }
 294}
 295