diff options
author | Robby Cai <R63905@freescale.com> | 2013-12-20 18:20:47 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 08:47:31 -0500 |
commit | c60c2626756cdf54d48bd6070f25928b2edf6088 (patch) | |
tree | ed82b40d7bc4bb30d7e89852c6935aae9080ab48 /drivers/media | |
parent | da556c02559574c290cf975fb53b4d3cedd1db31 (diff) |
ENGR00293132-1 pxp/v4l2: change memory alloc policy for PxP output buffer
In previous implementation, the memory allocation/free for PxP output buffer is
done each time v4l2 output device is opened/closed. This is not necessary and
may cause memory fragmentation issue after running many many times. Now we
re-allocate the memory for it only if the existing memory size is not sufficent
for new case.
Signed-off-by: Robby Cai <R63905@freescale.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/mxc/output/mxc_pxp_v4l2.c | 65 | ||||
-rw-r--r-- | drivers/media/platform/mxc/output/mxc_pxp_v4l2.h | 12 |
2 files changed, 54 insertions, 23 deletions
diff --git a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c index 8fe072ecbf1c..08ea59ab5510 100644 --- a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c +++ b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -168,6 +168,30 @@ struct v4l2_queryctrl pxp_controls[] = { }, }; +static void free_dma_buf(struct pxps *pxp, struct dma_mem *buf) +{ + dma_free_coherent(&pxp->pdev->dev, buf->size, buf->vaddr, buf->paddr); + dev_dbg(&pxp->pdev->dev, + "free dma size:0x%x, paddr:0x%x\n", + buf->size, buf->paddr); + memset(buf, 0, sizeof(*buf)); +} + +static int alloc_dma_buf(struct pxps *pxp, struct dma_mem *buf) +{ + + buf->vaddr = dma_alloc_coherent(&pxp->pdev->dev, buf->size, &buf->paddr, + GFP_DMA | GFP_KERNEL); + if (!buf->vaddr) { + dev_err(&pxp->pdev->dev, + "cannot get dma buf size:0x%x\n", buf->size); + return -ENOMEM; + } + dev_dbg(&pxp->pdev->dev, + "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr); + return 0; +} + /* callback function */ static void video_dma_done(void *arg) { @@ -300,7 +324,7 @@ static int pxp_show_buf(struct pxps *pxp, bool toshow) console_lock(); fbi->fix.smem_start = toshow ? - pxp->outb_phys : (unsigned long)pxp->fb.base; + pxp->outbuf.paddr : (unsigned long)pxp->fb.base; ret = fb_pan_display(fbi, &fbi->var); console_unlock(); @@ -381,7 +405,7 @@ static int pxp_enumoutput(struct file *file, void *fh, } o->type = V4L2_OUTPUT_TYPE_INTERNAL; o->std = 0; - o->reserved[0] = pxp->outb_phys; + o->reserved[0] = pxp->outbuf.paddr; return 0; } @@ -401,30 +425,27 @@ static int pxp_s_output(struct file *file, void *fh, { struct pxps *pxp = video_get_drvdata(video_devdata(file)); struct v4l2_pix_format *fmt = &pxp->fb.fmt; - int bpp; + u32 size; + int ret, bpp; if ((i < 0) || (i > 1)) return -EINVAL; - if (pxp->outb) - return 0; - /* Output buffer is same format as fbdev */ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) bpp = 4; else bpp = 2; - pxp->outb_size = fmt->width * fmt->height * bpp; - pxp->outb = kmalloc(fmt->width * fmt->height * bpp, - GFP_KERNEL | GFP_DMA); - if (pxp->outb == NULL) { - dev_err(&pxp->pdev->dev, "No enough memory!\n"); - return -ENOMEM; + size = fmt->width * fmt->height * bpp; + if (size > pxp->outbuf.size) { + if (pxp->outbuf.vaddr) + free_dma_buf(pxp, &pxp->outbuf); + pxp->outbuf.size = size; + ret = alloc_dma_buf(pxp, &pxp->outbuf); + if (ret < 0) + return ret; } - pxp->outb_phys = virt_to_phys(pxp->outb); - dma_map_single(NULL, pxp->outb, - fmt->width * fmt->height * bpp, DMA_TO_DEVICE); pxp->pxp_conf.out_param.width = fmt->width; pxp->pxp_conf.out_param.height = fmt->height; @@ -726,6 +747,12 @@ static int pxp_buf_prepare(struct videobuf_queue *q, int ret = 0; int i, length; + if (!pxp->outbuf.paddr) { + dev_err(&pxp->pdev->dev, "Not allocate memory for " + "PxP Out buffer?\n"); + return -ENOMEM; + } + vb->width = pxp->pxp_conf.s0_param.width; vb->height = pxp->pxp_conf.s0_param.height; vb->size = vb->width * vb->height * pxp->s0_fmt->bpp; @@ -785,7 +812,7 @@ static int pxp_buf_prepare(struct videobuf_queue *q, pxp->fb.fmt.height; } - pxp_conf->out_param.paddr = pxp->outb_phys; + pxp_conf->out_param.paddr = pxp->outbuf.paddr; memcpy(&desc->layer_param.out_param, &pxp_conf->out_param, sizeof(struct pxp_layer_param)); @@ -1100,8 +1127,6 @@ static int pxp_close(struct file *file) videobuf_stop(&pxp->s0_vbq); videobuf_mmap_free(&pxp->s0_vbq); pxp->active = NULL; - kfree(pxp->outb); - pxp->outb = NULL; mutex_lock(&pxp->mutex); pxp->users--; @@ -1238,6 +1263,8 @@ static int pxp_remove(struct platform_device *pdev) video_unregister_device(pxp->vdev); video_device_release(pxp->vdev); + free_dma_buf(pxp, &pxp->outbuf); + kfree(pxp); return 0; diff --git a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h index f1d3da78c345..8abb4c17f3fd 100644 --- a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h +++ b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +37,12 @@ struct pxp_buffer { struct scatterlist sg[3]; }; +struct dma_mem { + void *vaddr; + dma_addr_t paddr; + size_t size; +}; + struct pxps { struct platform_device *pdev; @@ -51,11 +57,9 @@ struct pxps { struct list_head outq; struct pxp_channel *pxp_channel[1]; /* We need 1 channel */ struct pxp_config_data pxp_conf; + struct dma_mem outbuf; int output; - u32 *outb; - dma_addr_t outb_phys; - u32 outb_size; /* Current S0 configuration */ struct pxp_data_format *s0_fmt; |