Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: exregion - ACPI default op_region (address space) handlers
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 
0014 #define _COMPONENT          ACPI_EXECUTER
0015 ACPI_MODULE_NAME("exregion")
0016 
0017 /*******************************************************************************
0018  *
0019  * FUNCTION:    acpi_ex_system_memory_space_handler
0020  *
0021  * PARAMETERS:  function            - Read or Write operation
0022  *              address             - Where in the space to read or write
0023  *              bit_width           - Field width in bits (8, 16, or 32)
0024  *              value               - Pointer to in or out value
0025  *              handler_context     - Pointer to Handler's context
0026  *              region_context      - Pointer to context specific to the
0027  *                                    accessed region
0028  *
0029  * RETURN:      Status
0030  *
0031  * DESCRIPTION: Handler for the System Memory address space (Op Region)
0032  *
0033  ******************************************************************************/
0034 acpi_status
0035 acpi_ex_system_memory_space_handler(u32 function,
0036                     acpi_physical_address address,
0037                     u32 bit_width,
0038                     u64 *value,
0039                     void *handler_context, void *region_context)
0040 {
0041     acpi_status status = AE_OK;
0042     void *logical_addr_ptr = NULL;
0043     struct acpi_mem_space_context *mem_info = region_context;
0044     struct acpi_mem_mapping *mm = mem_info->cur_mm;
0045     u32 length;
0046     acpi_size map_length;
0047     acpi_size page_boundary_map_length;
0048 #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
0049     u32 remainder;
0050 #endif
0051 
0052     ACPI_FUNCTION_TRACE(ex_system_memory_space_handler);
0053 
0054     /* Validate and translate the bit width */
0055 
0056     switch (bit_width) {
0057     case 8:
0058 
0059         length = 1;
0060         break;
0061 
0062     case 16:
0063 
0064         length = 2;
0065         break;
0066 
0067     case 32:
0068 
0069         length = 4;
0070         break;
0071 
0072     case 64:
0073 
0074         length = 8;
0075         break;
0076 
0077     default:
0078 
0079         ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
0080                 bit_width));
0081         return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
0082     }
0083 
0084 #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
0085     /*
0086      * Hardware does not support non-aligned data transfers, we must verify
0087      * the request.
0088      */
0089     (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder);
0090     if (remainder != 0) {
0091         return_ACPI_STATUS(AE_AML_ALIGNMENT);
0092     }
0093 #endif
0094 
0095     /*
0096      * Does the request fit into the cached memory mapping?
0097      * Is 1) Address below the current mapping? OR
0098      *    2) Address beyond the current mapping?
0099      */
0100     if (!mm || (address < mm->physical_address) ||
0101         ((u64) address + length > (u64) mm->physical_address + mm->length)) {
0102         /*
0103          * The request cannot be resolved by the current memory mapping.
0104          *
0105          * Look for an existing saved mapping covering the address range
0106          * at hand.  If found, save it as the current one and carry out
0107          * the access.
0108          */
0109         for (mm = mem_info->first_mm; mm; mm = mm->next_mm) {
0110             if (mm == mem_info->cur_mm)
0111                 continue;
0112 
0113             if (address < mm->physical_address)
0114                 continue;
0115 
0116             if ((u64) address + length >
0117                     (u64) mm->physical_address + mm->length)
0118                 continue;
0119 
0120             mem_info->cur_mm = mm;
0121             goto access;
0122         }
0123 
0124         /* Create a new mappings list entry */
0125         mm = ACPI_ALLOCATE_ZEROED(sizeof(*mm));
0126         if (!mm) {
0127             ACPI_ERROR((AE_INFO,
0128                     "Unable to save memory mapping at 0x%8.8X%8.8X, size %u",
0129                     ACPI_FORMAT_UINT64(address), length));
0130             return_ACPI_STATUS(AE_NO_MEMORY);
0131         }
0132 
0133         /*
0134          * October 2009: Attempt to map from the requested address to the
0135          * end of the region. However, we will never map more than one
0136          * page, nor will we cross a page boundary.
0137          */
0138         map_length = (acpi_size)
0139             ((mem_info->address + mem_info->length) - address);
0140 
0141         /*
0142          * If mapping the entire remaining portion of the region will cross
0143          * a page boundary, just map up to the page boundary, do not cross.
0144          * On some systems, crossing a page boundary while mapping regions
0145          * can cause warnings if the pages have different attributes
0146          * due to resource management.
0147          *
0148          * This has the added benefit of constraining a single mapping to
0149          * one page, which is similar to the original code that used a 4k
0150          * maximum window.
0151          */
0152         page_boundary_map_length = (acpi_size)
0153             (ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address);
0154         if (page_boundary_map_length == 0) {
0155             page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
0156         }
0157 
0158         if (map_length > page_boundary_map_length) {
0159             map_length = page_boundary_map_length;
0160         }
0161 
0162         /* Create a new mapping starting at the address given */
0163 
0164         logical_addr_ptr = acpi_os_map_memory(address, map_length);
0165         if (!logical_addr_ptr) {
0166             ACPI_ERROR((AE_INFO,
0167                     "Could not map memory at 0x%8.8X%8.8X, size %u",
0168                     ACPI_FORMAT_UINT64(address),
0169                     (u32)map_length));
0170             ACPI_FREE(mm);
0171             return_ACPI_STATUS(AE_NO_MEMORY);
0172         }
0173 
0174         /* Save the physical address and mapping size */
0175 
0176         mm->logical_address = logical_addr_ptr;
0177         mm->physical_address = address;
0178         mm->length = map_length;
0179 
0180         /*
0181          * Add the new entry to the mappigs list and save it as the
0182          * current mapping.
0183          */
0184         mm->next_mm = mem_info->first_mm;
0185         mem_info->first_mm = mm;
0186 
0187         mem_info->cur_mm = mm;
0188     }
0189 
0190 access:
0191     /*
0192      * Generate a logical pointer corresponding to the address we want to
0193      * access
0194      */
0195     logical_addr_ptr = mm->logical_address +
0196         ((u64) address - (u64) mm->physical_address);
0197 
0198     ACPI_DEBUG_PRINT((ACPI_DB_INFO,
0199               "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
0200               bit_width, function, ACPI_FORMAT_UINT64(address)));
0201 
0202     /*
0203      * Perform the memory read or write
0204      *
0205      * Note: For machines that do not support non-aligned transfers, the target
0206      * address was checked for alignment above. We do not attempt to break the
0207      * transfer up into smaller (byte-size) chunks because the AML specifically
0208      * asked for a transfer width that the hardware may require.
0209      */
0210     switch (function) {
0211     case ACPI_READ:
0212 
0213         *value = 0;
0214         switch (bit_width) {
0215         case 8:
0216 
0217             *value = (u64)ACPI_GET8(logical_addr_ptr);
0218             break;
0219 
0220         case 16:
0221 
0222             *value = (u64)ACPI_GET16(logical_addr_ptr);
0223             break;
0224 
0225         case 32:
0226 
0227             *value = (u64)ACPI_GET32(logical_addr_ptr);
0228             break;
0229 
0230         case 64:
0231 
0232             *value = (u64)ACPI_GET64(logical_addr_ptr);
0233             break;
0234 
0235         default:
0236 
0237             /* bit_width was already validated */
0238 
0239             break;
0240         }
0241         break;
0242 
0243     case ACPI_WRITE:
0244 
0245         switch (bit_width) {
0246         case 8:
0247 
0248             ACPI_SET8(logical_addr_ptr, *value);
0249             break;
0250 
0251         case 16:
0252 
0253             ACPI_SET16(logical_addr_ptr, *value);
0254             break;
0255 
0256         case 32:
0257 
0258             ACPI_SET32(logical_addr_ptr, *value);
0259             break;
0260 
0261         case 64:
0262 
0263             ACPI_SET64(logical_addr_ptr, *value);
0264             break;
0265 
0266         default:
0267 
0268             /* bit_width was already validated */
0269 
0270             break;
0271         }
0272         break;
0273 
0274     default:
0275 
0276         status = AE_BAD_PARAMETER;
0277         break;
0278     }
0279 
0280     return_ACPI_STATUS(status);
0281 }
0282 
0283 /*******************************************************************************
0284  *
0285  * FUNCTION:    acpi_ex_system_io_space_handler
0286  *
0287  * PARAMETERS:  function            - Read or Write operation
0288  *              address             - Where in the space to read or write
0289  *              bit_width           - Field width in bits (8, 16, or 32)
0290  *              value               - Pointer to in or out value
0291  *              handler_context     - Pointer to Handler's context
0292  *              region_context      - Pointer to context specific to the
0293  *                                    accessed region
0294  *
0295  * RETURN:      Status
0296  *
0297  * DESCRIPTION: Handler for the System IO address space (Op Region)
0298  *
0299  ******************************************************************************/
0300 
0301 acpi_status
0302 acpi_ex_system_io_space_handler(u32 function,
0303                 acpi_physical_address address,
0304                 u32 bit_width,
0305                 u64 *value,
0306                 void *handler_context, void *region_context)
0307 {
0308     acpi_status status = AE_OK;
0309     u32 value32;
0310 
0311     ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
0312 
0313     ACPI_DEBUG_PRINT((ACPI_DB_INFO,
0314               "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
0315               bit_width, function, ACPI_FORMAT_UINT64(address)));
0316 
0317     /* Decode the function parameter */
0318 
0319     switch (function) {
0320     case ACPI_READ:
0321 
0322         status = acpi_hw_read_port((acpi_io_address)address,
0323                        &value32, bit_width);
0324         *value = value32;
0325         break;
0326 
0327     case ACPI_WRITE:
0328 
0329         status = acpi_hw_write_port((acpi_io_address)address,
0330                         (u32)*value, bit_width);
0331         break;
0332 
0333     default:
0334 
0335         status = AE_BAD_PARAMETER;
0336         break;
0337     }
0338 
0339     return_ACPI_STATUS(status);
0340 }
0341 
0342 #ifdef ACPI_PCI_CONFIGURED
0343 /*******************************************************************************
0344  *
0345  * FUNCTION:    acpi_ex_pci_config_space_handler
0346  *
0347  * PARAMETERS:  function            - Read or Write operation
0348  *              address             - Where in the space to read or write
0349  *              bit_width           - Field width in bits (8, 16, or 32)
0350  *              value               - Pointer to in or out value
0351  *              handler_context     - Pointer to Handler's context
0352  *              region_context      - Pointer to context specific to the
0353  *                                    accessed region
0354  *
0355  * RETURN:      Status
0356  *
0357  * DESCRIPTION: Handler for the PCI Config address space (Op Region)
0358  *
0359  ******************************************************************************/
0360 
0361 acpi_status
0362 acpi_ex_pci_config_space_handler(u32 function,
0363                  acpi_physical_address address,
0364                  u32 bit_width,
0365                  u64 *value,
0366                  void *handler_context, void *region_context)
0367 {
0368     acpi_status status = AE_OK;
0369     struct acpi_pci_id *pci_id;
0370     u16 pci_register;
0371 
0372     ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
0373 
0374     /*
0375      *  The arguments to acpi_os(Read|Write)pci_configuration are:
0376      *
0377      *  pci_segment is the PCI bus segment range 0-31
0378      *  pci_bus     is the PCI bus number range 0-255
0379      *  pci_device  is the PCI device number range 0-31
0380      *  pci_function is the PCI device function number
0381      *  pci_register is the Config space register range 0-255 bytes
0382      *
0383      *  value - input value for write, output address for read
0384      *
0385      */
0386     pci_id = (struct acpi_pci_id *)region_context;
0387     pci_register = (u16) (u32) address;
0388 
0389     ACPI_DEBUG_PRINT((ACPI_DB_INFO,
0390               "Pci-Config %u (%u) Seg(%04x) Bus(%04x) "
0391               "Dev(%04x) Func(%04x) Reg(%04x)\n",
0392               function, bit_width, pci_id->segment, pci_id->bus,
0393               pci_id->device, pci_id->function, pci_register));
0394 
0395     switch (function) {
0396     case ACPI_READ:
0397 
0398         *value = 0;
0399         status =
0400             acpi_os_read_pci_configuration(pci_id, pci_register, value,
0401                            bit_width);
0402         break;
0403 
0404     case ACPI_WRITE:
0405 
0406         status =
0407             acpi_os_write_pci_configuration(pci_id, pci_register,
0408                             *value, bit_width);
0409         break;
0410 
0411     default:
0412 
0413         status = AE_BAD_PARAMETER;
0414         break;
0415     }
0416 
0417     return_ACPI_STATUS(status);
0418 }
0419 #endif
0420 
0421 /*******************************************************************************
0422  *
0423  * FUNCTION:    acpi_ex_cmos_space_handler
0424  *
0425  * PARAMETERS:  function            - Read or Write operation
0426  *              address             - Where in the space to read or write
0427  *              bit_width           - Field width in bits (8, 16, or 32)
0428  *              value               - Pointer to in or out value
0429  *              handler_context     - Pointer to Handler's context
0430  *              region_context      - Pointer to context specific to the
0431  *                                    accessed region
0432  *
0433  * RETURN:      Status
0434  *
0435  * DESCRIPTION: Handler for the CMOS address space (Op Region)
0436  *
0437  ******************************************************************************/
0438 
0439 acpi_status
0440 acpi_ex_cmos_space_handler(u32 function,
0441                acpi_physical_address address,
0442                u32 bit_width,
0443                u64 *value,
0444                void *handler_context, void *region_context)
0445 {
0446     acpi_status status = AE_OK;
0447 
0448     ACPI_FUNCTION_TRACE(ex_cmos_space_handler);
0449 
0450     return_ACPI_STATUS(status);
0451 }
0452 
0453 #ifdef ACPI_PCI_CONFIGURED
0454 /*******************************************************************************
0455  *
0456  * FUNCTION:    acpi_ex_pci_bar_space_handler
0457  *
0458  * PARAMETERS:  function            - Read or Write operation
0459  *              address             - Where in the space to read or write
0460  *              bit_width           - Field width in bits (8, 16, or 32)
0461  *              value               - Pointer to in or out value
0462  *              handler_context     - Pointer to Handler's context
0463  *              region_context      - Pointer to context specific to the
0464  *                                    accessed region
0465  *
0466  * RETURN:      Status
0467  *
0468  * DESCRIPTION: Handler for the PCI bar_target address space (Op Region)
0469  *
0470  ******************************************************************************/
0471 
0472 acpi_status
0473 acpi_ex_pci_bar_space_handler(u32 function,
0474                   acpi_physical_address address,
0475                   u32 bit_width,
0476                   u64 *value,
0477                   void *handler_context, void *region_context)
0478 {
0479     acpi_status status = AE_OK;
0480 
0481     ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler);
0482 
0483     return_ACPI_STATUS(status);
0484 }
0485 #endif
0486 
0487 /*******************************************************************************
0488  *
0489  * FUNCTION:    acpi_ex_data_table_space_handler
0490  *
0491  * PARAMETERS:  function            - Read or Write operation
0492  *              address             - Where in the space to read or write
0493  *              bit_width           - Field width in bits (8, 16, or 32)
0494  *              value               - Pointer to in or out value
0495  *              handler_context     - Pointer to Handler's context
0496  *              region_context      - Pointer to context specific to the
0497  *                                    accessed region
0498  *
0499  * RETURN:      Status
0500  *
0501  * DESCRIPTION: Handler for the Data Table address space (Op Region)
0502  *
0503  ******************************************************************************/
0504 
0505 acpi_status
0506 acpi_ex_data_table_space_handler(u32 function,
0507                  acpi_physical_address address,
0508                  u32 bit_width,
0509                  u64 *value,
0510                  void *handler_context, void *region_context)
0511 {
0512     struct acpi_data_table_space_context *mapping;
0513     char *pointer;
0514 
0515     ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
0516 
0517     mapping = (struct acpi_data_table_space_context *) region_context;
0518     pointer = ACPI_CAST_PTR(char, mapping->pointer) +
0519         (address - ACPI_PTR_TO_PHYSADDR(mapping->pointer));
0520 
0521     /*
0522      * Perform the memory read or write. The bit_width was already
0523      * validated.
0524      */
0525     switch (function) {
0526     case ACPI_READ:
0527 
0528         memcpy(ACPI_CAST_PTR(char, value), pointer,
0529                ACPI_DIV_8(bit_width));
0530         break;
0531 
0532     case ACPI_WRITE:
0533 
0534         memcpy(pointer, ACPI_CAST_PTR(char, value),
0535                ACPI_DIV_8(bit_width));
0536         break;
0537 
0538     default:
0539 
0540         return_ACPI_STATUS(AE_BAD_PARAMETER);
0541     }
0542 
0543     return_ACPI_STATUS(AE_OK);
0544 }