linux/drivers/acpi/acpica/exregion.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: exregion - ACPI default op_region (address space) handlers
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acinterp.h"
  13
  14#define _COMPONENT          ACPI_EXECUTER
  15ACPI_MODULE_NAME("exregion")
  16
  17/*******************************************************************************
  18 *
  19 * FUNCTION:    acpi_ex_system_memory_space_handler
  20 *
  21 * PARAMETERS:  function            - Read or Write operation
  22 *              address             - Where in the space to read or write
  23 *              bit_width           - Field width in bits (8, 16, or 32)
  24 *              value               - Pointer to in or out value
  25 *              handler_context     - Pointer to Handler's context
  26 *              region_context      - Pointer to context specific to the
  27 *                                    accessed region
  28 *
  29 * RETURN:      Status
  30 *
  31 * DESCRIPTION: Handler for the System Memory address space (Op Region)
  32 *
  33 ******************************************************************************/
  34acpi_status
  35acpi_ex_system_memory_space_handler(u32 function,
  36                                    acpi_physical_address address,
  37                                    u32 bit_width,
  38                                    u64 *value,
  39                                    void *handler_context, void *region_context)
  40{
  41        acpi_status status = AE_OK;
  42        void *logical_addr_ptr = NULL;
  43        struct acpi_mem_space_context *mem_info = region_context;
  44        struct acpi_mem_mapping *mm = mem_info->cur_mm;
  45        u32 length;
  46        acpi_size map_length;
  47        acpi_size page_boundary_map_length;
  48#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
  49        u32 remainder;
  50#endif
  51
  52        ACPI_FUNCTION_TRACE(ex_system_memory_space_handler);
  53
  54        /* Validate and translate the bit width */
  55
  56        switch (bit_width) {
  57        case 8:
  58
  59                length = 1;
  60                break;
  61
  62        case 16:
  63
  64                length = 2;
  65                break;
  66
  67        case 32:
  68
  69                length = 4;
  70                break;
  71
  72        case 64:
  73
  74                length = 8;
  75                break;
  76
  77        default:
  78
  79                ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
  80                            bit_width));
  81                return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
  82        }
  83
  84#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
  85        /*
  86         * Hardware does not support non-aligned data transfers, we must verify
  87         * the request.
  88         */
  89        (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder);
  90        if (remainder != 0) {
  91                return_ACPI_STATUS(AE_AML_ALIGNMENT);
  92        }
  93#endif
  94
  95        /*
  96         * Does the request fit into the cached memory mapping?
  97         * Is 1) Address below the current mapping? OR
  98         *    2) Address beyond the current mapping?
  99         */
 100        if (!mm || (address < mm->physical_address) ||
 101            ((u64) address + length > (u64) mm->physical_address + mm->length)) {
 102                /*
 103                 * The request cannot be resolved by the current memory mapping.
 104                 *
 105                 * Look for an existing saved mapping covering the address range
 106                 * at hand.  If found, save it as the current one and carry out
 107                 * the access.
 108                 */
 109                for (mm = mem_info->first_mm; mm; mm = mm->next_mm) {
 110                        if (mm == mem_info->cur_mm)
 111                                continue;
 112
 113                        if (address < mm->physical_address)
 114                                continue;
 115
 116                        if ((u64) address + length >
 117                                        (u64) mm->physical_address + mm->length)
 118                                continue;
 119
 120                        mem_info->cur_mm = mm;
 121                        goto access;
 122                }
 123
 124                /* Create a new mappings list entry */
 125                mm = ACPI_ALLOCATE_ZEROED(sizeof(*mm));
 126                if (!mm) {
 127                        ACPI_ERROR((AE_INFO,
 128                                    "Unable to save memory mapping at 0x%8.8X%8.8X, size %u",
 129                                    ACPI_FORMAT_UINT64(address), length));
 130                        return_ACPI_STATUS(AE_NO_MEMORY);
 131                }
 132
 133                /*
 134                 * October 2009: Attempt to map from the requested address to the
 135                 * end of the region. However, we will never map more than one
 136                 * page, nor will we cross a page boundary.
 137                 */
 138                map_length = (acpi_size)
 139                    ((mem_info->address + mem_info->length) - address);
 140
 141                /*
 142                 * If mapping the entire remaining portion of the region will cross
 143                 * a page boundary, just map up to the page boundary, do not cross.
 144                 * On some systems, crossing a page boundary while mapping regions
 145                 * can cause warnings if the pages have different attributes
 146                 * due to resource management.
 147                 *
 148                 * This has the added benefit of constraining a single mapping to
 149                 * one page, which is similar to the original code that used a 4k
 150                 * maximum window.
 151                 */
 152                page_boundary_map_length = (acpi_size)
 153                    (ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address);
 154                if (page_boundary_map_length == 0) {
 155                        page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
 156                }
 157
 158                if (map_length > page_boundary_map_length) {
 159                        map_length = page_boundary_map_length;
 160                }
 161
 162                /* Create a new mapping starting at the address given */
 163
 164                logical_addr_ptr = acpi_os_map_memory(address, map_length);
 165                if (!logical_addr_ptr) {
 166                        ACPI_ERROR((AE_INFO,
 167                                    "Could not map memory at 0x%8.8X%8.8X, size %u",
 168                                    ACPI_FORMAT_UINT64(address),
 169                                    (u32)map_length));
 170                        ACPI_FREE(mm);
 171                        return_ACPI_STATUS(AE_NO_MEMORY);
 172                }
 173
 174                /* Save the physical address and mapping size */
 175
 176                mm->logical_address = logical_addr_ptr;
 177                mm->physical_address = address;
 178                mm->length = map_length;
 179
 180                /*
 181                 * Add the new entry to the mappigs list and save it as the
 182                 * current mapping.
 183                 */
 184                mm->next_mm = mem_info->first_mm;
 185                mem_info->first_mm = mm;
 186
 187                mem_info->cur_mm = mm;
 188        }
 189
 190access:
 191        /*
 192         * Generate a logical pointer corresponding to the address we want to
 193         * access
 194         */
 195        logical_addr_ptr = mm->logical_address +
 196                ((u64) address - (u64) mm->physical_address);
 197
 198        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 199                          "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
 200                          bit_width, function, ACPI_FORMAT_UINT64(address)));
 201
 202        /*
 203         * Perform the memory read or write
 204         *
 205         * Note: For machines that do not support non-aligned transfers, the target
 206         * address was checked for alignment above. We do not attempt to break the
 207         * transfer up into smaller (byte-size) chunks because the AML specifically
 208         * asked for a transfer width that the hardware may require.
 209         */
 210        switch (function) {
 211        case ACPI_READ:
 212
 213                *value = 0;
 214                switch (bit_width) {
 215                case 8:
 216
 217                        *value = (u64)ACPI_GET8(logical_addr_ptr);
 218                        break;
 219
 220                case 16:
 221
 222                        *value = (u64)ACPI_GET16(logical_addr_ptr);
 223                        break;
 224
 225                case 32:
 226
 227                        *value = (u64)ACPI_GET32(logical_addr_ptr);
 228                        break;
 229
 230                case 64:
 231
 232                        *value = (u64)ACPI_GET64(logical_addr_ptr);
 233                        break;
 234
 235                default:
 236
 237                        /* bit_width was already validated */
 238
 239                        break;
 240                }
 241                break;
 242
 243        case ACPI_WRITE:
 244
 245                switch (bit_width) {
 246                case 8:
 247
 248                        ACPI_SET8(logical_addr_ptr, *value);
 249                        break;
 250
 251                case 16:
 252
 253                        ACPI_SET16(logical_addr_ptr, *value);
 254                        break;
 255
 256                case 32:
 257
 258                        ACPI_SET32(logical_addr_ptr, *value);
 259                        break;
 260
 261                case 64:
 262
 263                        ACPI_SET64(logical_addr_ptr, *value);
 264                        break;
 265
 266                default:
 267
 268                        /* bit_width was already validated */
 269
 270                        break;
 271                }
 272                break;
 273
 274        default:
 275
 276                status = AE_BAD_PARAMETER;
 277                break;
 278        }
 279
 280        return_ACPI_STATUS(status);
 281}
 282
 283/*******************************************************************************
 284 *
 285 * FUNCTION:    acpi_ex_system_io_space_handler
 286 *
 287 * PARAMETERS:  function            - Read or Write operation
 288 *              address             - Where in the space to read or write
 289 *              bit_width           - Field width in bits (8, 16, or 32)
 290 *              value               - Pointer to in or out value
 291 *              handler_context     - Pointer to Handler's context
 292 *              region_context      - Pointer to context specific to the
 293 *                                    accessed region
 294 *
 295 * RETURN:      Status
 296 *
 297 * DESCRIPTION: Handler for the System IO address space (Op Region)
 298 *
 299 ******************************************************************************/
 300
 301acpi_status
 302acpi_ex_system_io_space_handler(u32 function,
 303                                acpi_physical_address address,
 304                                u32 bit_width,
 305                                u64 *value,
 306                                void *handler_context, void *region_context)
 307{
 308        acpi_status status = AE_OK;
 309        u32 value32;
 310
 311        ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
 312
 313        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 314                          "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
 315                          bit_width, function, ACPI_FORMAT_UINT64(address)));
 316
 317        /* Decode the function parameter */
 318
 319        switch (function) {
 320        case ACPI_READ:
 321
 322                status = acpi_hw_read_port((acpi_io_address)address,
 323                                           &value32, bit_width);
 324                *value = value32;
 325                break;
 326
 327        case ACPI_WRITE:
 328
 329                status = acpi_hw_write_port((acpi_io_address)address,
 330                                            (u32)*value, bit_width);
 331                break;
 332
 333        default:
 334
 335                status = AE_BAD_PARAMETER;
 336                break;
 337        }
 338
 339        return_ACPI_STATUS(status);
 340}
 341
 342#ifdef ACPI_PCI_CONFIGURED
 343/*******************************************************************************
 344 *
 345 * FUNCTION:    acpi_ex_pci_config_space_handler
 346 *
 347 * PARAMETERS:  function            - Read or Write operation
 348 *              address             - Where in the space to read or write
 349 *              bit_width           - Field width in bits (8, 16, or 32)
 350 *              value               - Pointer to in or out value
 351 *              handler_context     - Pointer to Handler's context
 352 *              region_context      - Pointer to context specific to the
 353 *                                    accessed region
 354 *
 355 * RETURN:      Status
 356 *
 357 * DESCRIPTION: Handler for the PCI Config address space (Op Region)
 358 *
 359 ******************************************************************************/
 360
 361acpi_status
 362acpi_ex_pci_config_space_handler(u32 function,
 363                                 acpi_physical_address address,
 364                                 u32 bit_width,
 365                                 u64 *value,
 366                                 void *handler_context, void *region_context)
 367{
 368        acpi_status status = AE_OK;
 369        struct acpi_pci_id *pci_id;
 370        u16 pci_register;
 371
 372        ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
 373
 374        /*
 375         *  The arguments to acpi_os(Read|Write)pci_configuration are:
 376         *
 377         *  pci_segment is the PCI bus segment range 0-31
 378         *  pci_bus     is the PCI bus number range 0-255
 379         *  pci_device  is the PCI device number range 0-31
 380         *  pci_function is the PCI device function number
 381         *  pci_register is the Config space register range 0-255 bytes
 382         *
 383         *  value - input value for write, output address for read
 384         *
 385         */
 386        pci_id = (struct acpi_pci_id *)region_context;
 387        pci_register = (u16) (u32) address;
 388
 389        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 390                          "Pci-Config %u (%u) Seg(%04x) Bus(%04x) "
 391                          "Dev(%04x) Func(%04x) Reg(%04x)\n",
 392                          function, bit_width, pci_id->segment, pci_id->bus,
 393                          pci_id->device, pci_id->function, pci_register));
 394
 395        switch (function) {
 396        case ACPI_READ:
 397
 398                *value = 0;
 399                status =
 400                    acpi_os_read_pci_configuration(pci_id, pci_register, value,
 401                                                   bit_width);
 402                break;
 403
 404        case ACPI_WRITE:
 405
 406                status =
 407                    acpi_os_write_pci_configuration(pci_id, pci_register,
 408                                                    *value, bit_width);
 409                break;
 410
 411        default:
 412
 413                status = AE_BAD_PARAMETER;
 414                break;
 415        }
 416
 417        return_ACPI_STATUS(status);
 418}
 419#endif
 420
 421/*******************************************************************************
 422 *
 423 * FUNCTION:    acpi_ex_cmos_space_handler
 424 *
 425 * PARAMETERS:  function            - Read or Write operation
 426 *              address             - Where in the space to read or write
 427 *              bit_width           - Field width in bits (8, 16, or 32)
 428 *              value               - Pointer to in or out value
 429 *              handler_context     - Pointer to Handler's context
 430 *              region_context      - Pointer to context specific to the
 431 *                                    accessed region
 432 *
 433 * RETURN:      Status
 434 *
 435 * DESCRIPTION: Handler for the CMOS address space (Op Region)
 436 *
 437 ******************************************************************************/
 438
 439acpi_status
 440acpi_ex_cmos_space_handler(u32 function,
 441                           acpi_physical_address address,
 442                           u32 bit_width,
 443                           u64 *value,
 444                           void *handler_context, void *region_context)
 445{
 446        acpi_status status = AE_OK;
 447
 448        ACPI_FUNCTION_TRACE(ex_cmos_space_handler);
 449
 450        return_ACPI_STATUS(status);
 451}
 452
 453#ifdef ACPI_PCI_CONFIGURED
 454/*******************************************************************************
 455 *
 456 * FUNCTION:    acpi_ex_pci_bar_space_handler
 457 *
 458 * PARAMETERS:  function            - Read or Write operation
 459 *              address             - Where in the space to read or write
 460 *              bit_width           - Field width in bits (8, 16, or 32)
 461 *              value               - Pointer to in or out value
 462 *              handler_context     - Pointer to Handler's context
 463 *              region_context      - Pointer to context specific to the
 464 *                                    accessed region
 465 *
 466 * RETURN:      Status
 467 *
 468 * DESCRIPTION: Handler for the PCI bar_target address space (Op Region)
 469 *
 470 ******************************************************************************/
 471
 472acpi_status
 473acpi_ex_pci_bar_space_handler(u32 function,
 474                              acpi_physical_address address,
 475                              u32 bit_width,
 476                              u64 *value,
 477                              void *handler_context, void *region_context)
 478{
 479        acpi_status status = AE_OK;
 480
 481        ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler);
 482
 483        return_ACPI_STATUS(status);
 484}
 485#endif
 486
 487/*******************************************************************************
 488 *
 489 * FUNCTION:    acpi_ex_data_table_space_handler
 490 *
 491 * PARAMETERS:  function            - Read or Write operation
 492 *              address             - Where in the space to read or write
 493 *              bit_width           - Field width in bits (8, 16, or 32)
 494 *              value               - Pointer to in or out value
 495 *              handler_context     - Pointer to Handler's context
 496 *              region_context      - Pointer to context specific to the
 497 *                                    accessed region
 498 *
 499 * RETURN:      Status
 500 *
 501 * DESCRIPTION: Handler for the Data Table address space (Op Region)
 502 *
 503 ******************************************************************************/
 504
 505acpi_status
 506acpi_ex_data_table_space_handler(u32 function,
 507                                 acpi_physical_address address,
 508                                 u32 bit_width,
 509                                 u64 *value,
 510                                 void *handler_context, void *region_context)
 511{
 512        ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
 513
 514        /*
 515         * Perform the memory read or write. The bit_width was already
 516         * validated.
 517         */
 518        switch (function) {
 519        case ACPI_READ:
 520
 521                memcpy(ACPI_CAST_PTR(char, value),
 522                       ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width));
 523                break;
 524
 525        case ACPI_WRITE:
 526
 527                memcpy(ACPI_PHYSADDR_TO_PTR(address),
 528                       ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width));
 529                break;
 530
 531        default:
 532
 533                return_ACPI_STATUS(AE_BAD_PARAMETER);
 534        }
 535
 536        return_ACPI_STATUS(AE_OK);
 537}
 538