@@ -38,6 +38,9 @@ acpi_ev_system_memory_region_setup(acpi_handle handle,
union acpi_operand_object *region_desc =
(union acpi_operand_object *)handle;
struct acpi_mem_space_context *local_region_context;
+#ifdef ACPI_OS_MAP_MEMORY_FAST_PATH
+ struct acpi_mem_mapping *mapping;
+#endif
ACPI_FUNCTION_TRACE(ev_system_memory_region_setup);
@@ -46,13 +49,22 @@ 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);
+#ifdef ACPI_OS_MAP_MEMORY_FAST_PATH
+ while (local_region_context->first_mapping) {
+ mapping = local_region_context->first_mapping;
+ local_region_context->first_mapping = mapping->next;
+ acpi_os_unmap_memory(mapping->logical_address,
+ mapping->length);
+ ACPI_FREE(mapping);
+ }
+#endif
}
ACPI_FREE(local_region_context);
*region_context = NULL;
@@ -44,6 +44,9 @@ acpi_ex_system_memory_space_handler(u32 function,
u32 length;
acpi_size map_length;
acpi_size page_boundary_map_length;
+#ifdef ACPI_OS_MAP_MEMORY_FAST_PATH
+ struct acpi_mem_mapping *mapping;
+#endif
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
u32 remainder;
#endif
@@ -102,7 +105,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 +115,40 @@ acpi_ex_system_memory_space_handler(u32 function,
mem_info->mapped_length);
}
+#ifdef ACPI_OS_MAP_MEMORY_FAST_PATH
+ /*
+ * Look for an existing saved mapping matching the request at
+ * hand. If found, bump up its reference counter in the OS
+ * layer, cache it and carry out the access.
+ */
+ for (mapping = mem_info->first_mapping; mapping;
+ mapping = mapping->next) {
+ if (address < mapping->physical_address)
+ continue;
+
+ if ((u64)address + length >
+ (u64)mapping->physical_address +
+ mapping->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(mapping->physical_address,
+ mapping->length))
+ continue;
+
+ mem_info->mapped_logical_address =
+ mapping->logical_address;
+ mem_info->mapped_physical_address =
+ mapping->physical_address;
+ mem_info->mapped_length = mapping->length;
+ goto access;
+ }
+#endif /* ACPI_OS_MAP_MEMORY_FAST_PATH */
+
/*
* 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 +180,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 +192,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_OS_MAP_MEMORY_FAST_PATH
+ /*
+ * Get memory to save the new mapping for removal at the
+ * operation region deactivation time.
+ */
+ mapping = ACPI_ALLOCATE_ZEROED(sizeof(*mapping));
+ if (!mapping) {
+ /*
+ * 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 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 memory 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(mapping);
+ goto access;
+ }
+ mapping->physical_address = address;
+ mapping->logical_address = logical_addr_ptr;
+ mapping->length = map_length;
+ mapping->next = mem_info->first_mapping;
+ mem_info->first_mapping = mapping;
}
+access:
+#else /* !ACPI_OS_MAP_MEMORY_FAST_PATH */
+ }
+#endif /* !ACPI_OS_MAP_MEMORY_FAST_PATH */
/*
* Generate a logical pointer corresponding to the address we want to
* access
@@ -1200,12 +1200,20 @@ struct acpi_pci_id {
u16 function;
};
+struct acpi_mem_mapping {
+ acpi_physical_address physical_address;
+ u8 *logical_address;
+ acpi_size length;
+ struct acpi_mem_mapping *next;
+};
+
struct acpi_mem_space_context {
u32 length;
acpi_physical_address address;
acpi_physical_address mapped_physical_address;
u8 *mapped_logical_address;
acpi_size mapped_length;
+ struct acpi_mem_mapping *first_mapping;
};
/*