diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 6e9fb667a1c5..2c95cf0be45e 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -249,6 +249,15 @@ struct resource *lookup_resource(struct resource *root, resource_size_t start);
 int adjust_resource(struct resource *res, resource_size_t start,
 		    resource_size_t size);
 resource_size_t resource_alignment(struct resource *res);
+
+#ifdef CONFIG_SOFT_RESERVED_MANAGED
+void merge_srmem_resources(void);
+extern void release_srmem_region_adjustable(resource_size_t start,
+					    resource_size_t size);
+#else
+static inline void merge_srmem_resources(void) { }
+#endif
+
 static inline resource_size_t resource_size(const struct resource *res)
 {
 	return res->end - res->start + 1;
diff --git a/kernel/resource.c b/kernel/resource.c
index a83040fde236..9db420078a3f 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -48,6 +48,14 @@ struct resource iomem_resource = {
 };
 EXPORT_SYMBOL(iomem_resource);
 
+static struct resource srmem_resource = {
+	.name	= "Soft Reserved mem",
+	.start	= 0,
+	.end	= -1,
+	.flags	= IORESOURCE_MEM,
+	.desc	= IORES_DESC_SOFT_RESERVED,
+};
+
 static DEFINE_RWLOCK(resource_lock);
 
 static struct resource *next_resource(struct resource *p, bool skip_children)
@@ -818,6 +826,19 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
 {
 	struct resource *first, *next;
 
+	if (IS_ENABLED(CONFIG_SOFT_RESERVED_MANAGED)) {
+		/*
+		 * During boot SOFT RESERVED resources are placed on the srmem
+		 * resource tree. These resources may be updated later in boot,
+		 * for example see the CXL driver, prior to being merged into
+		 * the iomem resource tree.
+		 */
+		if (system_state < SYSTEM_RUNNING &&
+		    parent == &iomem_resource &&
+		    new->desc == IORES_DESC_SOFT_RESERVED)
+			parent = &srmem_resource;
+	}
+
 	for (;; parent = first) {
 		first = __request_resource(parent, new);
 		if (!first)
@@ -1336,11 +1357,12 @@ void __release_region(struct resource *parent, resource_size_t start,
 }
 EXPORT_SYMBOL(__release_region);
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 /**
- * release_mem_region_adjustable - release a previously reserved memory region
+ * release_region_adjustable - release a previously reserved memory region
+ * @parent: resource tree to release resource from
  * @start: resource start address
  * @size: resource region size
+ * @busy_check: check for IORESOURCE_BUSY
  *
  * This interface is intended for memory hot-delete.  The requested region
  * is released from a currently busy memory resource.  The requested region
@@ -1356,9 +1378,11 @@ EXPORT_SYMBOL(__release_region);
  *   assumes that all children remain in the lower address entry for
  *   simplicity.  Enhance this logic when necessary.
  */
-void release_mem_region_adjustable(resource_size_t start, resource_size_t size)
+static void release_region_adjustable(struct resource *parent,
+				      resource_size_t start,
+				      resource_size_t size,
+				      bool busy_check)
 {
-	struct resource *parent = &iomem_resource;
 	struct resource *new_res = NULL;
 	bool alloc_nofail = false;
 	struct resource **p;
@@ -1395,7 +1419,7 @@ void release_mem_region_adjustable(resource_size_t start, resource_size_t size)
 		if (!(res->flags & IORESOURCE_MEM))
 			break;
 
-		if (!(res->flags & IORESOURCE_BUSY)) {
+		if (busy_check && !(res->flags & IORESOURCE_BUSY)) {
 			p = &res->child;
 			continue;
 		}
@@ -1445,6 +1469,51 @@ void release_mem_region_adjustable(resource_size_t start, resource_size_t size)
 	write_unlock(&resource_lock);
 	free_resource(new_res);
 }
+
+#ifdef CONFIG_SOFT_RESERVED_MANAGED
+/**
+ * merge_srmem_resources - merge srmem resources into the iomem resource tree
+ *
+ * This is intended to allow kernel drivers that manage the SOFT RESERVED
+ * resources to merge any remaining resources into the iomem resource tree
+ * once any updates have been made.
+ */
+void merge_srmem_resources(void)
+{
+	struct resource *res, *next;
+	int rc;
+
+	for (res = srmem_resource.child; res; res = next) {
+		next = next_resource(res, true);
+
+		write_lock(&resource_lock);
+
+		if (WARN_ON(__release_resource(res, true))) {
+			write_unlock(&resource_lock);
+			continue;
+		}
+
+		if (WARN_ON(__insert_resource(&iomem_resource, res)))
+			__insert_resource(&srmem_resource, res);
+
+		write_unlock(&resource_lock);
+	}
+}
+EXPORT_SYMBOL_GPL(merge_srmem_resources);
+
+void release_srmem_region_adjustable(resource_size_t start,
+				     resource_size_t size)
+{
+	release_region_adjustable(&srmem_resource, start, size, false);
+}
+EXPORT_SYMBOL(release_srmem_region_adjustable);
+#endif
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+void release_mem_region_adjustable(resource_size_t start, resource_size_t size)
+{
+	release_region_adjustable(&iomem_resource, start, size, true);
+}
 #endif	/* CONFIG_MEMORY_HOTREMOVE */
 
 #ifdef CONFIG_MEMORY_HOTPLUG
diff --git a/lib/Kconfig b/lib/Kconfig
index b38849af6f13..4f4011334051 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -777,3 +777,7 @@ config POLYNOMIAL
 
 config FIRMWARE_TABLE
 	bool
+
+config SOFT_RESERVED_MANAGED
+	bool
+	default n
