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 <nanxin.qin@amlogic.com>
This commit is contained in:
Nanxin Qin
2018-10-25 10:42:17 +08:00
committed by Tao Zeng
parent 8d0507c810
commit 16cbe10144
7 changed files with 137 additions and 13 deletions

View File

@@ -44,6 +44,9 @@
#include "codec_mm_priv.h"
#include "codec_mm_scatter_priv.h"
#include "codec_mm_keeper_priv.h"
#include <linux/highmem.h>
#include <linux/page-flags.h>
#include <linux/vmalloc.h>
#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<<alg2n)-1)&(~((1<<alg2n)-1)))
@@ -138,6 +140,7 @@ struct codec_mm_mgt_s {
int alloced_for_sc_size;
int alloced_for_sc_cnt;
int alloced_from_coherent;
int phys_vmaped_page_cnt;
int alloc_from_sys_pages_max;
int enable_kmalloc_on_nomem;
@@ -267,6 +270,106 @@ static int codec_mm_alloc_pre_check_in(
return have_space;
}
static void *codec_mm_search_vaddr(unsigned long phy_addr)
{
struct codec_mm_mgt_s *mgt = get_mem_mgt();
struct codec_mm_s *mem = NULL;
void *vaddr = NULL;
unsigned long flags;
if (!PageHighMem(phys_to_page(phy_addr)))
return phys_to_virt(phy_addr);
spin_lock_irqsave(&mgt->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;

View File

@@ -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

View File

@@ -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]->

View File

@@ -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*/

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,