diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
index 699177d3171042617f57b67e1a4327aec69d65df..b28bd82aa405bcedb05680742fe116d0be3a414f 100644
--- a/Documentation/devicetree/bindings/memory.txt
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -38,6 +38,7 @@ wit the following convention:
 	(linux,default-contiguous-region);
 	(linux,reserve-region);
 	(linux,memory-limit);
+	(linux,remove-completely);
         label = (unique_name);
 };
 
@@ -58,6 +59,10 @@ linux,memory-limit: property specifying an upper bound on the physical address
 		is specificed, the region may be placed anywhere in the physical
 		address space. 0 may be used to specify lowmem (i.e. the region
 		will be placed in the direct mapped lowmem region)
+linux,remove-completely: property indicating the memory will be removed from the
+		linux page allocator completely. This means that page structures
+		associated with the memory will not be valid. This binding is
+		expected to be used in conjunction with linux,reserve-region.
 label:		an internal name used for automatically associating the
 		cma region with a given device. The label is optional;
 		if the label is not given the client is responsible for
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 1eeb5ce1b14b871e5c4e1d4c4e64bedc81ed1c15..3b51cc4ebc70a30deed098134f822702b1c99d05 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -38,6 +38,7 @@
 #include <linux/swap.h>
 #include <linux/mm_types.h>
 #include <linux/dma-contiguous.h>
+#include <linux/dma-removed.h>
 #include <trace/events/kmem.h>
 
 struct cma {
@@ -220,6 +221,7 @@ int __init cma_fdt_scan(unsigned long node, const char *uname,
 	__be32 *prop;
 	char *name;
 	bool in_system;
+	bool remove;
 	unsigned long size_cells = dt_root_size_cells;
 	unsigned long addr_cells = dt_root_addr_cells;
 	phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE;
@@ -250,10 +252,13 @@ int __init cma_fdt_scan(unsigned long node, const char *uname,
 	if (prop)
 		limit = be32_to_cpu(prop[0]);
 
+	remove =
+	     of_get_flat_dt_prop(node, "linux,remove-completely", NULL) ? 1 : 0;
+
 	pr_info("Found %s, memory base %pa, size %ld MiB, limit %pa\n", uname,
 			&base, (unsigned long)size / SZ_1M, &limit);
 	dma_contiguous_reserve_area(size, &base, limit, name,
-					in_system);
+					in_system, remove);
 
 	return 0;
 }
@@ -295,7 +300,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 			 (unsigned long)sel_size / SZ_1M);
 
 		if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL,
-		    CMA_RESERVE_AREA) == 0)
+		    CMA_RESERVE_AREA, false) == 0)
 			dma_contiguous_def_base = base;
 	}
 #ifdef CONFIG_OF
@@ -319,7 +324,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
  */
 int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
 				       phys_addr_t limit, const char *name,
-				       bool to_system)
+				       bool to_system, bool remove)
 {
 	phys_addr_t base = *res_base;
 	phys_addr_t alignment;
@@ -365,6 +370,15 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
 		}
 	}
 
+	if (remove) {
+		if (!to_system) {
+			memblock_free(base, size);
+			memblock_remove(base, size);
+		} else {
+			WARN(1, "Removing is incompatible with staying in the system\n");
+		}
+	}
+
 	/*
 	 * Each reserved area must be initialised later, when more kernel
 	 * subsystems (like slab allocator) are available.
@@ -380,7 +394,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
 		 &base);
 
 	/* Architecture specific contiguous memory fixup. */
-	dma_contiguous_early_fixup(base, size);
+	if (!remove)
+		dma_contiguous_early_fixup(base, size);
 	return 0;
 err:
 	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
@@ -430,6 +445,10 @@ static void cma_assign_device_from_dt(struct device *dev)
 		return;
 
 	dev_set_cma_area(dev, cma);
+
+	if (of_property_read_bool(node, "linux,remove-completely"))
+		set_dma_ops(dev, &removed_dma_ops);
+
 	pr_info("Assigned CMA region at %lx to %s device\n", (unsigned long)value, dev_name(dev));
 }
 
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index cea8a6fd64f0bfa2ffb3abef1b40413f9cd6a0a6..594d836df37f54d9903edf12516d2e64a2149ba6 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -74,7 +74,8 @@ void dma_contiguous_reserve(phys_addr_t addr_limit);
 
 int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
 				  phys_addr_t limit, const char *name,
-				  bool in_system);
+				  bool in_system,
+				  bool remove);
 
 int dma_contiguous_add_device(struct device *dev, phys_addr_t base);
 
@@ -95,7 +96,8 @@ static inline int dma_declare_contiguous(struct device *dev, phys_addr_t size,
 					 phys_addr_t base, phys_addr_t limit)
 {
 	int ret;
-	ret = dma_contiguous_reserve_area(size, &base, limit, NULL, true);
+	ret = dma_contiguous_reserve_area(size, &base, limit, NULL, true,
+						false);
 	if (ret == 0)
 		ret = dma_contiguous_add_device(dev, base);
 	return ret;
@@ -107,7 +109,8 @@ static inline int dma_declare_contiguous_reserved(struct device *dev,
 					 phys_addr_t limit)
 {
 	int ret;
-	ret = dma_contiguous_reserve_area(size, &base, limit, NULL, false);
+	ret = dma_contiguous_reserve_area(size, &base, limit, NULL, false,
+						false);
 	if (ret == 0)
 		ret = dma_contiguous_add_device(dev, base);
 	return ret;