linux/drivers/acpi/acpica/utaddress.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: utaddress - op_region address range check
   5 *
   6 * Copyright (C) 2000 - 2020, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acnamesp.h"
  13
  14#define _COMPONENT          ACPI_UTILITIES
  15ACPI_MODULE_NAME("utaddress")
  16
  17/*******************************************************************************
  18 *
  19 * FUNCTION:    acpi_ut_add_address_range
  20 *
  21 * PARAMETERS:  space_id            - Address space ID
  22 *              address             - op_region start address
  23 *              length              - op_region length
  24 *              region_node         - op_region namespace node
  25 *
  26 * RETURN:      Status
  27 *
  28 * DESCRIPTION: Add the Operation Region address range to the global list.
  29 *              The only supported Space IDs are Memory and I/O. Called when
  30 *              the op_region address/length operands are fully evaluated.
  31 *
  32 * MUTEX:       Locks the namespace
  33 *
  34 * NOTE: Because this interface is only called when an op_region argument
  35 * list is evaluated, there cannot be any duplicate region_nodes.
  36 * Duplicate Address/Length values are allowed, however, so that multiple
  37 * address conflicts can be detected.
  38 *
  39 ******************************************************************************/
  40acpi_status
  41acpi_ut_add_address_range(acpi_adr_space_type space_id,
  42                          acpi_physical_address address,
  43                          u32 length, struct acpi_namespace_node *region_node)
  44{
  45        struct acpi_address_range *range_info;
  46
  47        ACPI_FUNCTION_TRACE(ut_add_address_range);
  48
  49        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
  50            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
  51                return_ACPI_STATUS(AE_OK);
  52        }
  53
  54        /* Allocate/init a new info block, add it to the appropriate list */
  55
  56        range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
  57        if (!range_info) {
  58                return_ACPI_STATUS(AE_NO_MEMORY);
  59        }
  60
  61        range_info->start_address = address;
  62        range_info->end_address = (address + length - 1);
  63        range_info->region_node = region_node;
  64
  65        range_info->next = acpi_gbl_address_range_list[space_id];
  66        acpi_gbl_address_range_list[space_id] = range_info;
  67
  68        ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
  69                          "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
  70                          acpi_ut_get_node_name(range_info->region_node),
  71                          ACPI_FORMAT_UINT64(address),
  72                          ACPI_FORMAT_UINT64(range_info->end_address)));
  73
  74        return_ACPI_STATUS(AE_OK);
  75}
  76
  77/*******************************************************************************
  78 *
  79 * FUNCTION:    acpi_ut_remove_address_range
  80 *
  81 * PARAMETERS:  space_id            - Address space ID
  82 *              region_node         - op_region namespace node
  83 *
  84 * RETURN:      None
  85 *
  86 * DESCRIPTION: Remove the Operation Region from the global list. The only
  87 *              supported Space IDs are Memory and I/O. Called when an
  88 *              op_region is deleted.
  89 *
  90 * MUTEX:       Assumes the namespace is locked
  91 *
  92 ******************************************************************************/
  93
  94void
  95acpi_ut_remove_address_range(acpi_adr_space_type space_id,
  96                             struct acpi_namespace_node *region_node)
  97{
  98        struct acpi_address_range *range_info;
  99        struct acpi_address_range *prev;
 100
 101        ACPI_FUNCTION_TRACE(ut_remove_address_range);
 102
 103        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
 104            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
 105                return_VOID;
 106        }
 107
 108        /* Get the appropriate list head and check the list */
 109
 110        range_info = prev = acpi_gbl_address_range_list[space_id];
 111        while (range_info) {
 112                if (range_info->region_node == region_node) {
 113                        if (range_info == prev) {       /* Found at list head */
 114                                acpi_gbl_address_range_list[space_id] =
 115                                    range_info->next;
 116                        } else {
 117                                prev->next = range_info->next;
 118                        }
 119
 120                        ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
 121                                          "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
 122                                          acpi_ut_get_node_name(range_info->
 123                                                                region_node),
 124                                          ACPI_FORMAT_UINT64(range_info->
 125                                                             start_address),
 126                                          ACPI_FORMAT_UINT64(range_info->
 127                                                             end_address)));
 128
 129                        ACPI_FREE(range_info);
 130                        return_VOID;
 131                }
 132
 133                prev = range_info;
 134                range_info = range_info->next;
 135        }
 136
 137        return_VOID;
 138}
 139
 140/*******************************************************************************
 141 *
 142 * FUNCTION:    acpi_ut_check_address_range
 143 *
 144 * PARAMETERS:  space_id            - Address space ID
 145 *              address             - Start address
 146 *              length              - Length of address range
 147 *              warn                - TRUE if warning on overlap desired
 148 *
 149 * RETURN:      Count of the number of conflicts detected. Zero is always
 150 *              returned for Space IDs other than Memory or I/O.
 151 *
 152 * DESCRIPTION: Check if the input address range overlaps any of the
 153 *              ASL operation region address ranges. The only supported
 154 *              Space IDs are Memory and I/O.
 155 *
 156 * MUTEX:       Assumes the namespace is locked.
 157 *
 158 ******************************************************************************/
 159
 160u32
 161acpi_ut_check_address_range(acpi_adr_space_type space_id,
 162                            acpi_physical_address address, u32 length, u8 warn)
 163{
 164        struct acpi_address_range *range_info;
 165        acpi_physical_address end_address;
 166        char *pathname;
 167        u32 overlap_count = 0;
 168
 169        ACPI_FUNCTION_TRACE(ut_check_address_range);
 170
 171        if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
 172            (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
 173                return_UINT32(0);
 174        }
 175
 176        range_info = acpi_gbl_address_range_list[space_id];
 177        end_address = address + length - 1;
 178
 179        /* Check entire list for all possible conflicts */
 180
 181        while (range_info) {
 182                /*
 183                 * Check if the requested address/length overlaps this
 184                 * address range. There are four cases to consider:
 185                 *
 186                 * 1) Input address/length is contained completely in the
 187                 *    address range
 188                 * 2) Input address/length overlaps range at the range start
 189                 * 3) Input address/length overlaps range at the range end
 190                 * 4) Input address/length completely encompasses the range
 191                 */
 192                if ((address <= range_info->end_address) &&
 193                    (end_address >= range_info->start_address)) {
 194
 195                        /* Found an address range overlap */
 196
 197                        overlap_count++;
 198                        if (warn) {     /* Optional warning message */
 199                                pathname =
 200                                    acpi_ns_get_normalized_pathname(range_info->
 201                                                                    region_node,
 202                                                                    TRUE);
 203
 204                                ACPI_WARNING((AE_INFO,
 205                                              "%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)",
 206                                              acpi_ut_get_region_name(space_id),
 207                                              ACPI_FORMAT_UINT64(address),
 208                                              ACPI_FORMAT_UINT64(end_address),
 209                                              ACPI_FORMAT_UINT64(range_info->
 210                                                                 start_address),
 211                                              ACPI_FORMAT_UINT64(range_info->
 212                                                                 end_address),
 213                                              pathname));
 214                                ACPI_FREE(pathname);
 215                        }
 216                }
 217
 218                range_info = range_info->next;
 219        }
 220
 221        return_UINT32(overlap_count);
 222}
 223
 224/*******************************************************************************
 225 *
 226 * FUNCTION:    acpi_ut_delete_address_lists
 227 *
 228 * PARAMETERS:  None
 229 *
 230 * RETURN:      None
 231 *
 232 * DESCRIPTION: Delete all global address range lists (called during
 233 *              subsystem shutdown).
 234 *
 235 ******************************************************************************/
 236
 237void acpi_ut_delete_address_lists(void)
 238{
 239        struct acpi_address_range *next;
 240        struct acpi_address_range *range_info;
 241        int i;
 242
 243        /* Delete all elements in all address range lists */
 244
 245        for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
 246                next = acpi_gbl_address_range_list[i];
 247
 248                while (next) {
 249                        range_info = next;
 250                        next = range_info->next;
 251                        ACPI_FREE(range_info);
 252                }
 253
 254                acpi_gbl_address_range_list[i] = NULL;
 255        }
 256}
 257