From 16cbe10144aa670944b5233aaeccc025248fb9ca Mon Sep 17 00:00:00 2001 From: Nanxin Qin Date: Thu, 25 Oct 2018 10:42:17 +0800 Subject: [PATCH] media: remap the addr to prevent crash on the 32bit & 2G board [1/1] PD#SWPL-1909 Problem: mem rw exception caused crashed. Solution: 1. add mapping the highmem address by the func vmap(). 2. remove the flag CODEC_MM_FLAGS_CPU if not necessary. Verify: p212, w400 Change-Id: I982c775d7c009335cae5802f0eb6287d22037db6 Signed-off-by: Nanxin Qin --- drivers/amlogic/media/common/codec_mm/codec_mm.c | 134 +++++++++++++++++++-- .../media/video_processor/ppmgr/ppmgr_vpp.c | 2 +- .../media/video_processor/video_dev/amlvideo2.c | 2 +- drivers/amlogic/media/video_sink/video_keeper.c | 3 +- drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c | 2 +- drivers/staging/android/ion/ion_codec_mm_heap.c | 2 +- include/linux/amlogic/media/codec_mm/codec_mm.h | 5 + 7 files changed, 137 insertions(+), 13 deletions(-) diff --git a/drivers/amlogic/media/common/codec_mm/codec_mm.c b/drivers/amlogic/media/common/codec_mm/codec_mm.c index ac9b810..23417d6 100644 --- a/drivers/amlogic/media/common/codec_mm/codec_mm.c +++ b/drivers/amlogic/media/common/codec_mm/codec_mm.c @@ -44,6 +44,9 @@ #include "codec_mm_priv.h" #include "codec_mm_scatter_priv.h" #include "codec_mm_keeper_priv.h" +#include +#include +#include #define TVP_POOL_NAME "TVP_POOL" #define CMA_RES_POOL_NAME "CMA_RES" @@ -51,7 +54,6 @@ #define CONFIG_PATH "media.codec_mm" #define CONFIG_PREFIX "media" - #define MM_ALIGN_DOWN(addr, size) ((addr) & (~((size) - 1))) #define MM_ALIGN_UP2N(addr, alg2n) ((addr+(1<lock, flags); + + list_for_each_entry(mem, &mgt->mem_list, list) { + if (phy_addr >= mem->phy_addr && + phy_addr < mem->phy_addr + mem->buffer_size) { + + if (mem->vbuffer) + vaddr = mem->vbuffer + + (phy_addr - mem->phy_addr); + break; + } + } + + spin_unlock_irqrestore(&mgt->lock, flags); + + return vaddr; +} + +u8 *codec_mm_vmap(ulong addr, u32 size) +{ + u8 *vaddr = NULL; + ulong phys = addr; + u32 offset = phys & ~PAGE_MASK; + u32 npages = PAGE_ALIGN(size) / PAGE_SIZE; + struct page **pages = NULL; + pgprot_t pgprot; + int i; + + if (!PageHighMem(phys_to_page(phys))) + return phys_to_virt(phys); + + if (offset) + npages++; + + pages = vmalloc(sizeof(struct page *) * npages); + if (!pages) + return NULL; + + for (i = 0; i < npages; i++) { + pages[i] = phys_to_page(phys); + phys += PAGE_SIZE; + } + + /*nocache*/ + pgprot = pgprot_writecombine(PAGE_KERNEL); + + vaddr = vmap(pages, npages, VM_MAP, pgprot); + if (!vaddr) { + pr_err("the phy(%lx) vmaped fail, size: %d\n", + addr - offset, npages << PAGE_SHIFT); + vfree(pages); + return NULL; + } + + vfree(pages); + + if (debug_mode & 0x20) { + pr_info("[HIGH-MEM-MAP] %s, pa(%lx) to va(%p), size: %d\n", + __func__, addr, vaddr + offset, npages << PAGE_SHIFT); + } + + return vaddr + offset; +} +EXPORT_SYMBOL(codec_mm_vmap); + +void codec_mm_unmap_phyaddr(u8 *vaddr) +{ + void *addr = (void *)(PAGE_MASK & (ulong)vaddr); + + vunmap(addr); +} +EXPORT_SYMBOL(codec_mm_unmap_phyaddr); + +static void *codec_mm_map_phyaddr(struct codec_mm_s *mem) +{ + void *vaddr = NULL; + unsigned int phys = mem->phy_addr; + unsigned int size = mem->buffer_size; + + if (!PageHighMem(phys_to_page(phys))) + return phys_to_virt(phys); + + vaddr = codec_mm_vmap(phys, size); + /*vaddr = ioremap_nocache(phy_addr, size);*/ + + mem->flags |= CODEC_MM_FLAGS_FOR_PHYS_VMAPED; + + return vaddr; +} + static int codec_mm_alloc_in( struct codec_mm_mgt_s *mgt, struct codec_mm_s *mem) { @@ -417,9 +520,13 @@ static int codec_mm_alloc_in( align_2n - PAGE_SHIFT); mem->from_flags = AMPORTS_MEM_FLAGS_FROM_GET_FROM_CMA; if (mem->mem_handle) { - mem->vbuffer = mem->mem_handle; mem->phy_addr = - page_to_phys((struct page *)mem->mem_handle); + page_to_phys((struct page *) + mem->mem_handle); + + if (mem->flags & CODEC_MM_FLAGS_CPU) + mem->vbuffer = + codec_mm_map_phyaddr(mem); #ifdef CONFIG_ARM64 if (mem->flags & CODEC_MM_FLAGS_CMA_CLEAR) { /*dma_clear_buffer((struct page *)*/ @@ -495,6 +602,9 @@ static void codec_mm_free_in(struct codec_mm_mgt_s *mgt, { unsigned long flags; if (mem->from_flags == AMPORTS_MEM_FLAGS_FROM_GET_FROM_CMA) { + if (mem->flags & CODEC_MM_FLAGS_FOR_PHYS_VMAPED) + codec_mm_unmap_phyaddr(mem->vbuffer); + dma_release_from_contiguous(mgt->dev, mem->mem_handle, mem->page_count); } else if (mem->from_flags == @@ -522,6 +632,10 @@ static void codec_mm_free_in(struct codec_mm_mgt_s *mgt, mgt->alloced_for_sc_size -= mem->buffer_size; mgt->alloced_for_sc_cnt--; } + + if (mem->flags & CODEC_MM_FLAGS_FOR_PHYS_VMAPED) + mgt->phys_vmaped_page_cnt -= mem->page_count; + if (mem->from_flags == AMPORTS_MEM_FLAGS_FROM_GET_FROM_CMA) { mgt->alloced_cma_size -= mem->buffer_size; } else if (mem->from_flags == @@ -534,6 +648,7 @@ static void codec_mm_free_in(struct codec_mm_mgt_s *mgt, } else if (mem->from_flags == AMPORTS_MEM_FLAGS_FROM_GET_FROM_CMA_RES) { mgt->cma_res_pool.alloced_size -= mem->buffer_size; } + spin_unlock_irqrestore(&mgt->lock, flags); return; @@ -634,6 +749,10 @@ struct codec_mm_s *codec_mm_alloc(const char *owner, int size, mgt->alloced_for_sc_size += mem->buffer_size; mgt->alloced_for_sc_cnt++; } + + if (mem->flags & CODEC_MM_FLAGS_FOR_PHYS_VMAPED) + mgt->phys_vmaped_page_cnt += mem->page_count; + spin_unlock_irqrestore(&mgt->lock, flags); mem->alloced_jiffies = get_jiffies_64(); if (debug_mode & 0x20) @@ -1100,11 +1219,11 @@ void *codec_mm_phys_to_virt(unsigned long phy_addr) if (phy_addr >= mgt->rmem.base && phy_addr < mgt->rmem.base + mgt->rmem.size) { if (mgt->res_mem_flags & RES_MEM_FLAGS_HAVE_MAPED) - return phys_to_virt(phy_addr); + return codec_mm_search_vaddr(phy_addr); return NULL; /* no virt for reserved memory; */ } - return phys_to_virt(phy_addr); + return codec_mm_search_vaddr(phy_addr); } EXPORT_SYMBOL(codec_mm_phys_to_virt); @@ -1189,11 +1308,12 @@ static int dump_mem_infos(void *buf, int size) pbuf += s; s = snprintf(pbuf, size - tsize, - "\tCMA:%d,RES:%d,TVP:%d,SYS:%d MB\n", + "\tCMA:%d,RES:%d,TVP:%d,SYS:%d,VMAPED:%d MB\n", mgt->alloced_cma_size / SZ_1M, mgt->alloced_res_size / SZ_1M, mgt->tvp_pool.alloced_size / SZ_1M, - mgt->alloced_sys_size / SZ_1M); + mgt->alloced_sys_size / SZ_1M, + (mgt->phys_vmaped_page_cnt << PAGE_SHIFT) / SZ_1M); tsize += s; pbuf += s; diff --git a/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c b/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c index 18befa0..4f7e066 100644 --- a/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c +++ b/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c @@ -3297,7 +3297,7 @@ int ppmgr_buffer_init(int vout_mode) int buf_size; struct vinfo_s vinfo = {.width = 1280, .height = 720, }; /* int flags = CODEC_MM_FLAGS_DMA; */ - int flags = CODEC_MM_FLAGS_DMA_CPU|CODEC_MM_FLAGS_CMA_CLEAR; + int flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_CMA_CLEAR; #ifdef INTERLACE_DROP_MODE mycount = 0; #endif diff --git a/drivers/amlogic/media/video_processor/video_dev/amlvideo2.c b/drivers/amlogic/media/video_processor/video_dev/amlvideo2.c index cc8127a..8a58211 100644 --- a/drivers/amlogic/media/video_processor/video_dev/amlvideo2.c +++ b/drivers/amlogic/media/video_processor/video_dev/amlvideo2.c @@ -5353,7 +5353,7 @@ int amlvideo2_cma_buf_init(struct amlvideo2_device *vid_dev, int node_id) return -1; } } else { - flags = CODEC_MM_FLAGS_DMA_CPU| + flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_CMA_CLEAR; if (node_id == 0) { if (vid_dev->node[node_id]-> diff --git a/drivers/amlogic/media/video_sink/video_keeper.c b/drivers/amlogic/media/video_sink/video_keeper.c index 94b2c34..1dbfcd4 100644 --- a/drivers/amlogic/media/video_sink/video_keeper.c +++ b/drivers/amlogic/media/video_sink/video_keeper.c @@ -633,8 +633,7 @@ static int alloc_keep_buffer(void) * if not used ge2d. * need CPU access. */ - flags = CODEC_MM_FLAGS_DMA_CPU | - CODEC_MM_FLAGS_FOR_VDECODER; + flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_FOR_VDECODER; #endif if ((flags & CODEC_MM_FLAGS_FOR_VDECODER) && codec_mm_video_tvp_enabled())/*TVP TODO for MULTI*/ diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c b/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c index 5ae4c2d..edfa775 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c @@ -397,7 +397,7 @@ unsigned int vdin_cma_alloc(struct vdin_dev_s *devp) { unsigned int mem_size, h_size, v_size; int flags = CODEC_MM_FLAGS_CMA_FIRST|CODEC_MM_FLAGS_CMA_CLEAR| - CODEC_MM_FLAGS_CPU; + CODEC_MM_FLAGS_DMA; unsigned int max_buffer_num = min_buf_num; unsigned int i; diff --git a/drivers/staging/android/ion/ion_codec_mm_heap.c b/drivers/staging/android/ion/ion_codec_mm_heap.c index 074992f..3e1ca5e 100644 --- a/drivers/staging/android/ion/ion_codec_mm_heap.c +++ b/drivers/staging/android/ion/ion_codec_mm_heap.c @@ -54,7 +54,7 @@ ion_phys_addr_t ion_codec_mm_allocate(struct ion_heap *heap, CODEC_MM_ION, size / PAGE_SIZE, 0, - CODEC_MM_FLAGS_DMA_CPU); + CODEC_MM_FLAGS_DMA); if (!offset) { pr_err("ion_codec_mm_allocate failed out size %d\n", (int)size); diff --git a/include/linux/amlogic/media/codec_mm/codec_mm.h b/include/linux/amlogic/media/codec_mm/codec_mm.h index 500385b..7108cb4 100644 --- a/include/linux/amlogic/media/codec_mm/codec_mm.h +++ b/include/linux/amlogic/media/codec_mm/codec_mm.h @@ -61,6 +61,9 @@ /*used scatter manager*/ #define CODEC_MM_FLAGS_FOR_SCATTER 0x10000000 +/*used for cnt phys vmaped*/ +#define CODEC_MM_FLAGS_FOR_PHYS_VMAPED 0x20000000 + #define CODEC_MM_FLAGS_FROM_MASK \ (CODEC_MM_FLAGS_DMA |\ CODEC_MM_FLAGS_CPU |\ @@ -136,6 +139,8 @@ int codec_mm_free_for_dma(const char *owner, unsigned long phy_addr); void *codec_mm_phys_to_virt(unsigned long phy_addr); unsigned long codec_mm_virt_to_phys(void *vaddr); +u8 *codec_mm_vmap(ulong addr, u32 size); +void codec_mm_unmap_phyaddr(u8 *vaddr); void codec_mm_dma_flush(void *vaddr, int size, -- 2.7.4