diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index 1f1026fb06e9..db9c279baa2e 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -479,8 +479,12 @@ void acpi_ex_pci_cls_to_string(char *dest, u8 class_code[3]);
 
 u8 acpi_is_valid_space_id(u8 space_id);
 
+struct acpi_mem_space_context *acpi_ex_alloc_mem_space_context(void);
+
 void acpi_ex_unmap_region_memory(struct acpi_mem_space_context *mem_info);
 
+void acpi_ex_unmap_all_region_mappings(struct acpi_mem_space_context *mem_info);
+
 /*
  * exregion - default op_region handlers
  */
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 9f33114a74ca..f6c5feea10bc 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -46,10 +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_ex_unmap_region_memory(local_region_context);
+				acpi_ex_unmap_all_region_mappings(local_region_context);
 			}
 			ACPI_FREE(local_region_context);
 			*region_context = NULL;
@@ -59,8 +59,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));
+	local_region_context = acpi_ex_alloc_mem_space_context();
 	if (!(local_region_context)) {
 		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index af777b7fccb0..9d97b6a67074 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -14,6 +14,40 @@
 #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_alloc_mem_space_context
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Pointer to a new region context object.
+ *
+ * DESCRIPTION: Allocate memory for memory operation region representation.
+ *
+ ****************************************************************************/
+struct acpi_mem_space_context *acpi_ex_alloc_mem_space_context(void)
+{
+	ACPI_FUNCTION_TRACE(acpi_ex_alloc_mem_space_context);
+
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+	return ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mm_context));
+#else
+	return ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context));
+#endif
+}
+
 /*****************************************************************************
  *
  * FUNCTION:    acpi_ex_unmap_region_memory
@@ -40,6 +74,44 @@ void acpi_ex_unmap_region_memory(struct acpi_mem_space_context *mem_info)
 	return_VOID;
 }
 
+/*****************************************************************************
+ *
+ * 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_ex_unmap_region_memory(mem_info);
+
+#ifdef ACPI_USE_FAST_PATH_MAPPING
+	while (mm_context->first_mm) {
+		mm = mm_context->first_mm;
+		mm_context->first_mm = mm->next_mm;
+#ifdef ACPI_USE_DEFERRED_UNMAPPING
+		acpi_os_unmap_deferred(mm->logical_address, mm->length);
+#else
+		acpi_os_unmap_memory(mm->logical_address, mm->length);
+#endif
+		ACPI_FREE(mm);
+	}
+#endif /* ACPI_USE_FAST_PATH_MAPPING */
+
+	return_VOID;
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_system_memory_space_handler
@@ -70,6 +142,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
@@ -128,7 +204,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) {
 
@@ -137,6 +213,36 @@ acpi_ex_system_memory_space_handler(u32 function,
 			acpi_ex_unmap_region_memory(mem_info);
 		}
 
+#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
@@ -168,9 +274,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),
@@ -181,10 +286,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
