diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 70af068f10e02..79094d39d6da0 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -24,6 +24,7 @@ CONFIG_CPU_IDLE_THERMAL=y CONFIG_DEBUG_INFO_BTF=y CONFIG_DEBUG_INFO_BTF_MODULES=y # CONFIG_MODULE_ALLOW_BTF_MISMATCH is not set +CONFIG_DMA_CMA=y CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 0df0071119754..c9463a6d82a33 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -395,33 +395,45 @@ static int __init __add_cma_heap(struct cma *cma, const char *name) return 0; } -static int __init add_default_cma_heap(void) +static int __init add_cma_heaps(void) { struct cma *default_cma = dev_get_cma_area(NULL); const char *legacy_cma_name; + struct cma *cma; + unsigned int i; int ret; - if (!default_cma) - return 0; - - ret = __add_cma_heap(default_cma, DEFAULT_CMA_NAME); - if (ret) - return ret; - - if (IS_ENABLED(CONFIG_DMABUF_HEAPS_CMA_LEGACY)) { - legacy_cma_name = cma_get_name(default_cma); - if (!strcmp(legacy_cma_name, DEFAULT_CMA_NAME)) { - pr_warn("legacy name and default name are the same, skipping legacy heap\n"); - return 0; + if (default_cma) { + ret = __add_cma_heap(default_cma, DEFAULT_CMA_NAME); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_DMABUF_HEAPS_CMA_LEGACY)) { + legacy_cma_name = cma_get_name(default_cma); + if (!strcmp(legacy_cma_name, DEFAULT_CMA_NAME)) { + pr_warn("legacy name and default name are the same, skipping legacy heap\n"); + goto add_additional_heaps; + } + + ret = __add_cma_heap(default_cma, legacy_cma_name); + if (ret) + pr_warn("failed to add legacy heap: %pe\n", + ERR_PTR(ret)); } + } + +add_additional_heaps: + for (i = 0; (cma = dma_contiguous_get_area_by_idx(i)) != NULL; i++) { + if (cma == default_cma) + continue; - ret = __add_cma_heap(default_cma, legacy_cma_name); + ret = __add_cma_heap(cma, cma_get_name(cma)); if (ret) - pr_warn("failed to add legacy heap: %pe\n", - ERR_PTR(ret)); + pr_warn("failed to add CMA heap %s: %pe\n", + cma_get_name(cma), ERR_PTR(ret)); } return 0; } -module_init(add_default_cma_heap); +module_init(add_cma_heaps); MODULE_DESCRIPTION("DMA-BUF CMA Heap"); diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h index 10882d00cb170..8147a39df0618 100644 --- a/include/linux/dma-map-ops.h +++ b/include/linux/dma-map-ops.h @@ -98,6 +98,7 @@ static inline void set_dma_ops(struct device *dev, #ifdef CONFIG_DMA_CMA extern struct cma *dma_contiguous_default_area; +struct cma *dma_contiguous_get_area_by_idx(unsigned int idx); static inline struct cma *dev_get_cma_area(struct device *dev) { @@ -156,6 +157,11 @@ static inline void dma_free_contiguous(struct device *dev, struct page *page, static inline void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { } + +static inline struct cma *dma_contiguous_get_area_by_idx(unsigned int idx) +{ + return NULL; +} #endif /* CONFIG_DMA_CMA*/ #ifdef CONFIG_DMA_DECLARE_COHERENT diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c index 9071c08650e3a..1ebcba769d3b4 100644 --- a/kernel/dma/contiguous.c +++ b/kernel/dma/contiguous.c @@ -53,6 +53,27 @@ #endif struct cma *dma_contiguous_default_area; +static struct cma *dma_contiguous_areas[MAX_CMA_AREAS]; +static unsigned int dma_contiguous_areas_num; + +static int dma_contiguous_insert_area(struct cma *cma) +{ + if (dma_contiguous_areas_num >= ARRAY_SIZE(dma_contiguous_areas)) + return -EINVAL; + + dma_contiguous_areas[dma_contiguous_areas_num++] = cma; + + return 0; +} + +struct cma *dma_contiguous_get_area_by_idx(unsigned int idx) +{ + if (idx >= dma_contiguous_areas_num) + return NULL; + + return dma_contiguous_areas[idx]; +} +EXPORT_SYMBOL_GPL(dma_contiguous_get_area_by_idx); /* * Default global CMA area size can be defined in kernel's .config. @@ -251,13 +272,21 @@ void __init dma_contiguous_reserve(phys_addr_t limit) } if (selected_size && !dma_contiguous_default_area) { + int ret; + pr_debug("%s: reserving %ld MiB for global area\n", __func__, (unsigned long)selected_size / SZ_1M); - dma_contiguous_reserve_area(selected_size, selected_base, - selected_limit, - &dma_contiguous_default_area, - fixed); + ret = dma_contiguous_reserve_area(selected_size, selected_base, + selected_limit, + &dma_contiguous_default_area, + fixed); + if (ret) + return; + + ret = dma_contiguous_insert_area(dma_contiguous_default_area); + if (ret) + pr_warn("Couldn't queue default CMA region for heap creation.\n"); } } @@ -497,6 +526,10 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n", &rmem->base, (unsigned long)rmem->size / SZ_1M); + err = dma_contiguous_insert_area(cma); + if (err) + pr_warn("Couldn't store CMA reserved area.\n"); + return 0; } RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);