diff options
author | Robby Cai <R63905@freescale.com> | 2013-12-20 05:20:47 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:47:31 -0400 |
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 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. | 2 | * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -168,6 +168,30 @@ struct v4l2_queryctrl pxp_controls[] = { | |||
168 | }, | 168 | }, |
169 | }; | 169 | }; |
170 | 170 | ||
171 | static void free_dma_buf(struct pxps *pxp, struct dma_mem *buf) | ||
172 | { | ||
173 | dma_free_coherent(&pxp->pdev->dev, buf->size, buf->vaddr, buf->paddr); | ||
174 | dev_dbg(&pxp->pdev->dev, | ||
175 | "free dma size:0x%x, paddr:0x%x\n", | ||
176 | buf->size, buf->paddr); | ||
177 | memset(buf, 0, sizeof(*buf)); | ||
178 | } | ||
179 | |||
180 | static int alloc_dma_buf(struct pxps *pxp, struct dma_mem *buf) | ||
181 | { | ||
182 | |||
183 | buf->vaddr = dma_alloc_coherent(&pxp->pdev->dev, buf->size, &buf->paddr, | ||
184 | GFP_DMA | GFP_KERNEL); | ||
185 | if (!buf->vaddr) { | ||
186 | dev_err(&pxp->pdev->dev, | ||
187 | "cannot get dma buf size:0x%x\n", buf->size); | ||
188 | return -ENOMEM; | ||
189 | } | ||
190 | dev_dbg(&pxp->pdev->dev, | ||
191 | "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
171 | /* callback function */ | 195 | /* callback function */ |
172 | static void video_dma_done(void *arg) | 196 | static void video_dma_done(void *arg) |
173 | { | 197 | { |
@@ -300,7 +324,7 @@ static int pxp_show_buf(struct pxps *pxp, bool toshow) | |||
300 | 324 | ||
301 | console_lock(); | 325 | console_lock(); |
302 | fbi->fix.smem_start = toshow ? | 326 | fbi->fix.smem_start = toshow ? |
303 | pxp->outb_phys : (unsigned long)pxp->fb.base; | 327 | pxp->outbuf.paddr : (unsigned long)pxp->fb.base; |
304 | ret = fb_pan_display(fbi, &fbi->var); | 328 | ret = fb_pan_display(fbi, &fbi->var); |
305 | console_unlock(); | 329 | console_unlock(); |
306 | 330 | ||
@@ -381,7 +405,7 @@ static int pxp_enumoutput(struct file *file, void *fh, | |||
381 | } | 405 | } |
382 | o->type = V4L2_OUTPUT_TYPE_INTERNAL; | 406 | o->type = V4L2_OUTPUT_TYPE_INTERNAL; |
383 | o->std = 0; | 407 | o->std = 0; |
384 | o->reserved[0] = pxp->outb_phys; | 408 | o->reserved[0] = pxp->outbuf.paddr; |
385 | 409 | ||
386 | return 0; | 410 | return 0; |
387 | } | 411 | } |
@@ -401,30 +425,27 @@ static int pxp_s_output(struct file *file, void *fh, | |||
401 | { | 425 | { |
402 | struct pxps *pxp = video_get_drvdata(video_devdata(file)); | 426 | struct pxps *pxp = video_get_drvdata(video_devdata(file)); |
403 | struct v4l2_pix_format *fmt = &pxp->fb.fmt; | 427 | struct v4l2_pix_format *fmt = &pxp->fb.fmt; |
404 | int bpp; | 428 | u32 size; |
429 | int ret, bpp; | ||
405 | 430 | ||
406 | if ((i < 0) || (i > 1)) | 431 | if ((i < 0) || (i > 1)) |
407 | return -EINVAL; | 432 | return -EINVAL; |
408 | 433 | ||
409 | if (pxp->outb) | ||
410 | return 0; | ||
411 | |||
412 | /* Output buffer is same format as fbdev */ | 434 | /* Output buffer is same format as fbdev */ |
413 | if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) | 435 | if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) |
414 | bpp = 4; | 436 | bpp = 4; |
415 | else | 437 | else |
416 | bpp = 2; | 438 | bpp = 2; |
417 | 439 | ||
418 | pxp->outb_size = fmt->width * fmt->height * bpp; | 440 | size = fmt->width * fmt->height * bpp; |
419 | pxp->outb = kmalloc(fmt->width * fmt->height * bpp, | 441 | if (size > pxp->outbuf.size) { |
420 | GFP_KERNEL | GFP_DMA); | 442 | if (pxp->outbuf.vaddr) |
421 | if (pxp->outb == NULL) { | 443 | free_dma_buf(pxp, &pxp->outbuf); |
422 | dev_err(&pxp->pdev->dev, "No enough memory!\n"); | 444 | pxp->outbuf.size = size; |
423 | return -ENOMEM; | 445 | ret = alloc_dma_buf(pxp, &pxp->outbuf); |
446 | if (ret < 0) | ||
447 | return ret; | ||
424 | } | 448 | } |
425 | pxp->outb_phys = virt_to_phys(pxp->outb); | ||
426 | dma_map_single(NULL, pxp->outb, | ||
427 | fmt->width * fmt->height * bpp, DMA_TO_DEVICE); | ||
428 | 449 | ||
429 | pxp->pxp_conf.out_param.width = fmt->width; | 450 | pxp->pxp_conf.out_param.width = fmt->width; |
430 | pxp->pxp_conf.out_param.height = fmt->height; | 451 | pxp->pxp_conf.out_param.height = fmt->height; |
@@ -726,6 +747,12 @@ static int pxp_buf_prepare(struct videobuf_queue *q, | |||
726 | int ret = 0; | 747 | int ret = 0; |
727 | int i, length; | 748 | int i, length; |
728 | 749 | ||
750 | if (!pxp->outbuf.paddr) { | ||
751 | dev_err(&pxp->pdev->dev, "Not allocate memory for " | ||
752 | "PxP Out buffer?\n"); | ||
753 | return -ENOMEM; | ||
754 | } | ||
755 | |||
729 | vb->width = pxp->pxp_conf.s0_param.width; | 756 | vb->width = pxp->pxp_conf.s0_param.width; |
730 | vb->height = pxp->pxp_conf.s0_param.height; | 757 | vb->height = pxp->pxp_conf.s0_param.height; |
731 | vb->size = vb->width * vb->height * pxp->s0_fmt->bpp; | 758 | vb->size = vb->width * vb->height * pxp->s0_fmt->bpp; |
@@ -785,7 +812,7 @@ static int pxp_buf_prepare(struct videobuf_queue *q, | |||
785 | pxp->fb.fmt.height; | 812 | pxp->fb.fmt.height; |
786 | } | 813 | } |
787 | 814 | ||
788 | pxp_conf->out_param.paddr = pxp->outb_phys; | 815 | pxp_conf->out_param.paddr = pxp->outbuf.paddr; |
789 | memcpy(&desc->layer_param.out_param, | 816 | memcpy(&desc->layer_param.out_param, |
790 | &pxp_conf->out_param, | 817 | &pxp_conf->out_param, |
791 | sizeof(struct pxp_layer_param)); | 818 | sizeof(struct pxp_layer_param)); |
@@ -1100,8 +1127,6 @@ static int pxp_close(struct file *file) | |||
1100 | videobuf_stop(&pxp->s0_vbq); | 1127 | videobuf_stop(&pxp->s0_vbq); |
1101 | videobuf_mmap_free(&pxp->s0_vbq); | 1128 | videobuf_mmap_free(&pxp->s0_vbq); |
1102 | pxp->active = NULL; | 1129 | pxp->active = NULL; |
1103 | kfree(pxp->outb); | ||
1104 | pxp->outb = NULL; | ||
1105 | 1130 | ||
1106 | mutex_lock(&pxp->mutex); | 1131 | mutex_lock(&pxp->mutex); |
1107 | pxp->users--; | 1132 | pxp->users--; |
@@ -1238,6 +1263,8 @@ static int pxp_remove(struct platform_device *pdev) | |||
1238 | video_unregister_device(pxp->vdev); | 1263 | video_unregister_device(pxp->vdev); |
1239 | video_device_release(pxp->vdev); | 1264 | video_device_release(pxp->vdev); |
1240 | 1265 | ||
1266 | free_dma_buf(pxp, &pxp->outbuf); | ||
1267 | |||
1241 | kfree(pxp); | 1268 | kfree(pxp); |
1242 | 1269 | ||
1243 | return 0; | 1270 | 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 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. | 2 | * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -37,6 +37,12 @@ struct pxp_buffer { | |||
37 | struct scatterlist sg[3]; | 37 | struct scatterlist sg[3]; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct dma_mem { | ||
41 | void *vaddr; | ||
42 | dma_addr_t paddr; | ||
43 | size_t size; | ||
44 | }; | ||
45 | |||
40 | struct pxps { | 46 | struct pxps { |
41 | struct platform_device *pdev; | 47 | struct platform_device *pdev; |
42 | 48 | ||
@@ -51,11 +57,9 @@ struct pxps { | |||
51 | struct list_head outq; | 57 | struct list_head outq; |
52 | struct pxp_channel *pxp_channel[1]; /* We need 1 channel */ | 58 | struct pxp_channel *pxp_channel[1]; /* We need 1 channel */ |
53 | struct pxp_config_data pxp_conf; | 59 | struct pxp_config_data pxp_conf; |
60 | struct dma_mem outbuf; | ||
54 | 61 | ||
55 | int output; | 62 | int output; |
56 | u32 *outb; | ||
57 | dma_addr_t outb_phys; | ||
58 | u32 outb_size; | ||
59 | 63 | ||
60 | /* Current S0 configuration */ | 64 | /* Current S0 configuration */ |
61 | struct pxp_data_format *s0_fmt; | 65 | struct pxp_data_format *s0_fmt; |