summaryrefslogtreecommitdiff
path: root/drivers/acpi/acpica/exregion.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/exregion.c')
-rw-r--r--drivers/acpi/acpica/exregion.c104
1 files changed, 60 insertions, 44 deletions
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index d15a66de26c0..a390a1c2b0ab 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -3,7 +3,7 @@
*
* Module Name: exregion - ACPI default op_region (address space) handlers
*
- * Copyright (C) 2000 - 2020, Intel Corp.
+ * Copyright (C) 2000 - 2025, Intel Corp.
*
*****************************************************************************/
@@ -41,9 +41,9 @@ acpi_ex_system_memory_space_handler(u32 function,
acpi_status status = AE_OK;
void *logical_addr_ptr = NULL;
struct acpi_mem_space_context *mem_info = region_context;
+ struct acpi_mem_mapping *mm = mem_info->cur_mm;
u32 length;
acpi_size map_length;
- acpi_size page_boundary_map_length;
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
u32 remainder;
#endif
@@ -96,20 +96,37 @@ acpi_ex_system_memory_space_handler(u32 function,
* Is 1) Address below the current mapping? OR
* 2) Address beyond the current mapping?
*/
- if ((address < mem_info->mapped_physical_address) ||
- (((u64) address + length) > ((u64)
- mem_info->mapped_physical_address +
- mem_info->mapped_length))) {
+ if (!mm || (address < mm->physical_address) ||
+ ((u64) address + length > (u64) mm->physical_address + mm->length)) {
/*
- * The request cannot be resolved by the current memory mapping;
- * Delete the existing mapping and create a new one.
+ * The request cannot be resolved by the current memory mapping.
+ *
+ * Look for an existing saved mapping covering the address range
+ * at hand. If found, save it as the current one and carry out
+ * the access.
*/
- if (mem_info->mapped_length) {
+ for (mm = mem_info->first_mm; mm; mm = mm->next_mm) {
+ if (mm == mem_info->cur_mm)
+ continue;
+
+ if (address < mm->physical_address)
+ continue;
- /* Valid mapping, delete it */
+ if ((u64) address + length >
+ (u64) mm->physical_address + mm->length)
+ continue;
- acpi_os_unmap_memory(mem_info->mapped_logical_address,
- mem_info->mapped_length);
+ mem_info->cur_mm = mm;
+ goto access;
+ }
+
+ /* Create a new mappings list entry */
+ mm = ACPI_ALLOCATE_ZEROED(sizeof(*mm));
+ if (!mm) {
+ ACPI_ERROR((AE_INFO,
+ "Unable to save memory mapping at 0x%8.8X%8.8X, size %u",
+ ACPI_FORMAT_UINT64(address), length));
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
/*
@@ -120,52 +137,44 @@ acpi_ex_system_memory_space_handler(u32 function,
map_length = (acpi_size)
((mem_info->address + mem_info->length) - address);
- /*
- * If mapping the entire remaining portion of the region will cross
- * a page boundary, just map up to the page boundary, do not cross.
- * On some systems, crossing a page boundary while mapping regions
- * can cause warnings if the pages have different attributes
- * due to resource management.
- *
- * This has the added benefit of constraining a single mapping to
- * one page, which is similar to the original code that used a 4k
- * maximum window.
- */
- page_boundary_map_length = (acpi_size)
- (ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address);
- if (page_boundary_map_length == 0) {
- page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
- }
-
- if (map_length > page_boundary_map_length) {
- map_length = page_boundary_map_length;
- }
+ if (map_length > ACPI_DEFAULT_PAGE_SIZE)
+ map_length = ACPI_DEFAULT_PAGE_SIZE;
/* Create a new mapping starting at the address given */
- mem_info->mapped_logical_address =
- acpi_os_map_memory(address, map_length);
- if (!mem_info->mapped_logical_address) {
+ logical_addr_ptr = acpi_os_map_memory(address, map_length);
+ if (!logical_addr_ptr) {
ACPI_ERROR((AE_INFO,
"Could not map memory at 0x%8.8X%8.8X, size %u",
ACPI_FORMAT_UINT64(address),
(u32)map_length));
- mem_info->mapped_length = 0;
+ ACPI_FREE(mm);
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Save the physical address and mapping size */
- mem_info->mapped_physical_address = address;
- mem_info->mapped_length = map_length;
+ mm->logical_address = logical_addr_ptr;
+ mm->physical_address = address;
+ mm->length = map_length;
+
+ /*
+ * Add the new entry to the mappigs list and save it as the
+ * current mapping.
+ */
+ mm->next_mm = mem_info->first_mm;
+ mem_info->first_mm = mm;
+
+ mem_info->cur_mm = mm;
}
+access:
/*
* Generate a logical pointer corresponding to the address we want to
* access
*/
- logical_addr_ptr = mem_info->mapped_logical_address +
- ((u64) address - (u64) mem_info->mapped_physical_address);
+ logical_addr_ptr = mm->logical_address +
+ ((u64) address - (u64) mm->physical_address);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
@@ -481,8 +490,15 @@ acpi_ex_data_table_space_handler(u32 function,
u64 *value,
void *handler_context, void *region_context)
{
+ struct acpi_data_table_mapping *mapping;
+ char *pointer;
+
ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
+ mapping = (struct acpi_data_table_mapping *) region_context;
+ pointer = ACPI_CAST_PTR(char, mapping->pointer) +
+ (address - ACPI_PTR_TO_PHYSADDR(mapping->pointer));
+
/*
* Perform the memory read or write. The bit_width was already
* validated.
@@ -490,14 +506,14 @@ acpi_ex_data_table_space_handler(u32 function,
switch (function) {
case ACPI_READ:
- memcpy(ACPI_CAST_PTR(char, value),
- ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width));
+ memcpy(ACPI_CAST_PTR(char, value), pointer,
+ ACPI_DIV_8(bit_width));
break;
case ACPI_WRITE:
- memcpy(ACPI_PHYSADDR_TO_PTR(address),
- ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width));
+ memcpy(pointer, ACPI_CAST_PTR(char, value),
+ ACPI_DIV_8(bit_width));
break;
default: