[media] coda: allocate bitstream buffer from REQBUFS, size depends on the format
authorPhilipp Zabel <p.zabel@pengutronix.de>
Tue, 24 Mar 2015 17:30:52 +0000 (14:30 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Fri, 10 Apr 2015 13:07:58 +0000 (10:07 -0300)
Allocating the bitstream buffer only when the format is set allows to guarantee
that at least two frames fit into the bitstream buffer. For small frame sizes
a smaller bitstream buffer can be allocated. Since the bitstream buffer size now
depends on the format, replace CODA_MAX_FRAME_SIZE with ctx->bitstream.size
where appropriate and remove the now unused constant.
Since REQBUFS can be called multiple times, but the format can't be changed
unless REQBUFS 0 was called before, we can just keep the allocated context and
bitstream buffers if REQBUFS is called multiple times with a non-zero buffer
count.

[fixed a resource leak preventing repeatedly decoding]

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/platform/coda/coda-bit.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/coda/coda.h

index 12b93867e6657b3eb21572f22a7834d0c2af1639..5aa8d8774d0c6acd0f4241d8a2e2f7e1c7c09d25 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/clk.h>
 #include <linux/irqreturn.h>
 #include <linux/kernel.h>
+#include <linux/log2.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
@@ -36,6 +37,8 @@
 #define CODA_DEFAULT_GAMMA     4096
 #define CODA9_DEFAULT_GAMMA    24576   /* 0.75 * 32768 */
 
+static void coda_free_bitstream_buffer(struct coda_ctx *ctx);
+
 static inline int coda_is_initialized(struct coda_dev *dev)
 {
        return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
@@ -389,21 +392,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
        if (dev->devtype->product == CODA_DX6)
                return 0;
 
-       if (ctx->psbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->slicebuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->workbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
-               ret = -EBUSY;
-               return -ENOMEM;
-       }
-
-       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+       if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {
                /* worst case slice size */
                size = (DIV_ROUND_UP(q_data->width, 16) *
                        DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
@@ -417,7 +406,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
                }
        }
 
-       if (dev->devtype->product == CODA_7541) {
+       if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) {
                ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
                                             CODA7_PS_BUF_SIZE, "psbuf");
                if (ret < 0) {
@@ -427,16 +416,19 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
                }
        }
 
-       size = dev->devtype->workbuf_size;
-       if (dev->devtype->product == CODA_960 &&
-           q_data->fourcc == V4L2_PIX_FMT_H264)
-               size += CODA9_PS_SAVE_SIZE;
-       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to allocate %d byte context buffer",
-                        ctx->workbuf.size);
-               goto err;
+       if (!ctx->workbuf.vaddr) {
+               size = dev->devtype->workbuf_size;
+               if (dev->devtype->product == CODA_960 &&
+                   q_data->fourcc == V4L2_PIX_FMT_H264)
+                       size += CODA9_PS_SAVE_SIZE;
+               ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size,
+                                            "workbuf");
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to allocate %d byte context buffer",
+                                ctx->workbuf.size);
+                       goto err;
+               }
        }
 
        return 0;
@@ -1337,6 +1329,7 @@ static void coda_bit_release(struct coda_ctx *ctx)
        mutex_lock(&ctx->buffer_mutex);
        coda_free_framebuffers(ctx);
        coda_free_context_buffers(ctx);
+       coda_free_bitstream_buffer(ctx);
        mutex_unlock(&ctx->buffer_mutex);
 }
 
@@ -1354,6 +1347,38 @@ const struct coda_context_ops coda_bit_encode_ops = {
  * Decoder context operations
  */
 
+static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
+                                      struct coda_q_data *q_data)
+{
+       if (ctx->bitstream.vaddr)
+               return 0;
+
+       ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
+       ctx->bitstream.vaddr = dma_alloc_writecombine(
+                       &ctx->dev->plat_dev->dev, ctx->bitstream.size,
+                       &ctx->bitstream.paddr, GFP_KERNEL);
+       if (!ctx->bitstream.vaddr) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "failed to allocate bitstream ringbuffer");
+               return -ENOMEM;
+       }
+       kfifo_init(&ctx->bitstream_fifo,
+                  ctx->bitstream.vaddr, ctx->bitstream.size);
+
+       return 0;
+}
+
+static void coda_free_bitstream_buffer(struct coda_ctx *ctx)
+{
+       if (ctx->bitstream.vaddr == NULL)
+               return;
+
+       dma_free_writecombine(&ctx->dev->plat_dev->dev, ctx->bitstream.size,
+                             ctx->bitstream.vaddr, ctx->bitstream.paddr);
+       ctx->bitstream.vaddr = NULL;
+       kfifo_init(&ctx->bitstream_fifo, NULL, 0);
+}
+
 static int coda_decoder_reqbufs(struct coda_ctx *ctx,
                                struct v4l2_requestbuffers *rb)
 {
@@ -1368,7 +1393,13 @@ static int coda_decoder_reqbufs(struct coda_ctx *ctx,
                ret = coda_alloc_context_buffers(ctx, q_data_src);
                if (ret < 0)
                        return ret;
+               ret = coda_alloc_bitstream_buffer(ctx, q_data_src);
+               if (ret < 0) {
+                       coda_free_context_buffers(ctx);
+                       return ret;
+               }
        } else {
+               coda_free_bitstream_buffer(ctx);
                coda_free_context_buffers(ctx);
        }
 
@@ -1736,7 +1767,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
         * by up to 512 bytes
         */
        if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
-               if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512)
+               if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512)
                        kfifo_init(&ctx->bitstream_fifo,
                                ctx->bitstream.vaddr, ctx->bitstream.size);
        }
index a8a6c36a1f000daec9d96ddaef0d6c8d861af78b..3a852ac6a8c39ffb14c213962e9d06db98f386b0 100644 (file)
@@ -1723,20 +1723,6 @@ static int coda_open(struct file *file)
                        goto err_dma_alloc;
                }
        }
-       if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) {
-               ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
-               ctx->bitstream.vaddr = dma_alloc_writecombine(
-                               &dev->plat_dev->dev, ctx->bitstream.size,
-                               &ctx->bitstream.paddr, GFP_KERNEL);
-               if (!ctx->bitstream.vaddr) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "failed to allocate bitstream ringbuffer");
-                       ret = -ENOMEM;
-                       goto err_dma_writecombine;
-               }
-       }
-       kfifo_init(&ctx->bitstream_fifo,
-               ctx->bitstream.vaddr, ctx->bitstream.size);
        mutex_init(&ctx->bitstream_mutex);
        mutex_init(&ctx->buffer_mutex);
        INIT_LIST_HEAD(&ctx->buffer_meta_list);
@@ -1750,10 +1736,6 @@ static int coda_open(struct file *file)
 
        return 0;
 
-err_dma_writecombine:
-       if (ctx->dev->devtype->product == CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-       coda_free_aux_buf(dev, &ctx->parabuf);
 err_dma_alloc:
        v4l2_ctrl_handler_free(&ctx->ctrls);
 err_ctrls_setup:
@@ -1798,10 +1780,6 @@ static int coda_release(struct file *file)
        list_del(&ctx->list);
        coda_unlock(ctx);
 
-       if (ctx->bitstream.vaddr) {
-               dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
-                       ctx->bitstream.vaddr, ctx->bitstream.paddr);
-       }
        if (ctx->dev->devtype->product == CODA_DX6)
                coda_free_aux_buf(dev, &ctx->workbuf);
 
index 57d070ce666515253b37f22f9008c5bf26bd2e9a..01d940c630b3e379f469f098a7e6400c8a5da199 100644 (file)
@@ -26,7 +26,6 @@
 #include "coda_regs.h"
 
 #define CODA_MAX_FRAMEBUFFERS  8
-#define CODA_MAX_FRAME_SIZE    0x100000
 #define FMO_SLICE_SAVE_BUF_SIZE        (32)
 
 enum {