[media] s5p-mfc: Fixes for decode REQBUFS

- Honor return values from vb2_reqbufs on REQBUFS(0).

- Do not set the number of allocated buffers to 0 if userspace tries
  to request buffers again without freeing them.

- There is no need to verify correct instance state on reqbufs, as we will
  verify this in queue_setup().

- There is also no need to verify that vb2_reqbufs() was able to allocate enough
  buffers (pb_count) and call buf_init on that many buffers (i.e. dst_buf_count
  is at least pb_count), because this will be verified by second queue_setup()
  call as well and vb2_reqbufs() will fail otherwise.

- Only verify state is MFCINST_INIT when allocating, not when freeing.

- Refactor and simplify code.

Signed-off-by: Pawel Osciak <posciak@chromium.org>
Signed-off-by: Arun Kumar K <arun.kk@samsung.com>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Pawel Osciak 2014-05-19 09:32:58 -03:00 committed by Mauro Carvalho Chehab
parent a0517f5d4d
commit 38beac65a2
1 changed files with 102 additions and 82 deletions

View File

@ -462,102 +462,122 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
return ret;
}
static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
struct v4l2_requestbuffers *reqbufs)
{
int ret = 0;
s5p_mfc_clock_on();
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
if (ret)
goto out;
ctx->src_bufs_cnt = 0;
} else if (ctx->output_state == QUEUE_FREE) {
/* Can only request buffers after the instance
* has been opened.
*/
WARN_ON(ctx->src_bufs_cnt != 0);
if (ctx->state != MFCINST_INIT) {
mfc_err("Reqbufs called in an invalid state\n");
ret = -EINVAL;
goto out;
}
mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n",
reqbufs->count);
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
if (ret)
goto out;
ctx->output_state = QUEUE_BUFS_REQUESTED;
} else {
mfc_err("Buffers have already been requested\n");
ret = -EINVAL;
}
out:
s5p_mfc_clock_off();
if (ret)
mfc_err("Failed allocating buffers for OUTPUT queue\n");
return ret;
}
static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
struct v4l2_requestbuffers *reqbufs)
{
int ret = 0;
s5p_mfc_clock_on();
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
if (ret)
goto out;
s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
ctx->dst_bufs_cnt = 0;
} else if (ctx->capture_state == QUEUE_FREE) {
WARN_ON(ctx->dst_bufs_cnt != 0);
mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n",
reqbufs->count);
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
if (ret)
goto out;
ctx->capture_state = QUEUE_BUFS_REQUESTED;
ctx->total_dpb_count = reqbufs->count;
ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx);
if (ret) {
mfc_err("Failed to allocate decoding buffers\n");
reqbufs->count = 0;
vb2_reqbufs(&ctx->vq_dst, reqbufs);
ret = -ENOMEM;
ctx->capture_state = QUEUE_FREE;
goto out;
}
WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count);
ctx->capture_state = QUEUE_BUFS_MMAPED;
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
0);
} else {
mfc_err("Buffers have already been requested\n");
ret = -EINVAL;
}
out:
s5p_mfc_clock_off();
if (ret)
mfc_err("Failed allocating buffers for CAPTURE queue\n");
return ret;
}
/* Reqeust buffers */
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
if (reqbufs->memory != V4L2_MEMORY_MMAP) {
mfc_err("Only V4L2_MEMORY_MAP is supported\n");
return -EINVAL;
}
if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/* Can only request buffers after an instance has been opened.*/
if (ctx->state == MFCINST_INIT) {
ctx->src_bufs_cnt = 0;
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
s5p_mfc_clock_off();
return ret;
}
/* Decoding */
if (ctx->output_state != QUEUE_FREE) {
mfc_err("Bufs have already been requested\n");
return -EINVAL;
}
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
s5p_mfc_clock_off();
if (ret) {
mfc_err("vb2_reqbufs on output failed\n");
return ret;
}
mfc_debug(2, "vb2_reqbufs: %d\n", ret);
ctx->output_state = QUEUE_BUFS_REQUESTED;
}
return reqbufs_output(dev, ctx, reqbufs);
} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
ctx->dst_bufs_cnt = 0;
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
s5p_mfc_clock_off();
return ret;
}
if (ctx->capture_state != QUEUE_FREE) {
mfc_err("Bufs have already been requested\n");
return -EINVAL;
}
ctx->capture_state = QUEUE_BUFS_REQUESTED;
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
s5p_mfc_clock_off();
if (ret) {
mfc_err("vb2_reqbufs on capture failed\n");
return ret;
}
if (reqbufs->count < ctx->pb_count) {
mfc_err("Not enough buffers allocated\n");
reqbufs->count = 0;
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
s5p_mfc_clock_off();
return -ENOMEM;
}
ctx->total_dpb_count = reqbufs->count;
ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx);
if (ret) {
mfc_err("Failed to allocate decoding buffers\n");
reqbufs->count = 0;
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
s5p_mfc_clock_off();
return -ENOMEM;
}
if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
ctx->capture_state = QUEUE_BUFS_MMAPED;
} else {
mfc_err("Not all buffers passed to buf_init\n");
reqbufs->count = 0;
s5p_mfc_clock_on();
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers,
ctx);
s5p_mfc_clock_off();
return -ENOMEM;
}
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0);
return reqbufs_capture(dev, ctx, reqbufs);
} else {
mfc_err("Invalid type requested\n");
return -EINVAL;
}
return ret;
}
/* Query buffer */