diff --git a/include/linux/cma.h b/include/linux/cma.h index 190184b5ff32..20cac3e866dc 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -37,4 +37,7 @@ extern struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, extern bool cma_release(struct cma *cma, const struct page *pages, unsigned int count); extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data); + +extern void set_cma_area_inactive(struct cma *cma); + #endif diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c index b2a87905846d..14e0117c3604 100644 --- a/kernel/dma/contiguous.c +++ b/kernel/dma/contiguous.c @@ -270,6 +270,9 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) if (of_get_flat_dt_prop(node, "linux,cma-default", NULL)) dma_contiguous_set_default(cma); + if (of_get_flat_dt_prop(node, "inactive", NULL)) + set_cma_area_inactive(cma); + rmem->ops = &rmem_cma_ops; rmem->priv = cma; diff --git a/mm/cma.c b/mm/cma.c index 9516e7694d91..20bf0b4b5031 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -112,6 +112,9 @@ static int __init cma_activate_area(struct cma *cma) return -ENOMEM; } + if (cma->inactive) + goto done; + WARN_ON_ONCE(!pfn_valid(pfn)); zone = page_zone(pfn_to_page(pfn)); @@ -133,6 +136,7 @@ static int __init cma_activate_area(struct cma *cma) init_cma_reserved_pageblock(pfn_to_page(base_pfn)); } while (--i); +done: mutex_init(&cma->lock); #ifdef CONFIG_CMA_DEBUGFS @@ -467,6 +471,11 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, mutex_unlock(&cma->lock); pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit); + if (cma->inactive) { + ret = 0; + page = pfn_to_page(pfn); + break; + } mutex_lock(&cma_mutex); ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA, GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0)); @@ -535,7 +544,8 @@ bool cma_release(struct cma *cma, const struct page *pages, unsigned int count) VM_BUG_ON(pfn + count > cma->base_pfn + cma->count); - free_contig_range(pfn, count); + if (!cma->inactive) + free_contig_range(pfn, count); cma_clear_bitmap(cma, pfn, count); trace_cma_release(pfn, pages, count); @@ -557,3 +567,9 @@ int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data) return 0; } EXPORT_SYMBOL_GPL(cma_for_each_area); + +void set_cma_area_inactive(struct cma *cma) +{ + cma->inactive = true; +} +EXPORT_SYMBOL_GPL(set_cma_area_inactive); diff --git a/mm/cma.h b/mm/cma.h index 33c0b517733c..e9e59243661b 100644 --- a/mm/cma.h +++ b/mm/cma.h @@ -13,6 +13,7 @@ struct cma { spinlock_t mem_head_lock; #endif const char *name; + bool inactive; }; extern struct cma cma_areas[MAX_CMA_AREAS];