From e47f90d189c7efb0eb566bbde29aa0ce11694774 Mon Sep 17 00:00:00 2001 From: Zhi Zhou Date: Fri, 14 Sep 2018 15:32:06 +0800 Subject: [PATCH] codec_mm: add reserved & cma support for 4.9. [1/1] PD#172483 Problem: Add reserved & cma support for 4.9. Solution: 1. add tvp padding, for test. 2. add no-cma-tvp,to force not used cma for tvp. 3. add nomap for reserved memroy detective. 4. add res & cma two mem region on same board. 5. add clear-map property for codec_mm_cma. Verify: Test this function with Android_O-MR1(GTVS) & ExoPlayer. Change-Id: Ib20e0e9bc4725afb271de97543ce5ebf3bfcfb29 Signed-off-by: Zhi Zhou --- arch/arm64/boot/dts/amlogic/g12b_a311d_w400.dts | 1 + arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts | 1 + arch/arm64/mm/mmu.c | 5 ++ drivers/amlogic/media/common/codec_mm/codec_mm.c | 13 +++ drivers/base/dma-contiguous.c | 4 + include/linux/cma.h | 6 ++ mm/cma.c | 103 +++++++++++++++++++++++ mm/cma.h | 5 ++ 8 files changed, 138 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/g12b_a311d_w400.dts b/arch/arm64/boot/dts/amlogic/g12b_a311d_w400.dts index 7a6e8d3..9da3d75 100644 --- a/arch/arm64/boot/dts/amlogic/g12b_a311d_w400.dts +++ b/arch/arm64/boot/dts/amlogic/g12b_a311d_w400.dts @@ -121,6 +121,7 @@ size = <0x0 0x13400000>; alignment = <0x0 0x400000>; linux,contiguous-region; + clear-map; }; /* codec shared reserved */ codec_mm_reserved:linux,codec_mm_reserved { diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts index 5fa4dbc..34fe9b2 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts @@ -683,6 +683,7 @@ compatible = "amlogic, codec, mm"; memory-region = <&codec_mm_cma &codec_mm_reserved>; dev_name = "codec_mm"; + /*no-cmatvp;*/ status = "okay"; }; diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 7362110..805d439 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -181,6 +181,10 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end, static inline bool use_1G_block(unsigned long addr, unsigned long next, unsigned long phys) { +#ifdef CONFIG_AMLOGIC_CMA + /* we need create full 2nd page table */ + return false; +#else if (PAGE_SHIFT != 12) return false; @@ -188,6 +192,7 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next, return false; return true; +#endif } static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, diff --git a/drivers/amlogic/media/common/codec_mm/codec_mm.c b/drivers/amlogic/media/common/codec_mm/codec_mm.c index 8a4870c..ac9b810 100644 --- a/drivers/amlogic/media/common/codec_mm/codec_mm.c +++ b/drivers/amlogic/media/common/codec_mm/codec_mm.c @@ -943,10 +943,20 @@ int codec_mm_extpool_pool_alloc( CODEC_MM_FLAGS_FOR_LOCAL_MGR | CODEC_MM_FLAGS_CMA); if (mem) { + if (for_tvp) { + cma_mmu_op(mem->mem_handle, + mem->page_count, + 0); + } ret = codec_mm_init_tvp_pool( tvp_pool, mem); if (ret < 0) { + if (for_tvp) { + cma_mmu_op(mem->mem_handle, + mem->page_count, + 1); + } codec_mm_release(mem, TVP_POOL_NAME); } else { alloced_size += try_alloced_size; @@ -994,6 +1004,9 @@ static int codec_mm_extpool_pool_release(struct extpool_mgt_s *tvp_pool) slot_mem_size = gen_pool_size(gpool); gen_pool_destroy(tvp_pool->gen_pool[i]); if (tvp_pool->mm[i]) { + cma_mmu_op(tvp_pool->mm[i]->mem_handle, + tvp_pool->mm[i]->page_count, + 1); codec_mm_release(tvp_pool->mm[i], TVP_POOL_NAME); } diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 0085c21..5fae019 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -268,6 +268,10 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) } /* Architecture specific contiguous memory fixup. */ dma_contiguous_early_fixup(rmem->base, rmem->size); +#ifdef CONFIG_AMLOGIC_CMA + if (of_get_flat_dt_prop(node, "clear-map", NULL)) + cma_init_clear(cma, 1); +#endif if (of_get_flat_dt_prop(node, "linux,cma-default", NULL)) dma_contiguous_set_default(cma); diff --git a/include/linux/cma.h b/include/linux/cma.h index 29f9e77..1c93d65 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -28,4 +28,10 @@ extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, struct cma **res_cma); 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); +#ifdef CONFIG_AMLOGIC_CMA +extern void cma_init_clear(struct cma *cma, bool clear); +extern int setup_cma_full_pagemap(struct cma *cma); +extern int cma_mmu_op(struct page *page, int count, bool set); +#endif + #endif diff --git a/mm/cma.c b/mm/cma.c index 5c2c466..86b45e4 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -37,6 +37,7 @@ #include #include #ifdef CONFIG_AMLOGIC_CMA +#include #include #endif /* CONFIG_AMLOGIC_CMA */ @@ -46,6 +47,103 @@ struct cma cma_areas[MAX_CMA_AREAS]; unsigned cma_area_count; static DEFINE_MUTEX(cma_mutex); +#ifdef CONFIG_AMLOGIC_CMA +void cma_init_clear(struct cma *cma, bool clear) +{ + cma->clear_map = clear; +} + +static int clear_cma_pagemap2(struct cma *cma) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + unsigned long addr, end; + struct mm_struct *mm; + + addr = (unsigned long)pfn_to_kaddr(cma->base_pfn); + end = addr + cma->count * PAGE_SIZE; + mm = &init_mm; + pgd = pgd_offset(mm, addr); + for (; addr < end; addr += PMD_SIZE) { + if (pgd_none(*pgd) || pgd_bad(*pgd)) + break; + + pud = pud_offset(pgd, addr); + if (pud_none(*pud) || pud_bad(*pud)) + break; + + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) + break; + + pmd_clear(pmd); + } + + return 0; +} + +int setup_cma_full_pagemap(struct cma *cma) +{ + struct vm_area_struct vma = {}; + unsigned long addr, size; + int ret; + + clear_cma_pagemap2(cma); + addr = (unsigned long)pfn_to_kaddr(cma->base_pfn); + size = cma->count * PAGE_SIZE; + vma.vm_mm = &init_mm; + vma.vm_start = addr; + vma.vm_end = addr + size; + vma.vm_page_prot = PAGE_KERNEL; + ret = remap_pfn_range(&vma, addr, cma->base_pfn, + size, vma.vm_page_prot); + if (ret < 0) + pr_info("%s, remap pte failed:%d, cma:%lx\n", + __func__, ret, cma->base_pfn); + return 0; +} + +int cma_mmu_op(struct page *page, int count, bool set) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long addr, end; + struct mm_struct *mm; + + if (!page) + return -EINVAL; + + addr = (unsigned long)page_address(page); + end = addr + count * PAGE_SIZE; + mm = &init_mm; + pgd = pgd_offset(mm, addr); + for (; addr < end; addr += PAGE_SIZE) { + if (pgd_none(*pgd) || pgd_bad(*pgd)) + break; + + pud = pud_offset(pgd, addr); + if (pud_none(*pud) || pud_bad(*pud)) + break; + + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) + break; + + pte = pte_offset_map(pmd, addr); + if (set) + set_pte_at(mm, addr, pte, mk_pte(page, PAGE_KERNEL)); + else + pte_clear(mm, addr, pte); + pte_unmap(pte); + page++; + } + return 0; +} +#endif + phys_addr_t cma_get_base(const struct cma *cma) { return PFN_PHYS(cma->base_pfn); @@ -129,6 +227,11 @@ static int __init cma_activate_area(struct cma *cma) mutex_init(&cma->lock); +#ifdef CONFIG_AMLOGIC_CMA + if (cma->clear_map) + setup_cma_full_pagemap(cma); +#endif + #ifdef CONFIG_CMA_DEBUGFS INIT_HLIST_HEAD(&cma->mem_head); spin_lock_init(&cma->mem_head_lock); diff --git a/mm/cma.h b/mm/cma.h index 17c75a4..bd5a7a5 100644 --- a/mm/cma.h +++ b/mm/cma.h @@ -11,6 +11,11 @@ struct cma { struct hlist_head mem_head; spinlock_t mem_head_lock; #endif + +#ifdef CONFIG_AMLOGIC_CMA /* clear kernel space mapping after driver it */ + bool clear_map; +#endif + }; extern struct cma cma_areas[MAX_CMA_AREAS]; -- 2.7.4