Hi Marek, On 14/12/17 15:11, Marek Szyprowski wrote: > Hi Hans, > > I would like to get your opinion on this patch. Do you think it makes sense to: > > 1. add limited support for USERPTR and DMA-buf import? (limited means driver will accept setting buffer pointer/fd only once after reqbufs for each buffer index) I don't like this. It's unexpected almost-but-not-quite behavior that will make life very difficult for userspace. > > 2. add a V4L2 device flag to let userspace to discover if device support queue buffer reconfiguration on-fly or not? This seems to me a better approach. It should be possible to implement most/all of this in vb2, but we need to find a way to signal this to the user. Is this an MFC limitation for the decoder, encoder or both? And is it a limitation of the capture or output side or both? Regards, Hans > > Here is the discussion: https://patchwork.linuxtv.org/patch/45305/ > > Best regards > Marek Szyprowski, PhD > Samsung R&D Institute Poland > > > On 2017-11-06 20:21, Nicolas Dufresne wrote: >> Le lundi 06 novembre 2017 à 10:28 +0100, Marek Szyprowski a écrit : >>> On 2017-11-03 14:45, Nicolas Dufresne wrote: >>>> Le vendredi 03 novembre 2017 à 09:11 +0100, Marek Szyprowski a écrit : >>>>> MFC driver supports only MMAP operation mode mainly due to the hardware >>>>> restrictions of the addresses of the DMA buffers (MFC v5 hardware can >>>>> access buffers only in 128MiB memory region starting from the base address >>>>> of its firmware). When IOMMU is available, this requirement is easily >>>>> fulfilled even for the buffers located anywhere in the memory - typically >>>>> by mapping them in the DMA address space as close as possible to the >>>>> firmware. Later hardware revisions don't have this limitations at all. >>>>> >>>>> The second limitation of the MFC hardware related to the memory buffers >>>>> is constant buffer address. Once the hardware has been initialized for >>>>> operation on given buffer set, the addresses of the buffers cannot be >>>>> changed. >>>>> >>>>> With the above assumptions, a limited support for USERPTR and DMABUF >>>>> operation modes can be added. The main requirement is to have all buffers >>>>> known when starting hardware. This has been achieved by postponing >>>>> hardware initialization once all the DMABUF or USERPTR buffers have been >>>>> queued for the first time. Once then, buffers cannot be modified to point >>>>> to other memory area. >>>> I am concerned about enabling this support with existing userspace. >>>> Userspace application will be left with some driver with this >>>> limitation and other drivers without. I think it is harmful to enable >>>> that feature without providing userspace the ability to know. >>>> >>>> This is specially conflicting with let's say UVC driver providing >>>> buffers, since UVC driver implementing CREATE_BUFS ioctl. So even if >>>> userspace start making an effort to maintain the same DMABuf for the >>>> same buffer index, if a new buffer is created, we won't be able to use >>>> it. >>> Sorry, but I don't get this as an 'issue'. The typical use scenario is to >>> configure buffer queue and start streaming. Basically ReqBufs, stream on and >>> a sequence of bufq/bufdq. This is handled without any problem by MFC driver >>> with this patch. After releasing a queue with reqbufs(0), one can use >>> different set of buffers. >> In real life, you often have capture code decorelated from the encoder >> code. At least, it's the case in GStreamer. The encoder have no >> information about how many buffers were pre-allocated by let's say the >> capture driver. As a side effect, we cannot make sure the importation >> queue is of the same size (amount of buffer). Specially if you have UVC >> driver that allow allocating more buffers at run-time. This is used in >> real-life to compensate additional latency that get's added when a >> pipeline topology is changed (at run-time). Only workaround I had in >> mind, would be to always prepare the queue with the maximum (32), and >> use this as a cache size, but for now, this is not how the deployed >> userspace works unfortunately. >> >> Your reqbuf(0) technique cause a break in the stream (probably a new >> keyframe), as you are forced to STREAMOFF. This is often unwanted, and >> it may create a time discontinuity in case the allocation took time. >> >>> What is the point of changing the buffers during the streaming? IMHO it was >>> one of the biggest pathology of the V4L2 USERPTR API that the buffers >>> were in >>> fact 'created' on the first queue operation. By creating I mean creating all >>> the kernel all needed structures and mappings between the real memory (user >>> ptr value) and the buffer index. The result of this was userspace, which >>> don't >>> use buffer indices and always queues buffers with index = 0, what means that >>> kernel has to reacquire direct access to each buffer every single frame. >>> That >>> is highly inefficient approach. DMABUF operation mode inherited this >>> drawback. >> This in fact is an implementation detail of the caching in the kernel >> framework. There is nothing that prevent the framework to maintain a >> validation cache that isn't bound to the queue size. DMABuf simply >> makes the buffer identification easier and safer. I bet it is difficult >> and it will stay like this, so it should at least be documented. >> >> I am completely aware of the inefficiency of the GStreamer behaviour, >> though it remains much faster in many case then copying raw frames >> using the CPU. You can complain as much as you can about what this >> userspace doing, but it as has been working better then nothing for >> many users. It might not be like this forever, someone could optimize >> this by signalling the missing information or with the 32 buffer hack I >> just mention, but I don't see anyone standing up for that work atm, >> which I have assumed to be good enough (for now). We see a lot more >> overhead from other component when piling up with a wayland compositor, >> a GL stack and more. >> >>> When we have a pipeline for processing video data it should use N buffers on >>> both input and output of each element when DMAbuf is used. Once we >>> allocate N >>> buffers, using N dmabuf-imported buffers which maps 1-1 is trivial. Only >>> this >>> way you will have true zero-copy processing without any additional overhead. >> Though, it is not a strict requirement. This is specific to V4L2 here, >> other kernel framework provide rather more flexible API, which indeed >> can have small period of inefficiency (during allocation and first >> importation) but will stabilize later on if userspace implements enough >> caching. Also, the cost of importation will vary a lot per driver. >> >> My point here, is just that we need to know from userspace if there is >> a strict limitation like this, because otherwise it may completely fall >> apart instead of being slightly inefficient. >> >>>>> This patch also removes unconditional USERPTR operation mode from encoder >>>>> video node, because it doesn't work with v5 MFC hardware without IOMMU >>>>> being enabled. >>>>> >>>>> In case of MFC v5 a bidirectional queue flag has to be enabled as a >>>>> workaround of the strange hardware behavior - MFC performs a few writes >>>>> to source data during the operation. >>>> Do you have more information about this ? It is quite terrible, since >>>> if you enable buffer importation, the buffer might be multi-plex across >>>> multiple encoder instance. That is another way this feature can be >>>> harmful to existing userspace. >>> I also don't like this behavior of the hardware. I will probably investigate >>> it further once I have some time. The other workaround would be to >>> always use >>> driver allocated buffers and simply copy input stream in case of USERPTR or >>> DMABUF to avoid modifying source data. It would mean copying the compressed >>> stream, what should not hurt us that much. >> Thanks for letting us know. So the writes are strictly for the decoder >> ? I was referring to the encoder in my comment. On Qualcomm Venus side, >> the writes are done in a portion expose to user space (see data_offset >> in mplane structures). As a side effect, importation is skipped, since >> there is no upstream driver that will magically provide this padding >> data. >> >>>>> Signed-off-by: Seung-Woo Kim <sw0312.kim@xxxxxxxxxxx> >>>>> [mszyprow: adapted to v4.14 code base, rewrote and extended commit message, >>>>> added checks for changing buffer addresses, added bidirectional queue >>>>> flags and comments] >>>>> Signed-off-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> >>>>> --- >>>>> v2: >>>>> - fixed copy/paste bug, which broke encoding support (thanks to Marian >>>>> Mihailescu for reporting it) >>>>> - added checks for changing buffers DMA addresses >>>>> - added bidirectional queue flags >>>>> >>>>> v1: >>>>> - inital version >>>>> --- >>>>> drivers/media/platform/s5p-mfc/s5p_mfc.c | 23 +++++- >>>>> drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 111 +++++++++++++++++++-------- >>>>> drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 64 +++++++++++---- >>>>> 3 files changed, 147 insertions(+), 51 deletions(-) >>>>> >>>>> diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c >>>>> index 1839a86cc2a5..f1ab8d198158 100644 >>>>> --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c >>>>> +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c >>>>> @@ -754,6 +754,7 @@ static int s5p_mfc_open(struct file *file) >>>>> struct s5p_mfc_dev *dev = video_drvdata(file); >>>>> struct s5p_mfc_ctx *ctx = NULL; >>>>> struct vb2_queue *q; >>>>> + unsigned int io_modes; >>>>> int ret = 0; >>>>> mfc_debug_enter(); >>>>> @@ -839,16 +840,25 @@ static int s5p_mfc_open(struct file *file) >>>>> if (ret) >>>>> goto err_init_hw; >>>>> } >>>>> + >>>>> + io_modes = VB2_MMAP; >>>>> + if (exynos_is_iommu_available(&dev->plat_dev->dev) || !IS_TWOPORT(dev)) >>>>> + io_modes |= VB2_USERPTR | VB2_DMABUF; >>>>> + >>>>> /* Init videobuf2 queue for CAPTURE */ >>>>> q = &ctx->vq_dst; >>>>> q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; >>>>> + q->io_modes = io_modes; >>>>> + /* >>>>> + * Destination buffers are always bidirectional, they use used as >>>>> + * reference data, which require READ access >>>>> + */ >>>>> + q->bidirectional = true; >>>>> q->drv_priv = &ctx->fh; >>>>> q->lock = &dev->mfc_mutex; >>>>> if (vdev == dev->vfd_dec) { >>>>> - q->io_modes = VB2_MMAP; >>>>> q->ops = get_dec_queue_ops(); >>>>> } else if (vdev == dev->vfd_enc) { >>>>> - q->io_modes = VB2_MMAP | VB2_USERPTR; >>>>> q->ops = get_enc_queue_ops(); >>>>> } else { >>>>> ret = -ENOENT; >>>>> @@ -869,13 +879,18 @@ static int s5p_mfc_open(struct file *file) >>>>> /* Init videobuf2 queue for OUTPUT */ >>>>> q = &ctx->vq_src; >>>>> q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; >>>>> + q->io_modes = io_modes; >>>>> + /* >>>>> + * MFV v5 performs write operations on source data, so make queue >>>>> + * bidirectional to avoid IOMMU protection fault. >>>>> + */ >>>>> + if (!IS_MFCV6_PLUS(dev)) >>>>> + q->bidirectional = true; >>>>> q->drv_priv = &ctx->fh; >>>>> q->lock = &dev->mfc_mutex; >>>>> if (vdev == dev->vfd_dec) { >>>>> - q->io_modes = VB2_MMAP; >>>>> q->ops = get_dec_queue_ops(); >>>>> } else if (vdev == dev->vfd_enc) { >>>>> - q->io_modes = VB2_MMAP | VB2_USERPTR; >>>>> q->ops = get_enc_queue_ops(); >>>>> } else { >>>>> ret = -ENOENT; >>>>> diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c >>>>> index e3e5c442902a..26ee8315e2cf 100644 >>>>> --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c >>>>> +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c >>>>> @@ -551,14 +551,27 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, >>>>> goto out; >>>>> } >>>>> - WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count); >>>>> - ctx->capture_state = QUEUE_BUFS_MMAPED; >>>>> + if (reqbufs->memory == V4L2_MEMORY_MMAP) { >>>>> + 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; >>>>> + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); >>>>> + s5p_mfc_hw_call(dev->mfc_ops, >>>>> + release_codec_buffers, ctx); >>>>> + ret = -ENOMEM; >>>>> + goto out; >>>>> + } >>>>> + } >>>>> 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); >>>>> + if (reqbufs->memory == V4L2_MEMORY_MMAP) { >>>>> + 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; >>>>> @@ -576,15 +589,19 @@ static int vidioc_reqbufs(struct file *file, void *priv, >>>>> { >>>>> struct s5p_mfc_dev *dev = video_drvdata(file); >>>>> struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); >>>>> - >>>>> - if (reqbufs->memory != V4L2_MEMORY_MMAP) { >>>>> - mfc_debug(2, "Only V4L2_MEMORY_MMAP is supported\n"); >>>>> - return -EINVAL; >>>>> - } >>>>> + int ret; >>>>> if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_src, reqbufs->memory, >>>>> + reqbufs->type); >>>>> + if (ret) >>>>> + return ret; >>>>> return reqbufs_output(dev, ctx, reqbufs); >>>>> } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_dst, reqbufs->memory, >>>>> + reqbufs->type); >>>>> + if (ret) >>>>> + return ret; >>>>> return reqbufs_capture(dev, ctx, reqbufs); >>>>> } else { >>>>> mfc_err("Invalid type requested\n"); >>>>> @@ -600,16 +617,20 @@ static int vidioc_querybuf(struct file *file, void *priv, >>>>> int ret; >>>>> int i; >>>>> - if (buf->memory != V4L2_MEMORY_MMAP) { >>>>> - mfc_err("Only mmaped buffers can be used\n"); >>>>> - return -EINVAL; >>>>> - } >>>>> mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); >>>>> if (ctx->state == MFCINST_GOT_INST && >>>>> buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_src, buf->memory, >>>>> + buf->type); >>>>> + if (ret) >>>>> + return ret; >>>>> ret = vb2_querybuf(&ctx->vq_src, buf); >>>>> } else if (ctx->state == MFCINST_RUNNING && >>>>> buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_dst, buf->memory, >>>>> + buf->type); >>>>> + if (ret) >>>>> + return ret; >>>>> ret = vb2_querybuf(&ctx->vq_dst, buf); >>>>> for (i = 0; i < buf->length; i++) >>>>> buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; >>>>> @@ -940,10 +961,12 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, >>>>> else >>>>> alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; >>>>> alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; >>>>> + memset(ctx->dst_bufs, 0, sizeof(ctx->dst_bufs)); >>>>> } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && >>>>> ctx->state == MFCINST_INIT) { >>>>> psize[0] = ctx->dec_src_buf_size; >>>>> alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; >>>>> + memset(ctx->src_bufs, 0, sizeof(ctx->src_bufs)); >>>>> } else { >>>>> mfc_err("This video node is dedicated to decoding. Decoding not initialized\n"); >>>>> return -EINVAL; >>>>> @@ -959,30 +982,35 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) >>>>> unsigned int i; >>>>> if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { >>>>> + dma_addr_t luma, chroma; >>>>> + >>>>> if (ctx->capture_state == QUEUE_BUFS_MMAPED) >>>>> return 0; >>>>> - for (i = 0; i < ctx->dst_fmt->num_planes; i++) { >>>>> - if (IS_ERR_OR_NULL(ERR_PTR( >>>>> - vb2_dma_contig_plane_dma_addr(vb, i)))) { >>>>> - mfc_err("Plane mem not allocated\n"); >>>>> - return -EINVAL; >>>>> - } >>>>> - } >>>>> - if (vb2_plane_size(vb, 0) < ctx->luma_size || >>>>> - vb2_plane_size(vb, 1) < ctx->chroma_size) { >>>>> - mfc_err("Plane buffer (CAPTURE) is too small\n"); >>>>> + >>>>> + luma = vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> + chroma = vb2_dma_contig_plane_dma_addr(vb, 1); >>>>> + if (!luma || !chroma) { >>>>> + mfc_err("Plane mem not allocated\n"); >>>>> return -EINVAL; >>>>> } >>>>> + >>>>> i = vb->index; >>>>> + if ((ctx->dst_bufs[i].cookie.raw.luma && >>>>> + ctx->dst_bufs[i].cookie.raw.luma != luma) || >>>>> + (ctx->dst_bufs[i].cookie.raw.chroma && >>>>> + ctx->dst_bufs[i].cookie.raw.chroma != chroma)) { >>>>> + mfc_err("Changing CAPTURE buffer address during straming is not possible\n"); >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>>> ctx->dst_bufs[i].b = vbuf; >>>>> - ctx->dst_bufs[i].cookie.raw.luma = >>>>> - vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> - ctx->dst_bufs[i].cookie.raw.chroma = >>>>> - vb2_dma_contig_plane_dma_addr(vb, 1); >>>>> + ctx->dst_bufs[i].cookie.raw.luma = luma; >>>>> + ctx->dst_bufs[i].cookie.raw.chroma = chroma; >>>>> ctx->dst_bufs_cnt++; >>>>> } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> - if (IS_ERR_OR_NULL(ERR_PTR( >>>>> - vb2_dma_contig_plane_dma_addr(vb, 0)))) { >>>>> + dma_addr_t stream = vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> + >>>>> + if (!stream) { >>>>> mfc_err("Plane memory not allocated\n"); >>>>> return -EINVAL; >>>>> } >>>>> @@ -992,9 +1020,14 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) >>>>> } >>>>> i = vb->index; >>>>> + if (ctx->src_bufs[i].cookie.stream && >>>>> + ctx->src_bufs[i].cookie.stream != stream) { >>>>> + mfc_err("Changing OUTPUT buffer address during straming is not possible\n"); >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>>> ctx->src_bufs[i].b = vbuf; >>>>> - ctx->src_bufs[i].cookie.stream = >>>>> - vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> + ctx->src_bufs[i].cookie.stream = stream; >>>>> ctx->src_bufs_cnt++; >>>>> } else { >>>>> mfc_err("s5p_mfc_buf_init: unknown queue type\n"); >>>>> @@ -1071,6 +1104,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) >>>>> struct s5p_mfc_dev *dev = ctx->dev; >>>>> unsigned long flags; >>>>> struct s5p_mfc_buf *mfc_buf; >>>>> + int wait_flag = 0; >>>>> if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> mfc_buf = &ctx->src_bufs[vb->index]; >>>>> @@ -1088,12 +1122,25 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) >>>>> list_add_tail(&mfc_buf->list, &ctx->dst_queue); >>>>> ctx->dst_queue_cnt++; >>>>> spin_unlock_irqrestore(&dev->irqlock, flags); >>>>> + if ((vq->memory == V4L2_MEMORY_USERPTR || >>>>> + vq->memory == V4L2_MEMORY_DMABUF) && >>>>> + ctx->dst_queue_cnt == ctx->total_dpb_count) >>>>> + ctx->capture_state = QUEUE_BUFS_MMAPED; >>>>> } else { >>>>> mfc_err("Unsupported buffer type (%d)\n", vq->type); >>>>> } >>>>> - if (s5p_mfc_ctx_ready(ctx)) >>>>> + if (s5p_mfc_ctx_ready(ctx)) { >>>>> set_work_bit_irqsave(ctx); >>>>> + if ((vq->memory == V4L2_MEMORY_USERPTR || >>>>> + vq->memory == V4L2_MEMORY_DMABUF) && >>>>> + ctx->state == MFCINST_HEAD_PARSED && >>>>> + ctx->capture_state == QUEUE_BUFS_MMAPED) >>>>> + wait_flag = 1; >>>>> + } >>>>> s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); >>>>> + if (wait_flag) >>>>> + s5p_mfc_wait_for_done_ctx(ctx, >>>>> + S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); >>>>> } >>>>> static struct vb2_ops s5p_mfc_dec_qops = { >>>>> diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c >>>>> index 7b041e5ee4be..33fc3f3ef48a 100644 >>>>> --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c >>>>> +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c >>>>> @@ -1125,11 +1125,11 @@ static int vidioc_reqbufs(struct file *file, void *priv, >>>>> struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); >>>>> int ret = 0; >>>>> - /* if memory is not mmp or userptr return error */ >>>>> - if ((reqbufs->memory != V4L2_MEMORY_MMAP) && >>>>> - (reqbufs->memory != V4L2_MEMORY_USERPTR)) >>>>> - return -EINVAL; >>>>> if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_dst, reqbufs->memory, >>>>> + reqbufs->type); >>>>> + if (ret) >>>>> + return ret; >>>>> if (reqbufs->count == 0) { >>>>> mfc_debug(2, "Freeing buffers\n"); >>>>> ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); >>>>> @@ -1159,6 +1159,10 @@ static int vidioc_reqbufs(struct file *file, void *priv, >>>>> return -ENOMEM; >>>>> } >>>>> } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_src, reqbufs->memory, >>>>> + reqbufs->type); >>>>> + if (ret) >>>>> + return ret; >>>>> if (reqbufs->count == 0) { >>>>> mfc_debug(2, "Freeing buffers\n"); >>>>> ret = vb2_reqbufs(&ctx->vq_src, reqbufs); >>>>> @@ -1190,6 +1194,8 @@ static int vidioc_reqbufs(struct file *file, void *priv, >>>>> mfc_err("error in vb2_reqbufs() for E(S)\n"); >>>>> return ret; >>>>> } >>>>> + if (reqbufs->memory != V4L2_MEMORY_MMAP) >>>>> + ctx->src_bufs_cnt = reqbufs->count; >>>>> ctx->output_state = QUEUE_BUFS_REQUESTED; >>>>> } else { >>>>> mfc_err("invalid buf type\n"); >>>>> @@ -1204,11 +1210,11 @@ static int vidioc_querybuf(struct file *file, void *priv, >>>>> struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); >>>>> int ret = 0; >>>>> - /* if memory is not mmp or userptr return error */ >>>>> - if ((buf->memory != V4L2_MEMORY_MMAP) && >>>>> - (buf->memory != V4L2_MEMORY_USERPTR)) >>>>> - return -EINVAL; >>>>> if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_dst, buf->memory, >>>>> + buf->type); >>>>> + if (ret) >>>>> + return ret; >>>>> if (ctx->state != MFCINST_GOT_INST) { >>>>> mfc_err("invalid context state: %d\n", ctx->state); >>>>> return -EINVAL; >>>>> @@ -1220,6 +1226,10 @@ static int vidioc_querybuf(struct file *file, void *priv, >>>>> } >>>>> buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; >>>>> } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> + ret = vb2_verify_memory_type(&ctx->vq_src, buf->memory, >>>>> + buf->type); >>>>> + if (ret) >>>>> + return ret; >>>>> ret = vb2_querybuf(&ctx->vq_src, buf); >>>>> if (ret != 0) { >>>>> mfc_err("error in vb2_querybuf() for E(S)\n"); >>>>> @@ -1828,6 +1838,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, >>>>> *buf_count = MFC_MAX_BUFFERS; >>>>> psize[0] = ctx->enc_dst_buf_size; >>>>> alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; >>>>> + memset(ctx->dst_bufs, 0, sizeof(ctx->dst_bufs)); >>>>> } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> if (ctx->src_fmt) >>>>> *plane_count = ctx->src_fmt->num_planes; >>>>> @@ -1849,6 +1860,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, >>>>> alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; >>>>> alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX]; >>>>> } >>>>> + memset(ctx->src_bufs, 0, sizeof(ctx->src_bufs)); >>>>> } else { >>>>> mfc_err("invalid queue type: %d\n", vq->type); >>>>> return -EINVAL; >>>>> @@ -1865,25 +1877,47 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) >>>>> int ret; >>>>> if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { >>>>> + dma_addr_t stream; >>>>> + >>>>> ret = check_vb_with_fmt(ctx->dst_fmt, vb); >>>>> if (ret < 0) >>>>> return ret; >>>>> + >>>>> + stream = vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> i = vb->index; >>>>> + if (ctx->dst_bufs[i].cookie.stream && >>>>> + ctx->src_bufs[i].cookie.stream != stream) { >>>>> + mfc_err("Changing CAPTURE buffer address during straming is not possible\n"); >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>>> ctx->dst_bufs[i].b = vbuf; >>>>> - ctx->dst_bufs[i].cookie.stream = >>>>> - vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> + ctx->dst_bufs[i].cookie.stream = stream; >>>>> ctx->dst_bufs_cnt++; >>>>> } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { >>>>> + dma_addr_t luma, chroma; >>>>> + >>>>> ret = check_vb_with_fmt(ctx->src_fmt, vb); >>>>> if (ret < 0) >>>>> return ret; >>>>> + >>>>> + luma = vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> + chroma = vb2_dma_contig_plane_dma_addr(vb, 1); >>>>> + >>>>> i = vb->index; >>>>> + if ((ctx->src_bufs[i].cookie.raw.luma && >>>>> + ctx->src_bufs[i].cookie.raw.luma != luma) || >>>>> + (ctx->src_bufs[i].cookie.raw.chroma && >>>>> + ctx->src_bufs[i].cookie.raw.chroma != chroma)) { >>>>> + mfc_err("Changing OUTPUT buffer address during straming is not possible\n"); >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>>> ctx->src_bufs[i].b = vbuf; >>>>> - ctx->src_bufs[i].cookie.raw.luma = >>>>> - vb2_dma_contig_plane_dma_addr(vb, 0); >>>>> - ctx->src_bufs[i].cookie.raw.chroma = >>>>> - vb2_dma_contig_plane_dma_addr(vb, 1); >>>>> - ctx->src_bufs_cnt++; >>>>> + ctx->src_bufs[i].cookie.raw.luma = luma; >>>>> + ctx->src_bufs[i].cookie.raw.chroma = chroma; >>>>> + if (vb->memory == V4L2_MEMORY_MMAP) >>>>> + ctx->src_bufs_cnt++; >>>>> } else { >>>>> mfc_err("invalid queue type: %d\n", vq->type); >>>>> return -EINVAL; > -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html