summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorRobby Cai <R63905@freescale.com>2013-12-20 18:20:47 +0800
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 08:47:31 -0500
commitc60c2626756cdf54d48bd6070f25928b2edf6088 (patch)
treeed82b40d7bc4bb30d7e89852c6935aae9080ab48 /drivers/media
parentda556c02559574c290cf975fb53b4d3cedd1db31 (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.c65
-rw-r--r--drivers/media/platform/mxc/output/mxc_pxp_v4l2.h12
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;