@@ -479,6 +479,9 @@ void acpi_ex_pci_cls_to_string(char *dest, u8 class_code[3]);
u8 acpi_is_valid_space_id(u8 space_id);
+acpi_size acpi_ex_mem_space_context_size(void);
+void acpi_ex_unmap_all_region_mappings(struct acpi_mem_space_context *mem_info);
+
/*
* exregion - default op_region handlers
*/
@@ -46,13 +46,10 @@ acpi_ev_system_memory_region_setup(acpi_handle handle,
local_region_context =
(struct acpi_mem_space_context *)*region_context;
- /* Delete a cached mapping if present */
+ /* Delete memory mappings if present */
if (local_region_context->mapped_length) {
- acpi_os_unmap_memory(local_region_context->
- mapped_logical_address,
- local_region_context->
- mapped_length);
+ acpi_ex_unmap_all_region_mappings(local_region_context);
}
ACPI_FREE(local_region_context);
*region_context = NULL;
@@ -63,7 +60,7 @@ acpi_ev_system_memory_region_setup(acpi_handle handle,
/* Create a new context */
local_region_context =
- ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context));
+ ACPI_ALLOCATE_ZEROED(acpi_ex_mem_space_context_size());
if (!(local_region_context)) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -14,6 +14,73 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exregion")
+struct acpi_mem_mapping {
+ acpi_physical_address physical_address;
+ u8 *logical_address;
+ acpi_size length;
+ struct acpi_mem_mapping *next_mm;
+};
+
+struct acpi_mm_context {
+ struct acpi_mem_space_context mem_info;
+ struct acpi_mem_mapping *first_mm;
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_mem_space_context_size
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Size of internal memory operation region representation.
+ *
+ ******************************************************************************/
+acpi_size acpi_ex_mem_space_context_size(void)
+{
+ ACPI_FUNCTION_TRACE(acpi_ex_mem_space_context_size);
+
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+ return sizeof(struct acpi_mm_context);
+#else
+ return sizeof(struct acpi_mem_space_context);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_unmap_all_region_mappings
+ *
+ * PARAMETERS: mem_info - Region specific context
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Unmap all mappings associated with a memory operation region.
+ *
+ ******************************************************************************/
+void acpi_ex_unmap_all_region_mappings(struct acpi_mem_space_context *mem_info)
+{
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+ struct acpi_mm_context *mm_context = (struct acpi_mm_context *)mem_info;
+ struct acpi_mem_mapping *mm;
+#endif
+
+ ACPI_FUNCTION_TRACE(acpi_ex_unmap_all_region_mappings);
+
+ acpi_os_unmap_memory(mem_info->mapped_logical_address,
+ mem_info->mapped_length);
+
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+ while (mm_context->first_mm) {
+ mm = mm_context->first_mm;
+ mm_context->first_mm = mm->next_mm;
+ acpi_os_unmap_memory(mm->logical_address, mm->length);
+ ACPI_FREE(mm);
+ }
+#endif
+
+ return_VOID;
+}
+
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_memory_space_handler
@@ -44,6 +111,10 @@ acpi_ex_system_memory_space_handler(u32 function,
u32 length;
acpi_size map_length;
acpi_size page_boundary_map_length;
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+ struct acpi_mm_context *mm_context = (struct acpi_mm_context *)mem_info;
+ struct acpi_mem_mapping *mm;
+#endif
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
u32 remainder;
#endif
@@ -102,7 +173,7 @@ acpi_ex_system_memory_space_handler(u32 function,
mem_info->mapped_length))) {
/*
* The request cannot be resolved by the current memory mapping;
- * Delete the existing mapping and create a new one.
+ * Delete the current cached mapping and get a new one.
*/
if (mem_info->mapped_length) {
@@ -112,6 +183,36 @@ acpi_ex_system_memory_space_handler(u32 function,
mem_info->mapped_length);
}
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+ /*
+ * Look for an existing saved mapping matching the address range
+ * at hand. If found, make the OS layer bump up the reference
+ * counter of that mapping, cache it and carry out the access.
+ */
+ for (mm = mm_context->first_mm; mm; mm = mm->next_mm) {
+ if (address < mm->physical_address)
+ continue;
+
+ if ((u64)address + length >
+ (u64)mm->physical_address + mm->length)
+ continue;
+
+ /*
+ * When called on a known-existing memory mapping,
+ * acpi_os_map_memory_fast_path() must return the same
+ * logical address as before or NULL.
+ */
+ if (!acpi_os_map_memory_fast_path(mm->physical_address,
+ mm->length))
+ continue;
+
+ mem_info->mapped_logical_address = mm->logical_address;
+ mem_info->mapped_physical_address = mm->physical_address;
+ mem_info->mapped_length = mm->length;
+ goto access;
+ }
+#endif /* ACPI_USE_FAST_PATH_MAPPING */
+
/*
* October 2009: Attempt to map from the requested address to the
* end of the region. However, we will never map more than one
@@ -143,9 +244,8 @@ acpi_ex_system_memory_space_handler(u32 function,
/* 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),
@@ -156,10 +256,56 @@ acpi_ex_system_memory_space_handler(u32 function,
/* Save the physical address and mapping size */
+ mem_info->mapped_logical_address = logical_addr_ptr;
mem_info->mapped_physical_address = address;
mem_info->mapped_length = map_length;
+
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+ /*
+ * Create a new mm list entry to save the new mapping for
+ * removal at the operation region deactivation time.
+ */
+ mm = ACPI_ALLOCATE_ZEROED(sizeof(*mm));
+ if (!mm) {
+ /*
+ * No room to save the new mapping, but this is not
+ * critical. Just log the error and carry out the
+ * access as requested.
+ */
+ ACPI_ERROR((AE_INFO,
+ "Not enough memory to save memory mapping at 0x%8.8X%8.8X, size %u",
+ ACPI_FORMAT_UINT64(address),
+ (u32)map_length));
+ goto access;
+ }
+ /*
+ * Bump up the new mapping's reference counter in the OS layer
+ * to prevent it from getting dropped prematurely.
+ */
+ if (!acpi_os_map_memory_fast_path(address, map_length)) {
+ /*
+ * Something has gone wrong, but this is not critical.
+ * Log the error, free the mm list entry that won't be
+ * used and carry out the access as requested.
+ */
+ ACPI_ERROR((AE_INFO,
+ "Unable to save memory mapping at 0x%8.8X%8.8X, size %u",
+ ACPI_FORMAT_UINT64(address),
+ (u32)map_length));
+ ACPI_FREE(mm);
+ goto access;
+ }
+ mm->physical_address = address;
+ mm->logical_address = logical_addr_ptr;
+ mm->length = map_length;
+ mm->next_mm = mm_context->first_mm;
+ mm_context->first_mm = mm;
}
+access:
+#else /* !ACPI_USE_FAST_PATH_MAPPING */
+ }
+#endif /* !ACPI_USE_FAST_PATH_MAPPING */
/*
* Generate a logical pointer corresponding to the address we want to
* access