Re: [PATCHv2 04/12] media: s5p_mfc_dec: set flags for OUTPUT coded formats
gt; @@ -111,6 +123,7 @@ static struct s5p_mfc_fmt formats[] = { >> .type = MFC_FMT_DEC, >> .num_planes = 1, >> .versions = MFC_V5PLUS_BITS, >> + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, >> }, >> { >> .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, >> @@ -118,6 +131,7 @@ static struct s5p_mfc_fmt formats[] = { >> .type = MFC_FMT_DEC, >> .num_planes = 1, >> .versions = MFC_V5PLUS_BITS, >> + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, >> }, >> { >> .fourcc = V4L2_PIX_FMT_VP8, >> @@ -125,6 +139,7 @@ static struct s5p_mfc_fmt formats[] = { >> .type = MFC_FMT_DEC, >> .num_planes = 1, >> .versions = MFC_V6PLUS_BITS, >> + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, >> }, >> { >> .fourcc = V4L2_PIX_FMT_HEVC, >> @@ -132,6 +147,8 @@ static struct s5p_mfc_fmt formats[] = { >> .type = MFC_FMT_DEC, >> .num_planes = 1, >> .versions = MFC_V10_BIT, >> + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | >> + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, >> }, >> { >> .fourcc = V4L2_PIX_FMT_VP9, >> @@ -139,6 +156,7 @@ static struct s5p_mfc_fmt formats[] = { >> .type = MFC_FMT_DEC, >> .num_planes = 1, >> .versions = MFC_V10_BIT, >> + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, >> }, >> }; >> >> -- >> 2.20.1 >> > Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v2] media: vb2-dc: skip CPU sync in map/unmap dma_buf
Hi Lucas, On 2019-07-08 15:07, Lucas Stach wrote: > This is rougly equivalent to ca0e68e21aae (drm/prime: skip CPU sync > in map/unmap dma_buf). The contig memory allocated is already device > coherent memory, so there is no point in doing a CPU sync when > mapping it to another deevice. Also most importers currently cache > the mapping so the CPU sync would only happen on the first import, > so we are better off with not pretending to do a cache synchronization > at all. > > This gets rid of a lot of CPU overhead in uses where those dma-bufs > are regularily imported and detached again, like Weston is currently > doing in the DRM compositor. > > Signed-off-by: Lucas Stach Acked-by: Marek Szyprowski > --- > v2: Add comments why it is safe to skip the CPU sync. > --- > .../common/videobuf2/videobuf2-dma-contig.c | 23 +-- > 1 file changed, 16 insertions(+), 7 deletions(-) > > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c > b/drivers/media/common/videobuf2/videobuf2-dma-contig.c > index ecbef266130b..1b8f86366290 100644 > --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c > +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c > @@ -267,8 +267,14 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf > *dbuf, > > /* release the scatterlist cache */ > if (attach->dma_dir != DMA_NONE) > - dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, > - attach->dma_dir); > + /* > + * Cache sync can be skipped here, as the vb2_dc memory is > + * allocated from device coherent memory, which means the > + * memory locations do not require any explicit cache > + * maintenance prior or after being used by the device. > + */ > + dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, > + attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); > sg_free_table(sgt); > kfree(attach); > db_attach->priv = NULL; > @@ -293,14 +299,17 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( > > /* release any previous cache */ > if (attach->dma_dir != DMA_NONE) { > - dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, > - attach->dma_dir); > + dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, > + attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); > attach->dma_dir = DMA_NONE; > } > > - /* mapping to the client with new direction */ > - sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, > - dma_dir); > + /* > + * mapping to the client with new direction, no cache sync > + * required see comment in vb2_dc_dmabuf_ops_detach() > + */ > + sgt->nents = dma_map_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, > + dma_dir, DMA_ATTR_SKIP_CPU_SYNC); > if (!sgt->nents) { > pr_err("failed to map scatterlist\n"); > mutex_unlock(lock); Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH 4/6] s5p-cec: use cec_notifier_cec_adap_(un)register
Hi Hans, On 2019-07-15 12:30, Hans Verkuil wrote: > Use cec_notifier_cec_adap_(un)register instead of > cec_notifier_get, cec_notifier_put and cec_register_cec_notifier. > > Also enable the CEC_CAP_CONNECTOR_INFO capability. > > Signed-off-by: Hans Verkuil > Cc: Marek Szyprowski > Cc: Sylwester Nawrocki Acked-by: Marek Szyprowski > --- > drivers/media/platform/s5p-cec/s5p_cec.c | 23 ++- > 1 file changed, 14 insertions(+), 9 deletions(-) > > diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c > b/drivers/media/platform/s5p-cec/s5p_cec.c > index ea6231b387ed..6ddcc35b0bbd 100644 > --- a/drivers/media/platform/s5p-cec/s5p_cec.c > +++ b/drivers/media/platform/s5p-cec/s5p_cec.c > @@ -214,21 +214,23 @@ static int s5p_cec_probe(struct platform_device *pdev) > if (IS_ERR(cec->reg)) > return PTR_ERR(cec->reg); > > - cec->notifier = cec_notifier_get(hdmi_dev); > - if (cec->notifier == NULL) > - return -ENOMEM; > - > cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME, > - CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0), 1); > + CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0) | > + CEC_CAP_CONNECTOR_INFO, 1); > ret = PTR_ERR_OR_ZERO(cec->adap); > if (ret) > return ret; > > - ret = cec_register_adapter(cec->adap, &pdev->dev); > - if (ret) > + cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, > +cec->adap); > + if (!cec->notifier) { > + ret = -ENOMEM; > goto err_delete_adapter; > + } > > - cec_register_cec_notifier(cec->adap, cec->notifier); > + ret = cec_register_adapter(cec->adap, &pdev->dev); > + if (ret) > + goto err_notifier; > > platform_set_drvdata(pdev, cec); > pm_runtime_enable(dev); > @@ -236,6 +238,9 @@ static int s5p_cec_probe(struct platform_device *pdev) > dev_dbg(dev, "successfully probed\n"); > return 0; > > +err_notifier: > + cec_notifier_cec_adap_unregister(cec->notifier); > + > err_delete_adapter: > cec_delete_adapter(cec->adap); > return ret; > @@ -245,8 +250,8 @@ static int s5p_cec_remove(struct platform_device *pdev) > { > struct s5p_cec_dev *cec = platform_get_drvdata(pdev); > > + cec_notifier_cec_adap_unregister(cec->notifier); > cec_unregister_adapter(cec->adap); > - cec_notifier_put(cec->notifier); > pm_runtime_disable(&pdev->dev); > return 0; > } Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] media: s5p-mfc: Make additional clocks optional
Since the beginning the second clock ('special', 'sclk') was optional and it is not available on some variants of Exynos SoCs (i.e. Exynos5420 with v7 of MFC hardware). However commit 1bce6fb3edf1 made handling of all specified clocks mandatory. This patch restores original behavior of the driver and fixes its operation on Exynos5420 SoCs. Fixes: 1bce6fb3edf1 ("[media] s5p-mfc: Rework clock handling") Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 2e62f8721fa5..d2872e19dd9d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -34,6 +34,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) for (i = 0; i < pm->num_clocks; i++) { pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); if (IS_ERR(pm->clocks[i])) { + /* additional clocks are optional */ + if (i && PTR_ERR(pm->clocks[i] == -ENOENT)) { + pm->clocks[i] = NULL; + continue; + } mfc_err("Failed to get clock: %s\n", pm->clk_names[i]); return PTR_ERR(pm->clocks[i]); -- 2.17.1
[PATCH v2] media: s5p-mfc: Make additional clocks optional
Since the beginning the second clock ('special', 'sclk') was optional and it is not available on some variants of Exynos SoCs (i.e. Exynos5420 with v7 of MFC hardware). However commit 1bce6fb3edf1 made handling of all specified clocks mandatory. This patch restores original behavior of the driver and fixes its operation on Exynos5420 SoCs. Fixes: 1bce6fb3edf1 ("[media] s5p-mfc: Rework clock handling") Signed-off-by: Marek Szyprowski --- v2: this is the correct version, v1 had parenthesis in wrong place --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 2e62f8721fa5..7d52431c2c83 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -34,6 +34,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) for (i = 0; i < pm->num_clocks; i++) { pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); if (IS_ERR(pm->clocks[i])) { + /* additional clocks are optional */ + if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) { + pm->clocks[i] = NULL; + continue; + } mfc_err("Failed to get clock: %s\n", pm->clk_names[i]); return PTR_ERR(pm->clocks[i]); -- 2.17.1
[PATCH] media: s5p-mfc: fix reading min scratch buffer size on MFC v6/v7
MFC v6 and v7 has no register to read min scratch buffer size, so it has to be read conditionally only if hardware supports it. This fixes following NULL pointer exception on SoCs with MFC v6/v7: 8<--- cut here --- Unable to handle kernel NULL pointer dereference at virtual address pgd = f25837f9 [] *pgd=bd93d835 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: btmrvl_sdio btmrvl bluetooth mwifiex_sdio mwifiex ecdh_generic ecc CPU: 0 PID: 1430 Comm: v4l2_decode Not tainted 5.2.0-rc4-next-20190612-6-gf077fba72e95-dirty #6167 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) PC is at s5p_mfc_get_min_scratch_buf_size+0x30/0x3c LR is at s5p_mfc_get_min_scratch_buf_size+0x28/0x3c ... [] (s5p_mfc_get_min_scratch_buf_size) from [] (s5p_mfc_irq+0x814/0xa5c) [] (s5p_mfc_irq) from [] (__handle_irq_event_percpu+0x64/0x3f8) [] (__handle_irq_event_percpu) from [] (handle_irq_event_percpu+0x2c/0x7c) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [] (handle_irq_event) from [] (handle_fasteoi_irq+0xc4/0x180) [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x7c/0xec) [] (__handle_domain_irq) from [] (gic_handle_irq+0x58/0x9c) [] (gic_handle_irq) from [] (__irq_svc+0x70/0xb0) Exception stack(0xe73ddc60 to 0xe73ddca8) ... [] (__irq_svc) from [] (console_unlock+0x5a8/0x6a8) [] (console_unlock) from [] (vprintk_emit+0x118/0x2d8) [] (vprintk_emit) from [] (vprintk_default+0x20/0x28) [] (vprintk_default) from [] (printk+0x30/0x54) [] (printk) from [] (s5p_mfc_init_decode_v6+0x1d4/0x284) [] (s5p_mfc_init_decode_v6) from [] (vb2_start_streaming+0x24/0x150) [] (vb2_start_streaming) from [] (vb2_core_streamon+0x11c/0x15c) [] (vb2_core_streamon) from [] (vidioc_streamon+0x64/0xa0) [] (vidioc_streamon) from [] (__video_do_ioctl+0x28c/0x45c) [] (__video_do_ioctl) from [] (video_usercopy+0x260/0x8a4) [] (video_usercopy) from [] (do_vfs_ioctl+0xb0/0x9fc) [] (do_vfs_ioctl) from [] (ksys_ioctl+0x34/0x58) [] (ksys_ioctl) from [] (ret_fast_syscall+0x0/0x28) Exception stack(0xe73ddfa8 to 0xe73ddff0) ... ---[ end trace 376cf5ba6e0bee93 ]--- Fixes: c8ffbd433a77 ("media: s5p-mfc: Use min scratch buffer size as provided by F/W") Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index c5dc1880a4c6..b776f83e395e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -523,7 +523,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); - ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, get_min_scratch_buf_size, dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; -- 2.17.1
Re: [PATCH v2 1/5] media: vb2: Introduce a vb2_get_buffer accessor
On 2019-06-10 22:55, Ezequiel Garcia wrote: > Some drivers need to access a vb2 buffer from its > queue index. Introduce an accessor to abstract this, > and avoid drivers from accessing private members. > > Reviewed-by: Boris Brezillon > Signed-off-by: Ezequiel Garcia Acked-by: Marek Szyprowski > --- > Changes from v1: > * Drop redundant num_buffers > 0 check. > --- > include/media/videobuf2-core.h | 18 ++ > 1 file changed, 18 insertions(+) > > diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h > index c03ef7cc5071..640aabe69450 100644 > --- a/include/media/videobuf2-core.h > +++ b/include/media/videobuf2-core.h > @@ -1163,6 +1163,24 @@ static inline void > vb2_clear_last_buffer_dequeued(struct vb2_queue *q) > q->last_buffer_dequeued = false; > } > > +/** > + * vb2_get_buffer() - get a buffer from a queue > + * @q: pointer to &struct vb2_queue with videobuf2 queue. > + * @index: buffer index > + * > + * This function obtains a buffer from a queue, by its index. > + * Keep in mind that there is no refcounting involved in this > + * operation, so the buffer lifetime should be taken into > + * consideration. > + */ > +static inline struct vb2_buffer *vb2_get_buffer(struct vb2_queue *q, > + unsigned int index) > +{ > + if (index < q->num_buffers) > + return q->bufs[index]; > + return NULL; > +} > + > /* > * The following functions are not part of the vb2 core API, but are useful >* functions for videobuf2-*. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH for v5.2] videobuf2-core.c: always reacquire USERPTR memory
Hi Hans, On 2019-06-11 09:52, Hans Verkuil wrote: > On 6/7/19 9:43 PM, Nicolas Dufresne wrote: >> Le vendredi 07 juin 2019 à 16:39 +0200, Marek Szyprowski a écrit : >>> Hi Hans, >>> >>> On 2019-06-07 16:11, Hans Verkuil wrote: >>>> On 6/7/19 3:55 PM, Marek Szyprowski wrote: >>>>> On 2019-06-07 15:40, Hans Verkuil wrote: >>>>>> On 6/7/19 2:47 PM, Hans Verkuil wrote: >>>>>>> On 6/7/19 2:23 PM, Hans Verkuil wrote: >>>>>>>> On 6/7/19 2:14 PM, Marek Szyprowski wrote: >>>>>>>>> On 2019-06-07 14:01, Hans Verkuil wrote: >>>>>>>>>> On 6/7/19 1:16 PM, Laurent Pinchart wrote: >>>>>>>>>>> Thank you for the patch. >>>>>>>>>>> >>>>>>>>>>> On Fri, Jun 07, 2019 at 10:45:31AM +0200, Hans Verkuil wrote: >>>>>>>>>>>> The __prepare_userptr() function made the incorrect assumption >>>>>>>>>>>> that if the >>>>>>>>>>>> same user pointer was used as the last one for which memory was >>>>>>>>>>>> acquired, then >>>>>>>>>>>> there was no need to re-acquire the memory. This assumption was >>>>>>>>>>>> never properly >>>>>>>>>>>> tested, and after doing that it became clear that this was in fact >>>>>>>>>>>> wrong. >>>>>>>>>>> Could you explain in the commit message why the assumption is not >>>>>>>>>>> correct ? >>>>>>>>>> You can free the memory, then allocate it again and you can get the >>>>>>>>>> same pointer, >>>>>>>>>> even though it is not necessarily using the same physical pages for >>>>>>>>>> the memory >>>>>>>>>> that the kernel is still using for it. >>>>>>>>>> >>>>>>>>>> Worse, you can free the memory, then allocate only half the memory >>>>>>>>>> you need and >>>>>>>>>> get back the same pointer. vb2 wouldn't notice this. And it seems to >>>>>>>>>> work (since >>>>>>>>>> the original mapping still remains), but this can corrupt userspace >>>>>>>>>> memory >>>>>>>>>> causing the application to crash. It's not quite clear to me how the >>>>>>>>>> memory can >>>>>>>>>> get corrupted. I don't know enough of those low-level mm internals >>>>>>>>>> to understand >>>>>>>>>> the sequence of events. >>>>>>>>>> >>>>>>>>>> I have test code for v4l2-compliance available if someone wants to >>>>>>>>>> test this. >>>>>>>>> I'm interested, I would really like to know what happens in the mm >>>>>>>>> subsystem in such case. >>>>>>>> Here it is: >>>>>>>> >>>>>>>> diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>>>>> b/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>>>>> index be606e48..9abf41da 100644 >>>>>>>> --- a/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>>>>> +++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>>>>> @@ -797,7 +797,7 @@ int testReadWrite(struct node *node) >>>>>>>>return 0; >>>>>>>> } >>>>>>>> >>>>>>>> -static int captureBufs(struct node *node, const cv4l_queue &q, >>>>>>>> +static int captureBufs(struct node *node, cv4l_queue &q, >>>>>>>>const cv4l_queue &m2m_q, unsigned frame_count, int >>>>>>>> pollmode, >>>>>>>>unsigned &capture_count) >>>>>>>> { >>>>>>>> @@ -962,6 +962,21 @@ static int captureBufs(struct node *node, const >>>>>>>> cv4l_queue &q, >>>>>>>>buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD); >>>>
Re: [PATCH for v5.2] videobuf2-core.c: always reacquire USERPTR memory
Hi Hans, On 2019-06-07 16:11, Hans Verkuil wrote: > On 6/7/19 3:55 PM, Marek Szyprowski wrote: >> On 2019-06-07 15:40, Hans Verkuil wrote: >>> On 6/7/19 2:47 PM, Hans Verkuil wrote: >>>> On 6/7/19 2:23 PM, Hans Verkuil wrote: >>>>> On 6/7/19 2:14 PM, Marek Szyprowski wrote: >>>>>> On 2019-06-07 14:01, Hans Verkuil wrote: >>>>>>> On 6/7/19 1:16 PM, Laurent Pinchart wrote: >>>>>>>> Thank you for the patch. >>>>>>>> >>>>>>>> On Fri, Jun 07, 2019 at 10:45:31AM +0200, Hans Verkuil wrote: >>>>>>>>> The __prepare_userptr() function made the incorrect assumption that >>>>>>>>> if the >>>>>>>>> same user pointer was used as the last one for which memory was >>>>>>>>> acquired, then >>>>>>>>> there was no need to re-acquire the memory. This assumption was never >>>>>>>>> properly >>>>>>>>> tested, and after doing that it became clear that this was in fact >>>>>>>>> wrong. >>>>>>>> Could you explain in the commit message why the assumption is not >>>>>>>> correct ? >>>>>>> You can free the memory, then allocate it again and you can get the >>>>>>> same pointer, >>>>>>> even though it is not necessarily using the same physical pages for the >>>>>>> memory >>>>>>> that the kernel is still using for it. >>>>>>> >>>>>>> Worse, you can free the memory, then allocate only half the memory you >>>>>>> need and >>>>>>> get back the same pointer. vb2 wouldn't notice this. And it seems to >>>>>>> work (since >>>>>>> the original mapping still remains), but this can corrupt userspace >>>>>>> memory >>>>>>> causing the application to crash. It's not quite clear to me how the >>>>>>> memory can >>>>>>> get corrupted. I don't know enough of those low-level mm internals to >>>>>>> understand >>>>>>> the sequence of events. >>>>>>> >>>>>>> I have test code for v4l2-compliance available if someone wants to test >>>>>>> this. >>>>>> I'm interested, I would really like to know what happens in the mm >>>>>> subsystem in such case. >>>>> Here it is: >>>>> >>>>> diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>> b/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>> index be606e48..9abf41da 100644 >>>>> --- a/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>> +++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp >>>>> @@ -797,7 +797,7 @@ int testReadWrite(struct node *node) >>>>> return 0; >>>>>} >>>>> >>>>> -static int captureBufs(struct node *node, const cv4l_queue &q, >>>>> +static int captureBufs(struct node *node, cv4l_queue &q, >>>>> const cv4l_queue &m2m_q, unsigned frame_count, int >>>>> pollmode, >>>>> unsigned &capture_count) >>>>>{ >>>>> @@ -962,6 +962,21 @@ static int captureBufs(struct node *node, const >>>>> cv4l_queue &q, >>>>> buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD); >>>>> buf.s_request_fd(buf_req_fds[req_idx]); >>>>> } >>>>> + if (v4l_type_is_capture(buf.g_type()) && q.g_memory() >>>>> == V4L2_MEMORY_USERPTR) { >>>>> + printf("\nidx: %d", buf.g_index()); >>>>> + for (unsigned p = 0; p < q.g_num_planes(); p++) >>>>> { >>>>> + printf(" old buf[%d]: %p ", p, >>>>> buf.g_userptr(p)); >>>>> + fflush(stdout); >>>>> + free(buf.g_userptr(p)); >>>>> + void *m = calloc(1, q.g_length(p)/2); >>>>> + >>>>> + fail_on_tes
Re: [PATCH for v5.2] videobuf2-core.c: always reacquire USERPTR memory
Hi Hans, On 2019-06-07 15:40, Hans Verkuil wrote: > On 6/7/19 2:47 PM, Hans Verkuil wrote: >> On 6/7/19 2:23 PM, Hans Verkuil wrote: >>> On 6/7/19 2:14 PM, Marek Szyprowski wrote: >>>> On 2019-06-07 14:01, Hans Verkuil wrote: >>>>> On 6/7/19 1:16 PM, Laurent Pinchart wrote: >>>>>> Thank you for the patch. >>>>>> >>>>>> On Fri, Jun 07, 2019 at 10:45:31AM +0200, Hans Verkuil wrote: >>>>>>> The __prepare_userptr() function made the incorrect assumption that if >>>>>>> the >>>>>>> same user pointer was used as the last one for which memory was >>>>>>> acquired, then >>>>>>> there was no need to re-acquire the memory. This assumption was never >>>>>>> properly >>>>>>> tested, and after doing that it became clear that this was in fact >>>>>>> wrong. >>>>>> Could you explain in the commit message why the assumption is not >>>>>> correct ? >>>>> You can free the memory, then allocate it again and you can get the same >>>>> pointer, >>>>> even though it is not necessarily using the same physical pages for the >>>>> memory >>>>> that the kernel is still using for it. >>>>> >>>>> Worse, you can free the memory, then allocate only half the memory you >>>>> need and >>>>> get back the same pointer. vb2 wouldn't notice this. And it seems to work >>>>> (since >>>>> the original mapping still remains), but this can corrupt userspace memory >>>>> causing the application to crash. It's not quite clear to me how the >>>>> memory can >>>>> get corrupted. I don't know enough of those low-level mm internals to >>>>> understand >>>>> the sequence of events. >>>>> >>>>> I have test code for v4l2-compliance available if someone wants to test >>>>> this. >>>> I'm interested, I would really like to know what happens in the mm >>>> subsystem in such case. >>> Here it is: >>> >>> diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp >>> b/utils/v4l2-compliance/v4l2-test-buffers.cpp >>> index be606e48..9abf41da 100644 >>> --- a/utils/v4l2-compliance/v4l2-test-buffers.cpp >>> +++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp >>> @@ -797,7 +797,7 @@ int testReadWrite(struct node *node) >>> return 0; >>> } >>> >>> -static int captureBufs(struct node *node, const cv4l_queue &q, >>> +static int captureBufs(struct node *node, cv4l_queue &q, >>> const cv4l_queue &m2m_q, unsigned frame_count, int pollmode, >>> unsigned &capture_count) >>> { >>> @@ -962,6 +962,21 @@ static int captureBufs(struct node *node, const >>> cv4l_queue &q, >>> buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD); >>> buf.s_request_fd(buf_req_fds[req_idx]); >>> } >>> + if (v4l_type_is_capture(buf.g_type()) && q.g_memory() >>> == V4L2_MEMORY_USERPTR) { >>> + printf("\nidx: %d", buf.g_index()); >>> + for (unsigned p = 0; p < q.g_num_planes(); p++) >>> { >>> + printf(" old buf[%d]: %p ", p, >>> buf.g_userptr(p)); >>> + fflush(stdout); >>> + free(buf.g_userptr(p)); >>> + void *m = calloc(1, q.g_length(p)/2); >>> + >>> + fail_on_test(m == NULL); >>> + q.s_userptr(buf.g_index(), p, m); >>> + printf("new buf[%d]: %p", p, m); >>> + buf.s_userptr(m, p); >>> + } >>> + printf("\n"); >>> + } >>> fail_on_test(buf.qbuf(node, q)); >>> fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE); >>> if (buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD) { >>> >>> >>> >>> Load the vivid driver and just run 'v4l2
Re: [PATCH for v5.2] videobuf2-core.c: always reacquire USERPTR memory
Hi Hans, On 2019-06-07 14:01, Hans Verkuil wrote: > On 6/7/19 1:16 PM, Laurent Pinchart wrote: >> Hi Hans, >> >> Thank you for the patch. >> >> On Fri, Jun 07, 2019 at 10:45:31AM +0200, Hans Verkuil wrote: >>> The __prepare_userptr() function made the incorrect assumption that if the >>> same user pointer was used as the last one for which memory was acquired, >>> then >>> there was no need to re-acquire the memory. This assumption was never >>> properly >>> tested, and after doing that it became clear that this was in fact wrong. >> Could you explain in the commit message why the assumption is not >> correct ? > You can free the memory, then allocate it again and you can get the same > pointer, > even though it is not necessarily using the same physical pages for the memory > that the kernel is still using for it. > > Worse, you can free the memory, then allocate only half the memory you need > and > get back the same pointer. vb2 wouldn't notice this. And it seems to work > (since > the original mapping still remains), but this can corrupt userspace memory > causing the application to crash. It's not quite clear to me how the memory > can > get corrupted. I don't know enough of those low-level mm internals to > understand > the sequence of events. > > I have test code for v4l2-compliance available if someone wants to test this. I'm interested, I would really like to know what happens in the mm subsystem in such case. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: fix a layering violation in videobuf2 and improve dma_map_resource v2
Hi All, On 2019-01-18 12:37, Christoph Hellwig wrote: > Hi all, > > this series fixes a rather gross layering violation in videobuf2, which > pokes into arm DMA mapping internals to get a DMA address for memory that > does not have a page structure, and to do so fixes up the dma_map_resource > implementation to not provide a somewhat dangerous default and improve > the error handling. > > Changes since v1: > - don't apply bus offsets in dma_direct_map_resource Works fine on older Exynos based boards with IOMMU and CMA disabled. Tested-by: Marek Szyprowski Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCHv2 7/9] videobuf2/videobuf2-dma-sg.c: Convert to use vm_insert_range
Hi Souptick, On 2019-01-31 04:13, Souptick Joarder wrote: > Convert to use vm_insert_range to map range of kernel memory > to user vma. > > vm_pgoff is treated in V4L2 API as a 'cookie' to select a buffer, > not as a in-buffer offset by design and it always want to mmap a > whole buffer from its beginning. > > Signed-off-by: Souptick Joarder Suggested-by: Marek Szyprowski Reviewed-by: Marek Szyprowski > --- > drivers/media/common/videobuf2/videobuf2-core.c| 7 +++ > .../media/common/videobuf2/videobuf2-dma-contig.c | 6 -- > drivers/media/common/videobuf2/videobuf2-dma-sg.c | 22 > ++ > 3 files changed, 13 insertions(+), 22 deletions(-) > > diff --git a/drivers/media/common/videobuf2/videobuf2-core.c > b/drivers/media/common/videobuf2/videobuf2-core.c > index 70e8c33..ca4577a 100644 > --- a/drivers/media/common/videobuf2/videobuf2-core.c > +++ b/drivers/media/common/videobuf2/videobuf2-core.c > @@ -2175,6 +2175,13 @@ int vb2_mmap(struct vb2_queue *q, struct > vm_area_struct *vma) > goto unlock; > } > > + /* > + * vm_pgoff is treated in V4L2 API as a 'cookie' to select a buffer, > + * not as a in-buffer offset. We always want to mmap a whole buffer > + * from its beginning. > + */ > + vma->vm_pgoff = 0; > + > ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); > > unlock: > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c > b/drivers/media/common/videobuf2/videobuf2-dma-contig.c > index aff0ab7..46245c5 100644 > --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c > +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c > @@ -186,12 +186,6 @@ static int vb2_dc_mmap(void *buf_priv, struct > vm_area_struct *vma) > return -EINVAL; > } > > - /* > - * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to > - * map whole buffer > - */ > - vma->vm_pgoff = 0; > - > ret = dma_mmap_attrs(buf->dev, vma, buf->cookie, > buf->dma_addr, buf->size, buf->attrs); > > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c > b/drivers/media/common/videobuf2/videobuf2-dma-sg.c > index 015e737..a800200 100644 > --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c > +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c > @@ -328,28 +328,18 @@ static unsigned int vb2_dma_sg_num_users(void *buf_priv) > static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) > { > struct vb2_dma_sg_buf *buf = buf_priv; > - unsigned long uaddr = vma->vm_start; > - unsigned long usize = vma->vm_end - vma->vm_start; > - int i = 0; > + int err; > > if (!buf) { > printk(KERN_ERR "No memory to map\n"); > return -EINVAL; > } > > - do { > - int ret; > - > - ret = vm_insert_page(vma, uaddr, buf->pages[i++]); > - if (ret) { > - printk(KERN_ERR "Remapping memory, error: %d\n", ret); > - return ret; > - } > - > - uaddr += PAGE_SIZE; > - usize -= PAGE_SIZE; > - } while (usize > 0); > - > + err = vm_insert_range(vma, buf->pages, buf->num_pages); > + if (err) { > + printk(KERN_ERR "Remapping memory, error: %d\n", err); > + return err; > + } > > /* >* Use common vm_area operations to track buffer refcount. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH 7/9] videobuf2/videobuf2-dma-sg.c: Convert to use vm_insert_range_buggy
Hi Souptick, On 2019-01-25 05:55, Souptick Joarder wrote: > On Tue, Jan 22, 2019 at 8:37 PM Marek Szyprowski > wrote: >> On 2019-01-11 16:11, Souptick Joarder wrote: >>> Convert to use vm_insert_range_buggy to map range of kernel memory >>> to user vma. >>> >>> This driver has ignored vm_pgoff. We could later "fix" these drivers >>> to behave according to the normal vm_pgoff offsetting simply by >>> removing the _buggy suffix on the function name and if that causes >>> regressions, it gives us an easy way to revert. >> Just a generic note about videobuf2: videobuf2-dma-sg is ignoring vm_pgoff >> by design. vm_pgoff is used as a 'cookie' to select a buffer to mmap and >> videobuf2-core already checks that. If userspace provides an offset, which >> doesn't match any of the registered 'cookies' (reported to userspace via >> separate v4l2 ioctl), an error is returned. > Ok, it means once the buf is selected, videobuf2-dma-sg should always > mapped buf->pages[i] > from index 0 ( irrespective of vm_pgoff value). So although we are > replacing the code with > vm_insert_range_buggy(), *_buggy* suffix will mislead others and > should not be used. > And if we replace this code with vm_insert_range(), this will > introduce bug for *non zero* > value of vm_pgoff. > > Please correct me if my understanding is wrong. You are correct. IMHO the best solution in this case would be to add following fix: diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 70e8c3366f9c..ca4577a7d28a 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2175,6 +2175,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) goto unlock; } + /* + * vm_pgoff is treated in V4L2 API as a 'cookie' to select a buffer, + * not as a in-buffer offset. We always want to mmap a whole buffer + * from its beginning. + */ + vma->vm_pgoff = 0; + ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); unlock: diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index aff0ab7bf83d..46245c598a18 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -186,12 +186,6 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) return -EINVAL; } - /* - * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to - * map whole buffer - */ - vma->vm_pgoff = 0; - ret = dma_mmap_attrs(buf->dev, vma, buf->cookie, buf->dma_addr, buf->size, buf->attrs); -- Then you can simply use non-buggy version of your function in drivers/media/common/videobuf2/videobuf2-dma-sg.c. I can send above as a formal patch if you want. > So what your opinion about this patch ? Shall I drop this patch from > current series ? > or, > There is any better way to handle this scenario ? > > >>> There is an existing bug inside gem_mmap_obj(), where user passed >>> length is not checked against buf->num_pages. For any value of >>> length > buf->num_pages it will end up overrun buf->pages[i], >>> which could lead to a potential bug. > It is not gem_mmap_obj(), it should be vb2_dma_sg_mmap(). > Sorry about it. > > What about this issue ? Does it looks like a valid issue ? It is already handled in vb2_mmap(). Such call will be rejected. > ... Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH 7/9] videobuf2/videobuf2-dma-sg.c: Convert to use vm_insert_range_buggy
Hi Souptick, On 2019-01-11 16:11, Souptick Joarder wrote: > Convert to use vm_insert_range_buggy to map range of kernel memory > to user vma. > > This driver has ignored vm_pgoff. We could later "fix" these drivers > to behave according to the normal vm_pgoff offsetting simply by > removing the _buggy suffix on the function name and if that causes > regressions, it gives us an easy way to revert. Just a generic note about videobuf2: videobuf2-dma-sg is ignoring vm_pgoff by design. vm_pgoff is used as a 'cookie' to select a buffer to mmap and videobuf2-core already checks that. If userspace provides an offset, which doesn't match any of the registered 'cookies' (reported to userspace via separate v4l2 ioctl), an error is returned. I'm sorry for the late reply. > There is an existing bug inside gem_mmap_obj(), where user passed > length is not checked against buf->num_pages. For any value of > length > buf->num_pages it will end up overrun buf->pages[i], > which could lead to a potential bug. > > This has been addressed by passing buf->num_pages as input to > vm_insert_range_buggy() and inside this API error condition is > checked which will avoid overrun the page boundary. > > Signed-off-by: Souptick Joarder > --- > drivers/media/common/videobuf2/videobuf2-dma-sg.c | 22 ++ > 1 file changed, 6 insertions(+), 16 deletions(-) > > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c > b/drivers/media/common/videobuf2/videobuf2-dma-sg.c > index 015e737..ef046b4 100644 > --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c > +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c > @@ -328,28 +328,18 @@ static unsigned int vb2_dma_sg_num_users(void *buf_priv) > static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) > { > struct vb2_dma_sg_buf *buf = buf_priv; > - unsigned long uaddr = vma->vm_start; > - unsigned long usize = vma->vm_end - vma->vm_start; > - int i = 0; > + int err; > > if (!buf) { > printk(KERN_ERR "No memory to map\n"); > return -EINVAL; > } > > - do { > - int ret; > - > - ret = vm_insert_page(vma, uaddr, buf->pages[i++]); > - if (ret) { > - printk(KERN_ERR "Remapping memory, error: %d\n", ret); > - return ret; > - } > - > - uaddr += PAGE_SIZE; > - usize -= PAGE_SIZE; > - } while (usize > 0); > - > + err = vm_insert_range_buggy(vma, buf->pages, buf->num_pages); > + if (err) { > + printk(KERN_ERR "Remapping memory, error: %d\n", err); > + return err; > + } > > /* >* Use common vm_area operations to track buffer refcount. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH 3/3] videobuf2: replace a layering violation with dma_map_resource
Hi Christoph, On 2019-01-17 18:21, Christoph Hellwig wrote: > On Mon, Jan 14, 2019 at 01:42:26PM +0100, Marek Szyprowski wrote: >> On 2019-01-11 19:17, Christoph Hellwig wrote: >>> vb2_dc_get_userptr pokes into arm direct mapping details to get the >>> resemblance of a dma address for a a physical address that does is >>> not backed by a page struct. Not only is this not portable to other >>> architectures with dma direct mapping offsets, but also not to uses >>> of IOMMUs of any kind. Switch to the proper dma_map_resource / >>> dma_unmap_resource interface instead. >>> >>> Signed-off-by: Christoph Hellwig >> There are checks for IOMMU presence in other places in vb2-dma-contig, >> so it was used only when no IOMMU is available, but I agree that the >> hacky code should be replaced by a generic code if possible. >> >> Tested-by: Marek Szyprowski >> >> V4L2 pipeline works fine on older Exynos-based boards with CMA and IOMMU >> disabled. > Do you know if these rely on the offsets? E.g. would they still work > with the patch below applied on top. That would keep the map_resource > semantics as-is as solve the issue pointed out by Robin for now. AFAIK that code was only used for sharing buffers between hardware modules that are a part of the same SoC, usually implemented as platform devices. AFAIR this never worked for devices on different buses. So far I wasn't aware on ANY which would require an offset for the DMA access. The first version of videobuf2-dc code even incorrectly used paddr instead of dma_addr as a buffer 'address' returned to the client drivers, because in case of those SoC this was exactly the same (see commits 472af2b05bdefcaee7e754e22cbf131110017ad6 and ba7fcb0c954921534707f08ebc4d8beeb2eb17e7). > If not I can only think of a flag to bypass the offseting for now, but > that would be pretty ugly. Or go for the long-term solution of > discovering the relationship between the two devices, as done by the > PCIe P2P code.. > > diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c > index 8e0359b04957..25bd19974223 100644 > --- a/kernel/dma/direct.c > +++ b/kernel/dma/direct.c > @@ -359,7 +359,7 @@ EXPORT_SYMBOL(dma_direct_map_sg); > dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr, > size_t size, enum dma_data_direction dir, unsigned long attrs) > { > - dma_addr_t dma_addr = phys_to_dma(dev, paddr); > + dma_addr_t dma_addr = paddr; > > if (unlikely(!dma_direct_possible(dev, dma_addr, size))) { > report_addr(dev, dma_addr, size); > > > Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH 3/3] videobuf2: replace a layering violation with dma_map_resource
Hi Christoph, On 2019-01-11 19:17, Christoph Hellwig wrote: > vb2_dc_get_userptr pokes into arm direct mapping details to get the > resemblance of a dma address for a a physical address that does is > not backed by a page struct. Not only is this not portable to other > architectures with dma direct mapping offsets, but also not to uses > of IOMMUs of any kind. Switch to the proper dma_map_resource / > dma_unmap_resource interface instead. > > Signed-off-by: Christoph Hellwig There are checks for IOMMU presence in other places in vb2-dma-contig, so it was used only when no IOMMU is available, but I agree that the hacky code should be replaced by a generic code if possible. Tested-by: Marek Szyprowski V4L2 pipeline works fine on older Exynos-based boards with CMA and IOMMU disabled. > --- > .../common/videobuf2/videobuf2-dma-contig.c | 41 --- > 1 file changed, 9 insertions(+), 32 deletions(-) > > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c > b/drivers/media/common/videobuf2/videobuf2-dma-contig.c > index aff0ab7bf83d..82389aead6ed 100644 > --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c > +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c > @@ -439,42 +439,14 @@ static void vb2_dc_put_userptr(void *buf_priv) > set_page_dirty_lock(pages[i]); > sg_free_table(sgt); > kfree(sgt); > + } else { > + dma_unmap_resource(buf->dev, buf->dma_addr, buf->size, > +buf->dma_dir, 0); > } > vb2_destroy_framevec(buf->vec); > kfree(buf); > } > > -/* > - * For some kind of reserved memory there might be no struct page available, > - * so all that can be done to support such 'pages' is to try to convert > - * pfn to dma address or at the last resort just assume that > - * dma address == physical address (like it has been assumed in earlier > version > - * of videobuf2-dma-contig > - */ > - > -#ifdef __arch_pfn_to_dma > -static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long > pfn) > -{ > - return (dma_addr_t)__arch_pfn_to_dma(dev, pfn); > -} > -#elif defined(__pfn_to_bus) > -static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long > pfn) > -{ > - return (dma_addr_t)__pfn_to_bus(pfn); > -} > -#elif defined(__pfn_to_phys) > -static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long > pfn) > -{ > - return (dma_addr_t)__pfn_to_phys(pfn); > -} > -#else > -static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long > pfn) > -{ > - /* really, we cannot do anything better at this point */ > - return (dma_addr_t)(pfn) << PAGE_SHIFT; > -} > -#endif > - > static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, > unsigned long size, enum dma_data_direction dma_dir) > { > @@ -528,7 +500,12 @@ static void *vb2_dc_get_userptr(struct device *dev, > unsigned long vaddr, > for (i = 1; i < n_pages; i++) > if (nums[i-1] + 1 != nums[i]) > goto fail_pfnvec; > - buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, nums[0]); > + buf->dma_addr = dma_map_resource(buf->dev, > + __pfn_to_phys(nums[0]), size, buf->dma_dir, 0); > + if (dma_mapping_error(buf->dev, buf->dma_addr)) { > + ret = -ENOMEM; > + goto fail_pfnvec; > + } > goto out; > } > Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: fix a layering violation in videobuf2 and improve dma_map_resource
Hi Christoph, On 2019-01-11 19:17, Christoph Hellwig wrote: > Hi all, > > this series fixes a rather gross layering violation in videobuf2, which > pokes into arm DMA mapping internals to get a DMA address for memory that > does not have a page structure, and to do so fixes up the dma_map_resource > implementation to be practically useful. Thanks for rewriting this 'temporary code'! It predates dma_map_resource() and that time this was the only way to get it working somehow. Good that now it is possible to implement in it a clean way without any unwritten assumptions about the DMA mapping internals. Feel free to add my: Reviewed-by: Marek Szyprowski Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] media: s5p-mfc: fix incorrect bus assignment in virtual child device
Virtual MFC codec's child devices must not be assigned to platform bus, because they are allocated as raw 'struct device' and don't have the corresponding 'platform' part. This fixes NULL pointer access revealed recently by commit a66d972465d1 ("devres: Align data[] to ARCH_KMALLOC_MINALIGN"). Reported-by: Paweł Chmiel Fixes: c79667dd93b0 ("media: s5p-mfc: replace custom reserved memory handling code with generic one") Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 927a1235408d..ca11f8a7569d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1089,7 +1089,6 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, device_initialize(child); dev_set_name(child, "%s:%s", dev_name(dev), name); child->parent = dev; - child->bus = dev->bus; child->coherent_dma_mask = dev->coherent_dma_mask; child->dma_mask = dev->dma_mask; child->release = s5p_mfc_memdev_release; -- 2.17.1
Re: [PATCH 7/9] videobuf2/videobuf2-dma-sg.c: Convert to use vm_insert_range
Hi Souptick, On 2018-11-15 16:50, Souptick Joarder wrote: > Convert to use vm_insert_range to map range of kernel memory > to user vma. > > Signed-off-by: Souptick Joarder > Reviewed-by: Matthew Wilcox Acked-by: Marek Szyprowski > --- > drivers/media/common/videobuf2/videobuf2-dma-sg.c | 23 > +++ > 1 file changed, 7 insertions(+), 16 deletions(-) > > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c > b/drivers/media/common/videobuf2/videobuf2-dma-sg.c > index 015e737..898adef 100644 > --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c > +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c > @@ -328,28 +328,19 @@ static unsigned int vb2_dma_sg_num_users(void *buf_priv) > static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) > { > struct vb2_dma_sg_buf *buf = buf_priv; > - unsigned long uaddr = vma->vm_start; > - unsigned long usize = vma->vm_end - vma->vm_start; > - int i = 0; > + unsigned long page_count = vma_pages(vma); > + int err; > > if (!buf) { > printk(KERN_ERR "No memory to map\n"); > return -EINVAL; > } > > - do { > - int ret; > - > - ret = vm_insert_page(vma, uaddr, buf->pages[i++]); > - if (ret) { > - printk(KERN_ERR "Remapping memory, error: %d\n", ret); > - return ret; > - } > - > - uaddr += PAGE_SIZE; > - usize -= PAGE_SIZE; > - } while (usize > 0); > - > + err = vm_insert_range(vma, vma->vm_start, buf->pages, page_count); > + if (err) { > + printk(KERN_ERR "Remapping memory, error: %d\n", err); > + return err; > + } > > /* >* Use common vm_area operations to track buffer refcount. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] media: videobuf2-core: Fix error handling when fileio is deallocated
Hi Myungho, On 2018-11-12 01:49, Myungho Jung wrote: > The mutex that is held from vb2_fop_read() can be unlocked while waiting > for a buffer if the queue is streaming and blocking. Meanwhile, fileio > can be released. So, it should return an error if the fileio address is > changed. > > Signed-off-by: Myungho Jung > Reported-by: syzbot+4180ff9ca6810b06c...@syzkaller.appspotmail.com Acked-by: Marek Szyprowski Thanks for analyzing the code and fixing this issue! > --- > drivers/media/common/videobuf2/videobuf2-core.c | 4 > 1 file changed, 4 insertions(+) > > diff --git a/drivers/media/common/videobuf2/videobuf2-core.c > b/drivers/media/common/videobuf2/videobuf2-core.c > index 975ff5669f72..bff94752eb27 100644 > --- a/drivers/media/common/videobuf2/videobuf2-core.c > +++ b/drivers/media/common/videobuf2/videobuf2-core.c > @@ -2564,6 +2564,10 @@ static size_t __vb2_perform_fileio(struct vb2_queue > *q, char __user *data, size_ > dprintk(5, "vb2_dqbuf result: %d\n", ret); > if (ret) > return ret; > + if (fileio != q->fileio) { > + dprintk(3, "fileio deallocated\n"); > + return -EFAULT; > + } > fileio->dq_count += 1; > > fileio->cur_index = index; Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] MAINTAINERS: update videobuf2 entry
Commits 03fbdb2fc2b8 ("media: move videobuf2 to drivers/media/common") and 7952be9b6ece ("media: drivers/media/common/videobuf2: rename from videobuf") moved videobuf2 framework source code finally to drivers/media/common/videobuf2 directory, so update relevant paths in MAINTAINERS file. Reported-by: Joe Perches Signed-off-by: Marek Szyprowski --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 29c08106bd22..4455fe05d3a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15720,7 +15720,7 @@ M: Marek Szyprowski M: Kyungmin Park L: linux-media@vger.kernel.org S: Maintained -F: drivers/media/v4l2-core/videobuf2-* +F: drivers/media/common/videobuf2/* F: include/media/videobuf2-* VIMC VIRTUAL MEDIA CONTROLLER DRIVER -- 2.17.1
[PATCH] media: s5p-mfc: Use real device for request_firmware() call
Provide proper (real) struct device to request_firmware() call. This fixes following error messages: (NULL device *): Direct firmware load for s5p-mfc-v6-v2.fw failed with error -2 (NULL device *): Direct firmware load for s5p-mfc-v6.fw failed with error -2 into a bit more meaningful ones: s5p-mfc 1100.codec: Direct firmware load for s5p-mfc-v6-v2.fw failed with error -2 s5p-mfc 1100.codec: Direct firmware load for s5p-mfc-v6.fw failed with error -2 Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index f95cd76af537..ef9ae969d307 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -62,7 +62,7 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) if (!dev->variant->fw_name[i]) continue; err = request_firmware((const struct firmware **)&fw_blob, - dev->variant->fw_name[i], dev->v4l2_dev.dev); + dev->variant->fw_name[i], &dev->plat_dev->dev); if (!err) { dev->fw_ver = (enum s5p_mfc_fw_ver) i; break; -- 2.15.0
Re: [PATCH 1/8] clk: Add clk_bulk_alloc functions
Hi Robin, On 2018-02-19 17:29, Robin Murphy wrote: Hi Maciej, On 19/02/18 15:43, Maciej Purski wrote: When a driver is going to use clk_bulk_get() function, it has to initialize an array of clk_bulk_data, by filling its id fields. Add a new function to the core, which dynamically allocates clk_bulk_data array and fills its id fields. Add clk_bulk_free() function, which frees the array allocated by clk_bulk_alloc() function. Add a managed version of clk_bulk_alloc(). Seeing how every subsequent patch ends up with the roughly this same stanza: x = devm_clk_bulk_alloc(dev, num, names); if (IS_ERR(x) return PTR_ERR(x); ret = devm_clk_bulk_get(dev, x, num); I wonder if it might be better to simply implement: int devm_clk_bulk_alloc_get(dev, &x, num, names) that does the whole lot in one go, and let drivers that want to do more fiddly things continue to open-code the allocation. But perhaps that's an abstraction too far... I'm not all that familiar with the lie of the land here. Hmmm. This patchset clearly shows, that it would be much simpler if we get rid of clk_bulk_data structure at all and let clk_bulk_* functions to operate on struct clk *array[]. Typically the list of clock names is already in some kind of array (taken from driver data or statically embedded into driver), so there is little benefit from duplicating it in clk_bulk_data. Sadly, I missed clk_bulk_* api discussion and maybe there are other benefits from this approach. If not, I suggest simplifying clk_bulk_* api by dropping clk_bulk_data structure and switching to clock ptr array: int clk_bulk_get(struct device *dev, int num_clock, struct clk *clocks[], const char *clk_names[]); int clk_bulk_prepare(int num_clks, struct clk *clks[]); int clk_bulk_enable(int num_clks, struct clk *clks[]); ... Signed-off-by: Maciej Purski --- drivers/clk/clk-bulk.c | 16 drivers/clk/clk-devres.c | 37 +--- include/linux/clk.h | 64 3 files changed, 113 insertions(+), 4 deletions(-) [...] @@ -598,6 +645,23 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id); #else /* !CONFIG_HAVE_CLK */ +static inline struct clk_bulk_data *clk_bulk_alloc(int num_clks, + const char **clk_ids) +{ + return NULL; Either way, is it intentional not returning an ERR_PTR() value in this case? Since NULL will pass an IS_ERR() check, it seems a bit fragile for an allocation call to apparently succeed when the whole API is configured out (and I believe introducing new uses of IS_ERR_OR_NULL() is in general strongly discouraged.) Robin. +} + +static inline struct clk_bulk_data *devm_clk_bulk_alloc(struct device *dev, + int num_clks, + const char **clk_ids) +{ + return NULL; +} + +static inline void clk_bulk_free(struct clk_bulk_data *clks) +{ +} + static inline struct clk *clk_get(struct device *dev, const char *id) { return NULL; Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v2] media: vb2: Fix videobuf2 to map correct area
Hi Masami, On 2018-02-06 09:02, Masami Hiramatsu wrote: Fixes vb2_vmalloc_get_userptr() to ioremap correct area. Since the current code does ioremap the page address, if the offset > 0, it does not do ioremap the last page and results in kernel panic. This fixes to pass the size + offset to ioremap so that ioremap can map correct area. Also, this uses __pfn_to_phys() to get the physical address of given PFN. Signed-off-by: Masami Hiramatsu Reported-by: Takao Orito Reported-by: Fumihiro ATSUMI Reviewed-by: Marek Szyprowski --- Chanegs in v2: - Fix to pass size + offset instead of changing address. --- drivers/media/v4l2-core/videobuf2-vmalloc.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 3a7c80cd1a17..359fb9804d16 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) - ioremap_nocache(nums[0] << PAGE_SHIFT, size); + ioremap_nocache(__pfn_to_phys(nums[0]), size + offset); } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] [BUGFIX] media: vb2: Fix videobuf2 to map correct area
Hi Masami, On 2018-02-05 03:30, Masami Hiramatsu wrote: Fixes vb2_vmalloc_get_userptr() to ioremap correct area. Since the current code does ioremap the page address, if the offset > 0, it does not do ioremap the last page and results in kernel panic. This fixes to pass the page address + offset to ioremap so that ioremap can map correct area. Also, this uses __pfn_to_phys() to get the physical address of given PFN. Signed-off-by: Masami Hiramatsu Reported-by: Takao Orito --- drivers/media/v4l2-core/videobuf2-vmalloc.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 3a7c80cd1a17..896f2f378b40 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) - ioremap_nocache(nums[0] << PAGE_SHIFT, size); + ioremap_nocache(__pfn_to_phys(nums[0]) + offset, size); Thanks for reporting this issue. However the above line doesn't look like a proper fix. Please note that at the end of that function there is already "buf->vaddr += offset;". IMHO the proper fix is to create a larger mapping, which would include the in-page start offset: ioremap_nocache(__pfn_to_phys(nums[0]), offset + size); BTW, thanks for updating "<< PAGE_SHIFT" to better __pfn_to_phys() macro! } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v2] media: s5p-mfc: Add support for V4L2_MEMORY_DMABUF type
Hi Hans, On 2017-12-15 16:57, Hans Verkuil wrote: On 14/12/17 15:11, Marek Szyprowski wrote: 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. Okay, I will prepare a patch with such flag soon. Is this an MFC limitation for the decoder, encoder or both? And is it a limitation of the capture or output side or both? Both and both. DMA addresses of all buffers must be known while initializing decoder and encoder. > ... Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v2] media: s5p-mfc: Add support for V4L2_MEMORY_DMABUF type
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) 2. add a V4L2 device flag to let userspace to discover if device support queue buffer reconfiguration on-fly or not? 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 lik
Re: [PATCH 12/12] media: videobuf2: don't use kernel-doc "/**" markups
Hi Mauro, On 2017-11-29 11:46, Mauro Carvalho Chehab wrote: While it would be very cool to have those functions using kernel-doc markups, the reality right now is that they don't follow kernel-doc rules, as parameters aren't documented. So, stop abusing on "/**" markups. Signed-off-by: Mauro Carvalho Chehab Acked-by: Marek Szyprowski --- drivers/media/v4l2-core/videobuf2-core.c | 56 drivers/media/v4l2-core/videobuf2-v4l2.c | 10 +++--- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index cb115ba6a1d2..a8589d96ef72 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -188,7 +188,7 @@ module_param(debug, int, 0644); static void __vb2_queue_cancel(struct vb2_queue *q); static void __enqueue_in_driver(struct vb2_buffer *vb); -/** +/* * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) @@ -229,7 +229,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) return ret; } -/** +/* * __vb2_buf_mem_free() - free memory of the given buffer */ static void __vb2_buf_mem_free(struct vb2_buffer *vb) @@ -243,7 +243,7 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) } } -/** +/* * __vb2_buf_userptr_put() - release userspace memory associated with * a USERPTR buffer */ @@ -258,7 +258,7 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) } } -/** +/* * __vb2_plane_dmabuf_put() - release memory associated with * a DMABUF shared plane */ @@ -277,7 +277,7 @@ static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct vb2_plane *p) p->dbuf_mapped = 0; } -/** +/* * __vb2_buf_dmabuf_put() - release memory associated with * a DMABUF shared buffer */ @@ -289,7 +289,7 @@ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); } -/** +/* * __setup_offsets() - setup unique offsets ("cookies") for every plane in * the buffer. */ @@ -317,7 +317,7 @@ static void __setup_offsets(struct vb2_buffer *vb) } } -/** +/* * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type) * video buffer memory for all buffers/planes on the queue and initializes the * queue @@ -386,7 +386,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, return buffer; } -/** +/* * __vb2_free_mem() - release all video buffer memory for a given queue */ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) @@ -410,7 +410,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) } } -/** +/* * __vb2_queue_free() - free buffers at the end of the queue - video memory and * related information, if no buffers are left return the queue to an * uninitialized state. Might be called even if the queue has already been freed. @@ -544,7 +544,7 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) } EXPORT_SYMBOL(vb2_buffer_in_use); -/** +/* * __buffers_in_use() - return true if any buffers on the queue are in use and * the queue cannot be freed (by the means of REQBUFS(0)) call */ @@ -564,7 +564,7 @@ void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) } EXPORT_SYMBOL_GPL(vb2_core_querybuf); -/** +/* * __verify_userptr_ops() - verify that all memory operations required for * USERPTR queue type have been provided */ @@ -577,7 +577,7 @@ static int __verify_userptr_ops(struct vb2_queue *q) return 0; } -/** +/* * __verify_mmap_ops() - verify that all memory operations required for * MMAP queue type have been provided */ @@ -590,7 +590,7 @@ static int __verify_mmap_ops(struct vb2_queue *q) return 0; } -/** +/* * __verify_dmabuf_ops() - verify that all memory operations required for * DMABUF queue type have been provided */ @@ -953,7 +953,7 @@ void vb2_discard_done(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_discard_done); -/** +/* * __prepare_mmap() - prepare an MMAP buffer */ static int __prepare_mmap(struct vb2_buffer *vb, const void *pb) @@ -966,7 +966,7 @@ static int __prepare_mmap(struct vb2_buffer *vb, const void *pb) return ret ? ret : call_vb_qop(vb, buf_prepare, vb); } -/** +/* * __prepare_userptr() - prepare a USERPTR buffer */ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb) @@ -1082,7 +1082,7 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb) return ret; } -/** +/* * __prepare_dmabuf() - prepare a DMABUF buffer */ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb) @@ -1215,
Re: [PATCH v2] media: s5p-mfc: Add support for V4L2_MEMORY_DMABUF type
Hi Nicolas, 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. 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. 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. 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. Signed-off-by: Seung-Woo Kim [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 --- 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 @@ -75
[PATCH v2] media: s5p-mfc: Add support for V4L2_MEMORY_DMABUF type
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. 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. Signed-off-by: Seung-Woo Kim [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 --- 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_c
Re: [PATCH] media: s5p-mfc: Add support for V4L2_MEMORY_DMABUF type
Hi Tobias, On 2017-10-20 15:59, Tobias Jakobi wrote: Hey Marek and others, just wanted to point out that I've also played around with Seung-Woo' patch for a while. However this patch alone is very much incomplete. In particular this is missing: - At least v5 MFC hw needs source buffers to be also writable, so dma mapping needs to be setup bidirectional. - Like with mmap, all buffers need to be setup before decoding can begin. This is due to how MFC hw gets initialized. dmabufs that are added later are not going to be used before MFC hw isn't reinitialized. - Removing dmabufs, or replacing them seems to be impossible with the current code architecture. Right. Those are limitations of the hardware and in next version of this patch I will add checks for them. I had extended samsung-utils with some C++ app to test stuff when I was looking into this. You can find the code here: https://github.com/tobiasjakobi/samsung-utils/tree/devel/v4l2-mfc-drm-direct Now here is what happens. I allocate N buffer objects in DRM land to be used as destination for the MFC decoder. The BOs are exported, so that I can then use them in V4L2 space. I have to queue n (with n < N) buffers before I can start the MFC engine. According to my knowledge of the MFC HW, if you want to use N buffers with MFC, you have to queue all N buffers to initialize the HW. Otherwise, HW will produce video data only to the n buffer queued on stream on. If I do start the engine at that point (n buffers queued), I soon get an IOMMU pagefault. I need to queue all N buffers before anything works at all. Queueing a buffer the first time also registers it, and this has to happen before the MFC hw is initialized. In particular I can't just allocate more buffers from DRM and use them here _after_ decoding has started. To me it looks like the MFC code was never written with dmabuf in mind. It's centered around a static memory setup that is fixed before decoding begins. That's true, but still, using it with DMA-bufs might be convenient in some cases, even with the above limitations. The IOMMU fault can be mitigated by enabling bidirectional flag on OUTPUT queue. This is a bit strange, but that's how the hardware behaves. From my research it looks that it happens only in case of MFCv5, higher versions don't modify source stream. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH 2/2] media: exynos4-is: drop obsolete capabilities
Setting both V4L2_CAP_VIDEO_CAPTURE_MPLANE and V4L2_CAP_VIDEO_OUTPUT_MPLANE for mem2mem video nodes is obsolete since commit f0476a83d61a ("[media] V4L: Add capability flags for memory-to-memory devices"). It was enough time to adapt all users to the new flags, so drop the legacy caps for now to match other mem2mem drivers. Signed-off-by: Marek Szyprowski --- drivers/media/platform/exynos4-is/fimc-m2m.c | 10 +- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 9027d0b0d2bd..a19f8b164a47 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -236,15 +236,7 @@ static int fimc_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { struct fimc_dev *fimc = video_drvdata(file); - unsigned int caps; - - /* -* This is only a mem-to-mem video device. The capture and output -* device capability flags are left only for backward compatibility -* and are scheduled for removal. -*/ - caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; + unsigned int caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); return 0; -- 2.14.2
[PATCH 1/2] media: exynos-gsc: drop obsolete capabilities
Setting both V4L2_CAP_VIDEO_CAPTURE_MPLANE and V4L2_CAP_VIDEO_OUTPUT_MPLANE for mem2mem video nodes is obsolete since commit f0476a83d61a ("[media] V4L: Add capability flags for memory-to-memory devices"). It was enough time to adapt all users to the new flags, so drop the legacy caps for now to match other mem2mem drivers. Signed-off-by: Marek Szyprowski --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 722d7c45bf9e..785e67752194 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -298,9 +298,7 @@ static int gsc_m2m_querycap(struct file *file, void *fh, strlcpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&gsc->pdev->dev)); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; - + cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- 2.14.2
[PATCH] media: s5p-mfc: Add support for V4L2_MEMORY_DMABUF type
From: Seung-Woo Kim There is memory constraint for the buffers in V5 of the MFC hardware, but when IOMMU is used, then this constraint is meaningless. Other version of the MFC hardware don't have such limitations. So in such cases the driver is able to use buffers placed anywhere in the system memory, thus USERPTR and DMABUF operation modes can be also enabled. This patch also removes USERPTR operation mode from encoder node, as it doesn't work with v5 MFC hardware without IOMMU being enabled. Signed-off-by: Seung-Woo Kim [mszyprow: adapted to v4.14 code base and updated commit message] Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 14 -- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 73 drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 24 ++--- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index cf68aed59e0d..f975523dc040 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,21 @@ 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->drv_priv = &ctx->fh; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { - q->io_modes = VB2_MMAP; + q->io_modes = io_modes; q->ops = get_dec_queue_ops(); } else if (vdev == dev->vfd_enc) { - q->io_modes = VB2_MMAP | VB2_USERPTR; + q->io_modes = io_modes; q->ops = get_enc_queue_ops(); } else { ret = -ENOENT; @@ -872,10 +878,10 @@ static int s5p_mfc_open(struct file *file) q->drv_priv = &ctx->fh; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { - q->io_modes = VB2_MMAP; + q->io_modes = io_modes; q->ops = get_dec_queue_ops(); } else if (vdev == dev->vfd_enc) { - q->io_modes = VB2_MMAP | VB2_USERPTR; + q->io_modes = io_modes; 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 8937b0af7cb3..efe65fce4880 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -546,14 +546,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; @@ -571,15 +584,19 @@ static int vidioc_reqbufs(struct file *file, void *priv, { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p
Re: Exynos MFC issues on 4.14-rc4
Hi Marian, On 2017-10-12 02:49, Marian Mihailescu wrote: I've been testing 4.14-rc4 on Odroid-XU4, and here's a kernel complaint when running: gst-launch-1.0 filesrc location=bunny_trailer_1080p.mov ! parsebin ! v4l2video4dec capture-io-mode=dmabuf ! v4l2video6convert output-io-mode=dmabuf-import capture-io-mode=dmabuf ! kmssink http://paste.debian.net/990353/ This is rather harmless and it happens on v4.14-rcX, because LOCKDEP has been enabled by default in the exynos_defconfig. For more information see https://lkml.org/lkml/2017/10/13/974 PS: on kernel 4.9 patched with MFC & GSC updates (almost up to date with 4.14 I think) there was no "Wrong buffer/video queue type (1)" message either I will check it and let you know if this is something we should worry about. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH 0/2] fix lockdep warnings in s5p_mfc and exynos-gsc vb2 drivers
Hi Shuah, On 2017-10-14 01:13, Shuah Khan wrote: Driver mmap functions shouldn't hold lock when calling vb2_mmap(). The vb2_mmap() function has its own lock that it uses to protect the critical section. Reference: commit log for f035eb4e976ef5a059e30bc91cfd310ff030a7d3 It would make sense to add the information about the reference commit to each commit message and also point to commit e752577ed7bf55c81e10343fced8b378cda2b63b, as it is exactly the same case here. Anyway: Acked-by: Marek Szyprowski I wonder if makes sense to send those patches also to sta...@vget.kernel.org (maybe v4.3+, like the mentioned above commit, if they really apply?). Shuah Khan (2): media: exynos-gsc: fix lockdep warning media: s5p-mfc: fix lockdep warning drivers/media/platform/exynos-gsc/gsc-m2m.c | 5 - drivers/media/platform/s5p-mfc/s5p_mfc.c| 3 --- 2 files changed, 8 deletions(-) Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] media: vb2: unify calling of set_page_dirty_lock
Hi Stanimir, On 2017-10-10 09:42, Stanimir Varbanov wrote: Marek, Any comments? Oh, I thought that this one has been already merged. If not (yet), here is my ack. On 08/29/2017 02:26 PM, Stanimir Varbanov wrote: Currently videobuf2-dma-sg checks for dma direction for every single page and videobuf2-dc lacks any dma direction checks and calls set_page_dirty_lock unconditionally. Thus unify and align the invocations of set_page_dirty_lock for videobuf2-dc, videobuf2-sg memory allocators with videobuf2-vmalloc, i.e. the pattern used in vmalloc has been copied to dc and dma-sg. Suggested-by: Marek Szyprowski Signed-off-by: Stanimir Varbanov Acked-by: Marek Szyprowski --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 6 -- drivers/media/v4l2-core/videobuf2-dma-sg.c | 7 +++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 9f389f36566d..696e24f9128d 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -434,8 +434,10 @@ static void vb2_dc_put_userptr(void *buf_priv) pages = frame_vector_pages(buf->vec); /* sgt should exist only if vector contains pages... */ BUG_ON(IS_ERR(pages)); - for (i = 0; i < frame_vector_count(buf->vec); i++) - set_page_dirty_lock(pages[i]); + if (buf->dma_dir == DMA_FROM_DEVICE || + buf->dma_dir == DMA_BIDIRECTIONAL) + for (i = 0; i < frame_vector_count(buf->vec); i++) + set_page_dirty_lock(pages[i]); sg_free_table(sgt); kfree(sgt); } diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 6808231a6bdc..753ed3138dcc 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -292,11 +292,10 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) if (buf->vaddr) vm_unmap_ram(buf->vaddr, buf->num_pages); sg_free_table(buf->dma_sgt); - while (--i >= 0) { - if (buf->dma_dir == DMA_FROM_DEVICE || - buf->dma_dir == DMA_BIDIRECTIONAL) + if (buf->dma_dir == DMA_FROM_DEVICE || + buf->dma_dir == DMA_BIDIRECTIONAL) + while (--i >= 0) set_page_dirty_lock(buf->pages[i]); - } vb2_destroy_framevec(buf->vec); kfree(buf); } Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH 4/7] media: exynos4-is: Remove dependency on obsolete SoC support
Support for Exynos4212 SoCs has been removed by commit bca9085e0ae9 ("ARM: dts: exynos: remove Exynos4212 support (dead code)"), so there is no need to keep remaining dead code related to this SoC version. Signed-off-by: Marek Szyprowski --- drivers/media/platform/exynos4-is/Kconfig | 2 +- drivers/media/platform/exynos4-is/fimc-core.c | 2 +- drivers/media/platform/exynos4-is/fimc-lite.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 46a7d242a1a5..7b2c49e5a592 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -41,7 +41,7 @@ config VIDEO_S5P_MIPI_CSIS To compile this driver as a module, choose M here: the module will be called s5p-csis. -if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 +if SOC_EXYNOS4412 || SOC_EXYNOS5250 config VIDEO_EXYNOS_FIMC_LITE tristate "EXYNOS FIMC-LITE camera interface driver" diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 099c735a39b7..7ae239f2b0fd 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -1211,7 +1211,7 @@ static const struct fimc_drvdata fimc_drvdata_exynos4210 = { .out_buf_count = 32, }; -/* EXYNOS4212, EXYNOS4412 */ +/* EXYNOS4412 */ static const struct fimc_drvdata fimc_drvdata_exynos4x12 = { .num_entities = 4, .lclk_frequency = 16600UL, diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 4a3c9948ca54..3805a6daa3f4 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1646,7 +1646,7 @@ static const struct dev_pm_ops fimc_lite_pm_ops = { NULL) }; -/* EXYNOS4212, EXYNOS4412 */ +/* EXYNOS4412 */ static struct flite_drvdata fimc_lite_drvdata_exynos4 = { .max_width = 8192, .max_height = 8192, -- 2.14.2
Re: [PATCH v2 16/17] media: videobuf2-core: improve kernel-doc markups
Hi, On 2017-09-27 23:46, Mauro Carvalho Chehab wrote: Now that nested structs are supported, change the documentation to use it. While here, add cross-references where pertinent and use monotonic fonts where pertinent, using the right markup tags. Signed-off-by: Mauro Carvalho Chehab Acked-by: Marek Szyprowski --- include/media/videobuf2-core.h | 59 +- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index ef9b64398c8c..5f4df060affb 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -69,7 +69,7 @@ struct vb2_threadio_data; * argument to other ops in this structure. * @put_userptr: inform the allocator that a USERPTR buffer will no longer * be used. - * @attach_dmabuf: attach a shared struct dma_buf for a hardware operation; + * @attach_dmabuf: attach a shared &struct dma_buf for a hardware operation; * used for DMABUF memory types; dev is the alloc device * dbuf is the shared dma_buf; returns ERR_PTR() on failure; * allocator private per-buffer structure on success; @@ -153,20 +153,19 @@ struct vb2_mem_ops { * @length: size of this plane (NOT the payload) in bytes * @min_length: minimum required size of this plane (NOT the payload) in bytes. *@length is always greater or equal to @min_length. - * @offset:when memory in the associated struct vb2_buffer is - * VB2_MEMORY_MMAP, equals the offset from the start of + * @m: Union with memtype-specific data + * @m.offset: when memory in the associated struct vb2_buffer is + * %VB2_MEMORY_MMAP, equals the offset from the start of *the device memory for this plane (or is a "cookie" that *should be passed to mmap() called on the video node) - * @userptr: when memory is VB2_MEMORY_USERPTR, a userspace pointer + * @m.userptr: when memory is %VB2_MEMORY_USERPTR, a userspace pointer *pointing to this plane - * @fd:when memory is VB2_MEMORY_DMABUF, a userspace file + * @m.fd: when memory is %VB2_MEMORY_DMABUF, a userspace file *descriptor associated with this plane - * @m: Union with memtype-specific data (@offset, @userptr or - * @fd). * @data_offset: offset in the plane to the start of data; usually 0, *unless there is a header in front of the data * Should contain enough information to be able to cover all the fields - * of struct v4l2_plane at videodev2.h + * of &struct v4l2_plane at videodev2.h */ struct vb2_plane { void*mem_priv; @@ -356,7 +355,7 @@ struct vb2_buffer { *driver can return an error if hardware fails, in that *case all buffers that have been already given by *the @buf_queue callback are to be returned by the driver - * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED. + * by calling vb2_buffer_done() with %%VB2_BUF_STATE_QUEUED. *If you need a minimum number of buffers before you can *start streaming, then set @min_buffers_needed in the *vb2_queue structure. If that is non-zero then @@ -366,7 +365,7 @@ struct vb2_buffer { *should stop any DMA transactions or wait until they *finish and give back all buffers it got from &buf_queue *callback by calling vb2_buffer_done() with either - * %VB2_BUF_STATE_DONE or %VB2_BUF_STATE_ERROR; may use + * %VB2_BUF_STATE_DONE or %%VB2_BUF_STATE_ERROR; may use *vb2_wait_for_all_buffers() function * @buf_queue:passes buffer vb to the driver; driver may start *hardware operation on this buffer; driver should give @@ -401,13 +400,13 @@ struct vb2_ops { * @verify_planes_array: Verify that a given user space structure contains *enough planes for the buffer. This is called *for each dequeued buffer. - * @fill_user_buffer: given a vb2_buffer fill in the userspace structure. + * @fill_user_buffer: given a &vb2_buffer fill in the userspace structure. *For V4L2 this is a struct v4l2_buffer. - * @fill_vb2_buffer: given a userspace structure, fill in the vb2_buffer. + * @fill_vb2_buffer: given a userspace structure, fill in the &vb2_buffer. *If the userspace structure is invalid, then this op *will return an error. * @copy_timestamp: copy the timestamp from a userspace structure to - * the vb2_buffer struct. + *
Re: [PATCH 1/7 v3] media: vb2: add bidirectional flag in vb2_queue
Hi Stanimir, On 2017-08-21 13:34, Stanimir Varbanov wrote: This change is intended to give to the v4l2 drivers a choice to change the default behavior of the v4l2-core DMA mapping direction from DMA_TO/FROM_DEVICE (depending on the buffer type CAPTURE or OUTPUT) to DMA_BIDIRECTIONAL during queue_init time. Initially the issue with DMA mapping direction has been found in Venus encoder driver where the hardware (firmware side) adds few lines padding on bottom of the image buffer, and the consequence is triggering of IOMMU protection faults. This will help supporting venus encoder (and probably other drivers in the future) which wants to map output type of buffers as read/write. Signed-off-by: Stanimir Varbanov Thanks for the patch. Acked-by: Marek Szyprowski While touching this, I would love to unify set_page_dirty_lock() related code in videobuf2-dc, videobuf2-sg and videobuf2-vmalloc. IMHO the pattern used in videobuf2-vmalloc should be copied to videobuf2-sg (currently checks for dma_dir for every single page) and videobuf2-dc (currently it lacks any checks and calls set_page_dirty_lock() unconditionally). If you have a little bit of spare time, please prepare a separate patch for the above mentioned fix. --- v3: update V4L2 dma-sg/contig and vmalloc memory type ops with a check for DMA_BIDIRECTIONAL. v2: move dma_dir into private section. drivers/media/v4l2-core/videobuf2-core.c | 17 - drivers/media/v4l2-core/videobuf2-dma-contig.c | 3 ++- drivers/media/v4l2-core/videobuf2-dma-sg.c | 6 -- drivers/media/v4l2-core/videobuf2-vmalloc.c| 6 -- include/media/videobuf2-core.h | 13 + 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 0924594989b4..cb115ba6a1d2 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -194,8 +194,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb); static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; - enum dma_data_direction dma_dir = - q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; void *mem_priv; int plane; int ret = -ENOMEM; @@ -209,7 +207,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) mem_priv = call_ptr_memop(vb, alloc, q->alloc_devs[plane] ? : q->dev, - q->dma_attrs, size, dma_dir, q->gfp_flags); + q->dma_attrs, size, q->dma_dir, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) { if (mem_priv) ret = PTR_ERR(mem_priv); @@ -978,8 +976,6 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb) void *mem_priv; unsigned int plane; int ret = 0; - enum dma_data_direction dma_dir = - q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); @@ -1030,7 +1026,7 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb) mem_priv = call_ptr_memop(vb, get_userptr, q->alloc_devs[plane] ? : q->dev, planes[plane].m.userptr, - planes[plane].length, dma_dir); + planes[plane].length, q->dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed acquiring userspace memory for plane %d\n", plane); @@ -1096,8 +1092,6 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb) void *mem_priv; unsigned int plane; int ret = 0; - enum dma_data_direction dma_dir = - q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); @@ -1156,7 +1150,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, attach_dmabuf, q->alloc_devs[plane] ? : q->dev, - dbuf, planes[plane].length, dma_dir); + dbuf, planes[plane].length, q->dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed to attach dmabuf\n"); ret = PTR_ERR(mem_priv); @@ -2003,6 +1997,11 @@ int vb2_core_queue_init(struct vb2_queue *q) if (q->buf_struct_size == 0) q->buf_struct_size = sizeof(struct vb2_buf
Re: [PATCH 1/7 v2] media: vb2: add bidirectional flag in vb2_queue
doesn't fill in the @alloc_devs array. * @dma_attrs:DMA attributes to use for the DMA. + * @bidirectional: when this flag is set the DMA direction for the buffers of + * this queue will be overridden with DMA_BIDIRECTIONAL direction. + * This is useful in cases where the hardware (firmware) writes to + * a buffer which is mapped as read (DMA_TO_DEVICE), or reads from + * buffer which is mapped for write (DMA_FROM_DEVICE) in order + * to satisfy some internal hardware restrictions or adds a padding + * needed by the processing algorithm. In case the DMA mapping is + * not bidirectional but the hardware (firmware) trying to access + * the buffer (in the opposite direction) this could lead to an + * IOMMU protection faults. * @fileio_read_once: report EOF after reading the first buffer * @fileio_write_immediately: queue buffer after each write() call * @allow_zero_bytesused: allow bytesused == 0 to be passed to the driver @@ -465,6 +475,7 @@ struct vb2_buf_ops { * Private elements (won't appear at the uAPI book): * @mmap_lock:private mutex used when buffers are allocated/freed/mmapped * @memory: current memory type used + * @dma_dir: DMA mapping direction. * @bufs: videobuf buffer structures * @num_buffers: number of allocated/used buffers * @queued_list: list of buffers currently queued from userspace @@ -495,6 +506,7 @@ struct vb2_queue { unsigned intio_modes; struct device *dev; unsigned long dma_attrs; + unsignedbidirectional:1; unsignedfileio_read_once:1; unsignedfileio_write_immediately:1; unsignedallow_zero_bytesused:1; @@ -516,6 +528,7 @@ struct vb2_queue { /* private: internal use only */ struct mutexmmap_lock; unsigned intmemory; + enum dma_data_direction dma_dir; struct vb2_buffer *bufs[VB2_MAX_FRAME]; unsigned intnum_buffers; Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v3 0/2] [media] videobuf2-dc: Add support for cacheable MMAP
Hi Christoph, On 2017-07-05 19:33, Christoph Hellwig wrote: On Mon, Jul 03, 2017 at 11:27:32AM +0200, Marek Szyprowski wrote: The main question here if we want to merge incomplete solution or not. As for now, there is no support in ARM/ARM64 for NON_CONSISTENT attribute. Also none of the v4l2 drivers use it. Sadly support for NON_CONSISTENT attribute is not fully implemented nor even defined in mainline. DMA_ATTR_NON_CONSISTENT is the way to get the dma_alloc_noncoherent semantics through the dma_alloc_attr API, and as such I think it is pretty well defined, although the documentation in Documentation/DMA-attributes.txt is really bad and we need to improve it, by merging it with the dma_alloc_noncoherent description in Documentation/DMA-API.txt. My series to remove dma_alloc_noncoherent updates the latter to mention DMA_ATTR_NON_CONSISTENT, but we should probably merge Documentation/DMA-API.txt, Documentation/DMA-attributes.txt and Documentation/DMA-API-HOWTO.txt into a single coherent document. Right. I started conversion of dma_alloc_noncoherent to NON_CONSISTENT DMA attribute, but later I got stuck at the details of cache synchronization. I know that it works fine for some vendor kernel trees, but supporting it in mainline was a bit controversial. There is no proper way to sync cache for such buffers. Calling dma_sync_sg worked so far, but it has to be first agreed as a proper DMA API. As documented in Documentation/DMA-API.txt the proper way to sync noncoherent/nonconsistent regions is to call dma_cache_sync. It seems like it generally is the same as dma_sync_range/sg so if we could eventually merge these APIs that should reduce the confusion further. Original dma_alloc_noncoherent utilized dma_cache_sync() function, which had some flaws, which prevented me to continue that task and introduce it to ARM architecture. The dma_alloc_noncoherent() and dma_cache_sync() API lacks buffer ownership and imprecisely defines how and when the caches has to be synchronized. dma_cache_sync() also lacks DMA address argument, what also complicates potential lightweight implementation. IMHO it would make sense to change it to work similar to the other dma_sync_*_for_{cpu,device} functions, but I didn't find enough time to finally take a try. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] media: vb2 dma-sg: Constify dma_buf_ops structures.
Hi Arvind, On 2017-07-01 14:18, Arvind Yadav wrote: dma_buf_ops are not supposed to change at runtime. All functions working with dma_buf_ops provided by work with const dma_buf_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 5238112 4535414ea drivers/media/v4l2-core/videobuf2-dma-sg.o File size After adding 'const': text data bss dec hex filename 5358 0 4536214f2 drivers/media/v4l2-core/videobuf2-dma-sg.o Signed-off-by: Arvind Yadav Acked-by: Marek Szyprowski --- drivers/media/v4l2-core/videobuf2-dma-sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 8e8798a..f8b4643 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -500,7 +500,7 @@ static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf, return vb2_dma_sg_mmap(dbuf->priv, vma); } -static struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { +static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { .attach = vb2_dma_sg_dmabuf_ops_attach, .detach = vb2_dma_sg_dmabuf_ops_detach, .map_dma_buf = vb2_dma_sg_dmabuf_ops_map, Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] media: vb2 dma-contig: Constify dma_buf_ops structures.
Hi Arvind, On 2017-07-01 13:27, Arvind Yadav wrote: dma_buf_ops are not supposed to change at runtime. All functions working with dma_buf_ops provided by work with const dma_buf_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 6035272 0630718a3 drivers/media/v4l2-core/videobuf2-dma-contig.o File size After adding 'const': text data bss dec hex filename 6155160 0631518ab drivers/media/v4l2-core/videobuf2-dma-contig.o Signed-off-by: Arvind Yadav Thanks! Acked-by: Marek Szyprowski --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 4f246d1..5b90a66 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -352,7 +352,7 @@ static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf, return vb2_dc_mmap(dbuf->priv, vma); } -static struct dma_buf_ops vb2_dc_dmabuf_ops = { +static const struct dma_buf_ops vb2_dc_dmabuf_ops = { .attach = vb2_dc_dmabuf_ops_attach, .detach = vb2_dc_dmabuf_ops_detach, .map_dma_buf = vb2_dc_dmabuf_ops_map, Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] media: vb2 vmalloc: Constify dma_buf_ops structures.
Hi Arvind, On 2017-07-01 13:37, Arvind Yadav wrote: dma_buf_ops are not supposed to change at runtime. All functions working with dma_buf_ops provided by work with const dma_buf_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 3171192 03363 d23 drivers/media/v4l2-core/videobuf2-vmalloc.o File size After adding 'const': text data bss dec hex filename 3291 80 03371 d2b drivers/media/v4l2-core/videobuf2-vmalloc.o Signed-off-by: Arvind Yadav Acked-by: Marek Szyprowski --- drivers/media/v4l2-core/videobuf2-vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index b337d78..6bc130f 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -338,7 +338,7 @@ static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf, return vb2_vmalloc_mmap(dbuf->priv, vma); } -static struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { +static const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { .attach = vb2_vmalloc_dmabuf_ops_attach, .detach = vb2_vmalloc_dmabuf_ops_detach, .map_dma_buf = vb2_vmalloc_dmabuf_ops_map, Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v3 0/2] [media] videobuf2-dc: Add support for cacheable MMAP
Hi All, On 2016-10-26 10:52, Thierry Escande wrote: This series adds support for cacheable MMAP in DMA coherent allocator. The first patch moves the vb2_dc_get_base_sgt() function above mmap callbacks for calls introduced by the second patch. This avoids a forward declaration. I'm sorry for late review. Sylwester kicked me for pending v4l2/vb2 patches and I've just found this thread in my TODO folder. The main question here if we want to merge incomplete solution or not. As for now, there is no support in ARM/ARM64 for NON_CONSISTENT attribute. Also none of the v4l2 drivers use it. Sadly support for NON_CONSISTENT attribute is not fully implemented nor even defined in mainline. I know that it works fine for some vendor kernel trees, but supporting it in mainline was a bit controversial. There is no proper way to sync cache for such buffers. Calling dma_sync_sg worked so far, but it has to be first agreed as a proper DMA API. Changes in v2: - Put function move in a separate patch - Added comments Changes in v3: - Remove redundant test on NO_KERNEL_MAPPING DMA attribute in mmap() Heng-Ruey Hsu (1): [media] videobuf2-dc: Support cacheable MMAP Thierry Escande (1): [media] videobuf2-dc: Move vb2_dc_get_base_sgt() above mmap callbacks drivers/media/v4l2-core/videobuf2-dma-contig.c | 60 -- 1 file changed, 38 insertions(+), 22 deletions(-) Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH v2] s5p-cec: update MAINTAINERS entry
I would like to replace Kyungmin Park, who is no longer interested in maintaining S5P-CEC driver. I have access to various Exynos boards. I also already did some tests of this driver and helped enabling it on various Exynos boards. The driver itself is no longer in staging, so lets fix the path too and add DT bindings file pattern match. Also change the mailing list from ARM generic to Samsung SoC specific to get more attention and easier review in the future. Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski --- v2: - added DT bindings file as suggested by Krzysztof Kozlowski --- MAINTAINERS | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 053c3bdd1fe5..52e516376139 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1775,11 +1775,12 @@ F: arch/arm/plat-samsung/s5p-dev-mfc.c F: drivers/media/platform/s5p-mfc/ ARM/SAMSUNG S5P SERIES HDMI CEC SUBSYSTEM SUPPORT -M: Kyungmin Park -L: linux-arm-ker...@lists.infradead.org +M: Marek Szyprowski +L: linux-samsung-...@vger.kernel.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained -F: drivers/staging/media/platform/s5p-cec/ +F: drivers/media/platform/s5p-cec/ +F: Documentation/devicetree/bindings/media/s5p-cec.txt ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT M: Andrzej Pietrasiewicz -- 1.9.1
[PATCH] s5p-cec: update MAINTAINERS entry
I would like to replace Kyungmin Park, who is no longer interested in maintaining S5P-CEC driver. I have access to various Exynos boards. I also already did some tests of this driver and helped enabling it on various Exynos boards. The driver itself is no longer in staging, so lets fix the path too. Also change the mailing list from ARM generic to Samsung SoC specific to get more attention and easier review in the future. Signed-off-by: Marek Szyprowski --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 053c3bdd1fe5..fbfbc9866fa2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1775,11 +1775,11 @@ F: arch/arm/plat-samsung/s5p-dev-mfc.c F: drivers/media/platform/s5p-mfc/ ARM/SAMSUNG S5P SERIES HDMI CEC SUBSYSTEM SUPPORT -M: Kyungmin Park -L: linux-arm-ker...@lists.infradead.org +M: Marek Szyprowski +L: linux-samsung-...@vger.kernel.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained -F: drivers/staging/media/platform/s5p-cec/ +F: drivers/media/platform/s5p-cec/ ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT M: Andrzej Pietrasiewicz -- 1.9.1
Re: [PATCH 5/9] [media] s5p-jpeg: Add IOMMU support
Hi All, I'm sorry for the late reply, I just got back from holidays. On 2017-06-02 23:43, Jacek Anaszewski wrote: Cc Marek Szyprowski. Marek, could you share your opinion about this patch? On 06/02/2017 06:02 PM, Thierry Escande wrote: From: Tony K Nadackal This patch adds support for IOMMU s5p-jpeg driver if the Exynos IOMMU and ARM DMA IOMMU configurations are supported. The address space is created with size limited to 256M and base address set to 0x2000. Could you clarify WHY this patch is needed? IOMMU core configures per-device IO address space by default and AFAIR JPEG module doesn't have any specific requirements for the IO address space layout (base or size), so it should work fine (and works in my tests!) without this patch. Please drop this patch for now. Signed-off-by: Tony K Nadackal Signed-off-by: Thierry Escande --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 77 + 1 file changed, 77 insertions(+) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 770a709..5569b99 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -28,6 +28,14 @@ #include #include #include +#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) +#include +#include +#include +#include +#include +#include +#endif #include "jpeg-core.h" #include "jpeg-hw-s5p.h" @@ -35,6 +43,10 @@ #include "jpeg-hw-exynos3250.h" #include "jpeg-regs.h" +#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) +static struct dma_iommu_mapping *mapping; +#endif + static struct s5p_jpeg_fmt sjpeg_formats[] = { { .name = "JPEG JFIF", @@ -956,6 +968,60 @@ static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx) } } +#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) +static int jpeg_iommu_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int err; + + mapping = arm_iommu_create_mapping(&platform_bus_type, 0x2000, + SZ_512M); + if (IS_ERR(mapping)) { + dev_err(dev, "IOMMU mapping failed\n"); + return PTR_ERR(mapping); + } + + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) { + err = -ENOMEM; + goto error_alloc; + } + + err = dma_set_max_seg_size(dev, 0xu); + if (err) + goto error; + + err = arm_iommu_attach_device(dev, mapping); + if (err) + goto error; + + return 0; + +error: + devm_kfree(dev, dev->dma_parms); + dev->dma_parms = NULL; + +error_alloc: + arm_iommu_release_mapping(mapping); + mapping = NULL; + + return err; +} + +static void jpeg_iommu_deinit(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + if (mapping) { + arm_iommu_detach_device(dev); + devm_kfree(dev, dev->dma_parms); + dev->dma_parms = NULL; + arm_iommu_release_mapping(mapping); + mapping = NULL; + } +} +#endif + /* * * Device file operations @@ -2816,6 +2882,13 @@ static int s5p_jpeg_probe(struct platform_device *pdev) spin_lock_init(&jpeg->slock); jpeg->dev = &pdev->dev; +#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) + ret = jpeg_iommu_init(pdev); + if (ret) { + dev_err(&pdev->dev, "IOMMU Initialization failed\n"); + return ret; + } +#endif /* memory-mapped registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2962,6 +3035,10 @@ static int s5p_jpeg_remove(struct platform_device *pdev) clk_disable_unprepare(jpeg->clocks[i]); } +#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) + jpeg_iommu_deinit(pdev); +#endif + return 0; } Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] ARM: dts: exynos: Add HDMI CEC device to Exynos5 SoC family
Hi Krzysztof, On 2017-05-31 21:55, Krzysztof Kozlowski wrote: On Wed, May 31, 2017 at 01:00:17PM +0200, Marek Szyprowski wrote: Exynos5250 and Exynos542x SoCs have the same CEC hardware module as Exynos4 SoC series, so enable support for it using the same compatible string. Tested on Odroid XU3 (Exynos5422) and Google Snow (Exynos5250) boards. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 7 +++ arch/arm/boot/dts/exynos5250-snow-common.dtsi | 4 arch/arm/boot/dts/exynos5250.dtsi | 13 + arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 7 +++ arch/arm/boot/dts/exynos5420.dtsi | 13 + arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 4 6 files changed, 48 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index 2f6ab32b5954..1fd122db18e6 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -589,6 +589,13 @@ samsung,pin-pud = ; samsung,pin-drv = ; }; + + hdmi_cec: hdmi-cec { + samsung,pins = "gpx3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; }; &pinctrl_1 { diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi index 8f3a80430748..e1d293dbbe5d 100644 --- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi +++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi @@ -272,6 +272,10 @@ vdd_pll-supply = <&ldo8_reg>; }; +&hdmicec { + status = "okay"; +}; + &i2c_0 { status = "okay"; samsung,i2c-sda-delay = <100>; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 79c9c885613a..fbdc1d53a2ce 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -689,6 +689,19 @@ samsung,syscon-phandle = <&pmu_system_controller>; }; + hdmicec: cec@101B { + compatible = "samsung,s5p-cec"; + reg = <0x101B 0x200>; + interrupts = ; + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + samsung,syscon-phandle = <&pmu_system_controller>; + hdmi-phandle = <&hdmi>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + status = "disabled"; + }; What about Exynos5410? Is it applicable there as well? If yes, then this could be added to exynos5.dtsi... although then clocks and pinctrl should remain in SoC-specific DTSI. We're following such pattern in many places but I am not sure if this more readable. Exynos5410 has the same HW module, but as for now, it doesn't have support for HDMI due to missing a few pieces (mainly clocks definitions). I'm not sure if it makes sense to add only HDMICEC without HDMI itself. Maybe later, when multimedia support is added to Exynos5410, this can be integrated to exynos5.dtsi. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH RFC] v4l2-core: Use kvmalloc() for potentially big allocations
Hi Tomasz, On 2017-05-31 08:58, Tomasz Figa wrote: There are multiple places where arrays or otherwise variable sized buffer are allocated through V4L2 core code, including things like controls, memory pages, staging buffers for ioctls and so on. Such allocations can potentially require an order > 0 allocation from the page allocator, which is not guaranteed to be fulfilled and is likely to fail on a system with severe memory fragmentation (e.g. a system with very long uptime). Since the memory being allocated is intended to be used by the CPU exclusively, we can consider using vmalloc() as a fallback and this is exactly what the recently merged kvmalloc() helpers do. A kmalloc() call is still attempted, even for order > 0 allocations, but it is done with __GFP_NORETRY and __GFP_NOWARN, with expectation of failing if requested memory is not available instantly. Only then the vmalloc() fallback is used. This should give us fast and more reliable allocations even on systems with higher memory pressure and/or more fragmentation, while still retaining the same performance level on systems not suffering from such conditions. While at it, replace explicit array size calculations on changed allocations with kvmalloc_array(). Signed-off-by: Tomasz Figa --- drivers/media/v4l2-core/v4l2-async.c | 4 ++-- drivers/media/v4l2-core/v4l2-ctrls.c | 25 + drivers/media/v4l2-core/v4l2-event.c | 8 +--- drivers/media/v4l2-core/v4l2-ioctl.c | 6 +++--- drivers/media/v4l2-core/v4l2-subdev.c | 7 --- drivers/media/v4l2-core/videobuf2-dma-sg.c | 8 For vb2: Acked-by: Marek Szyprowski There are also a few vmalloc calls in old videobuf (v1) framework, which might be converted to kvmalloc if you have a few spare minutes to take a look. 6 files changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 96cc733f35ef..2d2d9f1f8831 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -204,7 +204,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) if (!notifier->v4l2_dev) return; - dev = kmalloc_array(n_subdev, sizeof(*dev), GFP_KERNEL); + dev = kvmalloc_array(n_subdev, sizeof(*dev), GFP_KERNEL); if (!dev) { dev_err(notifier->v4l2_dev->dev, "Failed to allocate device cache!\n"); @@ -260,7 +260,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) } put_device(d); } - kfree(dev); + kvfree(dev); notifier->v4l2_dev = NULL; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ec42872d11cf..88025527c67e 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1745,8 +1745,9 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, INIT_LIST_HEAD(&hdl->ctrls); INIT_LIST_HEAD(&hdl->ctrl_refs); hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; - hdl->buckets = kcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]), - GFP_KERNEL); + hdl->buckets = kvmalloc_array(hdl->nr_of_buckets, + sizeof(hdl->buckets[0]), + GFP_KERNEL | __GFP_ZERO); hdl->error = hdl->buckets ? 0 : -ENOMEM; return hdl->error; } @@ -1773,9 +1774,9 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) list_del(&ctrl->node); list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node) list_del(&sev->node); - kfree(ctrl); + kvfree(ctrl); } - kfree(hdl->buckets); + kvfree(hdl->buckets); hdl->buckets = NULL; hdl->cached = NULL; hdl->error = 0; @@ -2022,7 +2023,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, is_array) sz_extra += 2 * tot_ctrl_size; - ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); + ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); if (ctrl == NULL) { handler_set_err(hdl, -ENOMEM); return NULL; @@ -2071,7 +2072,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, } if (handler_new_ref(hdl, ctrl)) { - kfree(ctrl); + kvfree(ctrl); return NULL; } mutex_lock(hdl->lock); @@ -2824,8 +2825,8 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs return class_check(hdl, cs->which
Re: [PATCH] ARM: dts: exynos: Add HDMI CEC device to Exynos5 SoC family
Hi Hans, On 2017-05-31 13:17, Hans Verkuil wrote: On 05/31/17 13:00, Marek Szyprowski wrote: Exynos5250 and Exynos542x SoCs have the same CEC hardware module as Exynos4 SoC series, so enable support for it using the same compatible string. Tested on Odroid XU3 (Exynos5422) and Google Snow (Exynos5250) boards. Thanks! Do you know if the CEC block is always on for these devices or only if there is a hotplug signal? That was a problem with the exynos4 odroid. Odroid XU3 has exactly same wiring between SoC & HDMI connector (via IP4791CZ12 chip) as Odroid U3, so I expect the same issues. I don't have schematic for Google Snow board, so I have no idea how it works there. I have made a patch (not posted yet) to signal this in the device tree and added a CEC capability to signal this to the user. This capability will be added to 4.13 (see my patch 'cec: add CEC_CAP_NEEDS_HPD' from May 25th) since the DisplayPort CEC tunneling feature needs it as well. It's easy to test: don't connect an HDMI cable and run: cec-ctl --playback cec-ctl -t0 --image-view-on If this returns with a NACK error, then it is OK. If you get a kernel message that the transmit timed out, then you need this capability since CEC is disabled without HPD. I've checked those commands, but on all tested boards (Odroid U3+, Odroid XU3 and Google Snow) I get the following message: Transmit from Unregistered to TV (255 to 0): CEC_MSG_IMAGE_VIEW_ON (0x04) Sequence: 19 Tx Timestamp: 175.935s Tx, Error (1), Max Retries I have never got a timeout message from the kernel. Do I need to enable some kind of CEC debugs? > [...] Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [ANN] HDMI CEC Status Update
Hi Andrzej and Hans, On 2017-05-31 10:12, Andrzej Hajda wrote: On 30.05.2017 08:53, Hans Verkuil wrote: For those who are interested in HDMI CEC support I made a little status document that I intend to keep up to date: https://hverkuil.home.xs4all.nl/cec-status.txt My goal is to get CEC supported for any mainlined HDMI driver where the hardware supports CEC. If anyone is working on a CEC driver that I don't know already about, just drop me an email so I can update the status. Sii8620 HDMI->MHL bridge is on my TODO list. Regarding Exynos5 it is apparently the same IP as in Exynos4. I've just posted a patch enabling CEC module on Exynos5250 (Google Snow) and Exynos5422 (Odroid XU3). Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] ARM: dts: exynos: Add HDMI CEC device to Exynos5 SoC family
Exynos5250 and Exynos542x SoCs have the same CEC hardware module as Exynos4 SoC series, so enable support for it using the same compatible string. Tested on Odroid XU3 (Exynos5422) and Google Snow (Exynos5250) boards. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 7 +++ arch/arm/boot/dts/exynos5250-snow-common.dtsi | 4 arch/arm/boot/dts/exynos5250.dtsi | 13 + arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 7 +++ arch/arm/boot/dts/exynos5420.dtsi | 13 + arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 4 6 files changed, 48 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index 2f6ab32b5954..1fd122db18e6 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -589,6 +589,13 @@ samsung,pin-pud = ; samsung,pin-drv = ; }; + + hdmi_cec: hdmi-cec { + samsung,pins = "gpx3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; }; &pinctrl_1 { diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi index 8f3a80430748..e1d293dbbe5d 100644 --- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi +++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi @@ -272,6 +272,10 @@ vdd_pll-supply = <&ldo8_reg>; }; +&hdmicec { + status = "okay"; +}; + &i2c_0 { status = "okay"; samsung,i2c-sda-delay = <100>; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 79c9c885613a..fbdc1d53a2ce 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -689,6 +689,19 @@ samsung,syscon-phandle = <&pmu_system_controller>; }; + hdmicec: cec@101B { + compatible = "samsung,s5p-cec"; + reg = <0x101B 0x200>; + interrupts = ; + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + samsung,syscon-phandle = <&pmu_system_controller>; + hdmi-phandle = <&hdmi>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + status = "disabled"; + }; + mixer@1445 { compatible = "samsung,exynos5250-mixer"; reg = <0x1445 0x1>; diff --git a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi index 3924b4fafe72..65aa0e300c23 100644 --- a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi @@ -67,6 +67,13 @@ samsung,pin-pud = ; samsung,pin-drv = ; }; + + hdmi_cec: hdmi-cec { + samsung,pins = "gpx3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; }; &pinctrl_1 { diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 0db0bcf8da36..acd77b10b3df 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -624,6 +624,19 @@ reg = <0x145D 0x20>; }; + hdmicec: cec@101B { + compatible = "samsung,s5p-cec"; + reg = <0x101B 0x200>; + interrupts = ; + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + samsung,syscon-phandle = <&pmu_system_controller>; + hdmi-phandle = <&hdmi>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + status = "disabled"; + }; + mixer: mixer@1445 { compatible = "samsung,exynos5420-mixer"; reg = <0x1445 0x1>; diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi index 05b9afdd6757..01d6ac99e974 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi @@ -265,6 +265,10 @@ vdd-supply = <&ldo6_reg>; }; +&hdmicec { + status = "okay"; +}; + &hsi2c_4 { status = "okay"; -- 1.9.1
Re: [RFC 0/4] Exynos DRM: add Picture Processor extension
Hi Daniel, On 2017-05-10 09:55, Daniel Vetter wrote: On Wed, May 10, 2017 at 03:27:02PM +0900, Inki Dae wrote: Hi Tomasz, 2017년 05월 10일 14:38에 Tomasz Figa 이(가) 쓴 글: Hi Everyone, On Wed, May 10, 2017 at 9:24 AM, Inki Dae wrote: 2017년 04월 26일 07:21에 Sakari Ailus 이(가) 쓴 글: Hi Marek, On Thu, Apr 20, 2017 at 01:23:09PM +0200, Marek Szyprowski wrote: Hi Laurent, On 2017-04-20 12:25, Laurent Pinchart wrote: Hi Marek, (CC'ing Sakari Ailus) Thank you for the patches. On Thursday 20 Apr 2017 11:13:36 Marek Szyprowski wrote: Dear all, This is an updated proposal for extending EXYNOS DRM API with generic support for hardware modules, which can be used for processing image data >from the one memory buffer to another. Typical memory-to-memory operations are: rotation, scaling, colour space conversion or mix of them. This is a follow-up of my previous proposal "[RFC 0/2] New feature: Framebuffer processors", which has been rejected as "not really needed in the DRM core": http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg146286.html In this proposal I moved all the code to Exynos DRM driver, so now this will be specific only to Exynos DRM. I've also changed the name from framebuffer processor (fbproc) to picture processor (pp) to avoid confusion with fbdev API. Here is a bit more information what picture processors are: Embedded SoCs are known to have a number of hardware blocks, which perform such operations. They can be used in paralel to the main GPU module to offload CPU from processing grapics or video data. One of example use of such modules is implementing video overlay, which usually requires color space conversion from NV12 (or similar) to RGB32 color space and scaling to target window size. The proposed API is heavily inspired by atomic KMS approach - it is also based on DRM objects and their properties. A new DRM object is introduced: picture processor (called pp for convenience). Such objects have a set of standard DRM properties, which describes the operation to be performed by respective hardware module. In typical case those properties are a source fb id and rectangle (x, y, width, height) and destination fb id and rectangle. Optionally a rotation property can be also specified if supported by the given hardware. To perform an operation on image data, userspace provides a set of properties and their values for given fbproc object in a similar way as object and properties are provided for performing atomic page flip / mode setting. The proposed API consists of the 3 new ioctls: - DRM_IOCTL_EXYNOS_PP_GET_RESOURCES: to enumerate all available picture processors, - DRM_IOCTL_EXYNOS_PP_GET: to query capabilities of given picture processor, - DRM_IOCTL_EXYNOS_PP_COMMIT: to perform operation described by given property set. The proposed API is extensible. Drivers can attach their own, custom properties to add support for more advanced picture processing (for example blending). This proposal aims to replace Exynos DRM IPP (Image Post Processing) subsystem. IPP API is over-engineered in general, but not really extensible on the other side. It is also buggy, with significant design flaws - the biggest issue is the fact that the API covers memory-2-memory picture operations together with CRTC writeback and duplicating features, which belongs to video plane. Comparing with IPP subsystem, the PP framework is smaller (1807 vs 778 lines) and allows driver simplification (Exynos rotator driver smaller by over 200 lines). This seems to be the kind of hardware that is typically supported by V4L2. Stupid question, why DRM ? Let me elaborate a bit on the reasons for implementing it in Exynos DRM: 1. we want to replace existing Exynos IPP subsystem: - it is used only in some internal/vendor trees, not in open-source - we want it to have sane and potentially extensible userspace API - but we don't want to loose its functionality 2. we want to have simple API for performing single image processing operation: - typically it will be used by compositing window manager, this means that some parameters of the processing might change on each vblank (like destination rectangle for example). This api allows such change on each operation without any additional cost. V4L2 requires to reinitialize queues with new configuration on such change, what means that a bunch of ioctls has to be called. What do you mean by re-initialising the queue? Format, buffers or something else? If you need a larger buffer than what you have already allocated, you'll need to re-allocate, V4L2 or not. We also do lack a way to destroy individual buffers in V4L2. It'd be up to implementing that and some work in videobuf2. Another thing is that V4L2 is very stream oriented. For most devices that's fine as a lot of the parameters are not changeable during streaming, especially if the pipeline is handled by multiple drivers. Th
Re: [RFC 0/4] Exynos DRM: add Picture Processor extension
Hi Tobias and Nicolas, On 2017-04-26 17:16, Tobias Jakobi wrote: Nicolas Dufresne wrote: Le mercredi 26 avril 2017 à 01:21 +0300, Sakari Ailus a écrit : Hi Marek, On Thu, Apr 20, 2017 at 01:23:09PM +0200, Marek Szyprowski wrote: Hi Laurent, On 2017-04-20 12:25, Laurent Pinchart wrote: Hi Marek, (CC'ing Sakari Ailus) Thank you for the patches. On Thursday 20 Apr 2017 11:13:36 Marek Szyprowski wrote: Dear all, This is an updated proposal for extending EXYNOS DRM API with generic support for hardware modules, which can be used for processing image data from the one memory buffer to another. Typical memory-to-memory operations are: rotation, scaling, colour space conversion or mix of them. This is a follow-up of my previous proposal "[RFC 0/2] New feature: Framebuffer processors", which has been rejected as "not really needed in the DRM core": http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg146286.html In this proposal I moved all the code to Exynos DRM driver, so now this will be specific only to Exynos DRM. I've also changed the name from framebuffer processor (fbproc) to picture processor (pp) to avoid confusion with fbdev API. Here is a bit more information what picture processors are: Embedded SoCs are known to have a number of hardware blocks, which perform such operations. They can be used in paralel to the main GPU module to offload CPU from processing grapics or video data. One of example use of such modules is implementing video overlay, which usually requires color space conversion from NV12 (or similar) to RGB32 color space and scaling to target window size. The proposed API is heavily inspired by atomic KMS approach - it is also based on DRM objects and their properties. A new DRM object is introduced: picture processor (called pp for convenience). Such objects have a set of standard DRM properties, which describes the operation to be performed by respective hardware module. In typical case those properties are a source fb id and rectangle (x, y, width, height) and destination fb id and rectangle. Optionally a rotation property can be also specified if supported by the given hardware. To perform an operation on image data, userspace provides a set of properties and their values for given fbproc object in a similar way as object and properties are provided for performing atomic page flip / mode setting. The proposed API consists of the 3 new ioctls: - DRM_IOCTL_EXYNOS_PP_GET_RESOURCES: to enumerate all available picture processors, - DRM_IOCTL_EXYNOS_PP_GET: to query capabilities of given picture processor, - DRM_IOCTL_EXYNOS_PP_COMMIT: to perform operation described by given property set. The proposed API is extensible. Drivers can attach their own, custom properties to add support for more advanced picture processing (for example blending). This proposal aims to replace Exynos DRM IPP (Image Post Processing) subsystem. IPP API is over-engineered in general, but not really extensible on the other side. It is also buggy, with significant design flaws - the biggest issue is the fact that the API covers memory-2-memory picture operations together with CRTC writeback and duplicating features, which belongs to video plane. Comparing with IPP subsystem, the PP framework is smaller (1807 vs 778 lines) and allows driver simplification (Exynos rotator driver smaller by over 200 lines). Just a side note, we have written code in GStreamer using the Exnynos 4 FIMC IPP driver. I don't know how many, if any, deployment still exist (Exynos 4 is relatively old now), but there exist userspace for the FIMC driver. We use this for color transformation (from tiled to linear) and scaling. The FIMC driver is in fact quite stable in upstream kernel today. The GScaler V4L2 M2M driver on Exynos 5 is largely based on it and has received some maintenance to properly work in GStreamer. unlike this DRM API, you can reuse the same userspace code across multiple platforms (which we do already). We have also integrated this driver in Chromium in the past (not upstream though). I am well aware that the blitter driver has not got much attention though. But again, V4L2 offers a generic interface to userspace application. Fixing this driver could enable some work like this one: https://bugzilla.gnome.org/show_bug.cgi?id=772766 This work in progress feature is a generic hardware accelerated video mixer. It has been tested with IMX.6 v4l2 m2m blitter driver (which I believe is in staging right now). Again, unlike the exynos/drm, this code could be reused between platforms. In general, the problem with the DRM approach is that it only targets displays. We often need to use these IP block for stream pre/post processing outside a "playback" use case. just a short note that this is not true. You can use all this functionality e.g. through render nodes, without needing to have a display attached to your system. Yes. As an alternative I al
Re: [RFC 0/4] Exynos DRM: add Picture Processor extension
Hi Sakari, On 2017-04-26 00:21, Sakari Ailus wrote: Hi Marek, On Thu, Apr 20, 2017 at 01:23:09PM +0200, Marek Szyprowski wrote: Hi Laurent, On 2017-04-20 12:25, Laurent Pinchart wrote: Hi Marek, (CC'ing Sakari Ailus) Thank you for the patches. On Thursday 20 Apr 2017 11:13:36 Marek Szyprowski wrote: Dear all, This is an updated proposal for extending EXYNOS DRM API with generic support for hardware modules, which can be used for processing image data >from the one memory buffer to another. Typical memory-to-memory operations are: rotation, scaling, colour space conversion or mix of them. This is a follow-up of my previous proposal "[RFC 0/2] New feature: Framebuffer processors", which has been rejected as "not really needed in the DRM core": http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg146286.html In this proposal I moved all the code to Exynos DRM driver, so now this will be specific only to Exynos DRM. I've also changed the name from framebuffer processor (fbproc) to picture processor (pp) to avoid confusion with fbdev API. Here is a bit more information what picture processors are: Embedded SoCs are known to have a number of hardware blocks, which perform such operations. They can be used in paralel to the main GPU module to offload CPU from processing grapics or video data. One of example use of such modules is implementing video overlay, which usually requires color space conversion from NV12 (or similar) to RGB32 color space and scaling to target window size. The proposed API is heavily inspired by atomic KMS approach - it is also based on DRM objects and their properties. A new DRM object is introduced: picture processor (called pp for convenience). Such objects have a set of standard DRM properties, which describes the operation to be performed by respective hardware module. In typical case those properties are a source fb id and rectangle (x, y, width, height) and destination fb id and rectangle. Optionally a rotation property can be also specified if supported by the given hardware. To perform an operation on image data, userspace provides a set of properties and their values for given fbproc object in a similar way as object and properties are provided for performing atomic page flip / mode setting. The proposed API consists of the 3 new ioctls: - DRM_IOCTL_EXYNOS_PP_GET_RESOURCES: to enumerate all available picture processors, - DRM_IOCTL_EXYNOS_PP_GET: to query capabilities of given picture processor, - DRM_IOCTL_EXYNOS_PP_COMMIT: to perform operation described by given property set. The proposed API is extensible. Drivers can attach their own, custom properties to add support for more advanced picture processing (for example blending). This proposal aims to replace Exynos DRM IPP (Image Post Processing) subsystem. IPP API is over-engineered in general, but not really extensible on the other side. It is also buggy, with significant design flaws - the biggest issue is the fact that the API covers memory-2-memory picture operations together with CRTC writeback and duplicating features, which belongs to video plane. Comparing with IPP subsystem, the PP framework is smaller (1807 vs 778 lines) and allows driver simplification (Exynos rotator driver smaller by over 200 lines). This seems to be the kind of hardware that is typically supported by V4L2. Stupid question, why DRM ? Let me elaborate a bit on the reasons for implementing it in Exynos DRM: 1. we want to replace existing Exynos IPP subsystem: - it is used only in some internal/vendor trees, not in open-source - we want it to have sane and potentially extensible userspace API - but we don't want to loose its functionality 2. we want to have simple API for performing single image processing operation: - typically it will be used by compositing window manager, this means that some parameters of the processing might change on each vblank (like destination rectangle for example). This api allows such change on each operation without any additional cost. V4L2 requires to reinitialize queues with new configuration on such change, what means that a bunch of ioctls has to be called. What do you mean by re-initialising the queue? Format, buffers or something else? In case of compositor use case, the parameter that is being changed most frequently is source and/or destination rectangle position and/or size. If you need a larger buffer than what you have already allocated, you'll need to re-allocate, V4L2 or not. We also do lack a way to destroy individual buffers in V4L2. It'd be up to implementing that and some work in videobuf2. Well if we would use V4l2, buffers will always come as dmabuf objects. There is a hard limit of the number of buffers that can be imported to v4l2/vb2 queue to get buffer ids. This also limits easy processing of the buffers in the compositor, because you would need to reinitialize the v
Re: [Intel-gfx] [PATCH v2] dma-buf: Rename dma-ops to prevent conflict with kunmap_atomic macro
Hi All, On 2017-04-20 09:51, Daniel Vetter wrote: On Wed, Apr 19, 2017 at 01:36:10PM -0600, Logan Gunthorpe wrote: Seeing the kunmap_atomic dma_buf_ops share the same name with a macro in highmem.h, the former can be aliased if any dma-buf user includes that header. I'm personally trying to include highmem.h inside scatterlist.h and this breaks the dma-buf code proper. Christoph Hellwig suggested [1] renaming it and pushing this patch ASAP. To maintain consistency I've renamed all four of kmap* and kunmap* to be map* and unmap*. (Even though only kmap_atomic presently conflicts.) [1] https://www.spinics.net/lists/target-devel/msg15070.html Signed-off-by: Logan Gunthorpe Reviewed-by: Sinclair Yeh Acked-by: Daniel Vetter Probably simplest if we pull this in through the drm-misc tree for 4.12. Can we have an ack for the v4l side for that pls? For the V4L2/videobuf2: Acked-by: Marek Szyprowski Thanks, Daniel --- Changes since v1: - Added the missing tegra driver (noticed by kbuild robot) - Rebased off of drm-intel-next to get the i915 selftest that is new - Fixed nits Sinclair pointed out. drivers/dma-buf/dma-buf.c | 16 drivers/gpu/drm/armada/armada_gem.c| 8 drivers/gpu/drm/drm_prime.c| 8 drivers/gpu/drm/i915/i915_gem_dmabuf.c | 8 drivers/gpu/drm/i915/selftests/mock_dmabuf.c | 8 drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 8 drivers/gpu/drm/tegra/gem.c| 8 drivers/gpu/drm/udl/udl_dmabuf.c | 8 drivers/gpu/drm/vmwgfx/vmwgfx_prime.c | 8 drivers/media/v4l2-core/videobuf2-dma-contig.c | 4 ++-- drivers/media/v4l2-core/videobuf2-dma-sg.c | 4 ++-- drivers/media/v4l2-core/videobuf2-vmalloc.c| 4 ++-- drivers/staging/android/ion/ion.c | 8 include/linux/dma-buf.h| 22 +++--- 14 files changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index f72aaac..512bdbc 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -405,8 +405,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) || !exp_info->ops->map_dma_buf || !exp_info->ops->unmap_dma_buf || !exp_info->ops->release - || !exp_info->ops->kmap_atomic - || !exp_info->ops->kmap + || !exp_info->ops->map_atomic + || !exp_info->ops->map || !exp_info->ops->mmap)) { return ERR_PTR(-EINVAL); } @@ -872,7 +872,7 @@ void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num) { WARN_ON(!dmabuf); - return dmabuf->ops->kmap_atomic(dmabuf, page_num); + return dmabuf->ops->map_atomic(dmabuf, page_num); } EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic); @@ -889,8 +889,8 @@ void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num, { WARN_ON(!dmabuf); - if (dmabuf->ops->kunmap_atomic) - dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr); + if (dmabuf->ops->unmap_atomic) + dmabuf->ops->unmap_atomic(dmabuf, page_num, vaddr); } EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic); @@ -907,7 +907,7 @@ void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num) { WARN_ON(!dmabuf); - return dmabuf->ops->kmap(dmabuf, page_num); + return dmabuf->ops->map(dmabuf, page_num); } EXPORT_SYMBOL_GPL(dma_buf_kmap); @@ -924,8 +924,8 @@ void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num, { WARN_ON(!dmabuf); - if (dmabuf->ops->kunmap) - dmabuf->ops->kunmap(dmabuf, page_num, vaddr); + if (dmabuf->ops->unmap) + dmabuf->ops->unmap(dmabuf, page_num, vaddr); } EXPORT_SYMBOL_GPL(dma_buf_kunmap); diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 1597458..d6c2a5d 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -529,10 +529,10 @@ static const struct dma_buf_ops armada_gem_prime_dmabuf_ops = { .map_dma_buf= armada_gem_prime_map_dma_buf, .unmap_dma_buf = armada_gem_prime_unmap_dma_buf, .release= drm_gem_dmabuf_release, - .kmap_atomic= armada_gem_dmabuf_no_kmap, - .kunmap_atomic = armada_gem_dmabuf_no_kunmap, - .kmap = armada_gem_dmabuf_no_kmap, - .kunmap = armada_gem_dmabuf_no_kunmap, + .map_atomic = armada_gem_dmabuf_no_kmap, + .unmap_atomic = armad
Re: [PATCH] arm: dma: fix sharing of coherent DMA memory without struct page
Hi Shuah, On 2017-04-11 00:50, Shuah Khan wrote: On 04/06/2017 06:01 AM, Marek Szyprowski wrote: On 2017-04-05 18:02, Shuah Khan wrote: When coherent DMA memory without struct page is shared, importer fails to find the page and runs into kernel page fault when it tries to dmabuf_ops_attach/map_sg/map_page the invalid page found in the sg_table. Please see www.spinics.net/lists/stable/msg164204.html for more information on this problem. This solution allows coherent DMA memory without struct page to be shared by providing a way for the exporter to tag the DMA buffer as a special buffer without struct page association and passing the information in sg_table to the importer. This information is used in attach/map_sg to avoid cleaning D-cache and mapping. The details of the change are: Framework: - Add a new dma_attrs field to struct scatterlist. - Add a new DMA_ATTR_DEV_COHERENT_NOPAGE attribute to clearly identify Coherent memory without struct page. - Add a new dma_check_dev_coherent() interface to check if memory is the device coherent area. There is no way to tell where the memory returned by dma_alloc_attrs() came from. Exporter logic: - Add logic to vb2_dc_alloc() to call dma_check_dev_coherent() and set DMA_ATTR_DEV_COHERENT_NOPAGE based the results of the check. This is done in the exporter context. - Add logic to arm_dma_get_sgtable() to identify memory without struct page using DMA_ATTR_DEV_COHERENT_NOPAGE attribute. If this attr is set, arm_dma_get_sgtable() will set page as the cpu_addr and update dma_address and dma_attrs fields in struct scatterlist for this sgl. This is done in exporter context when buffer is exported. With this Note: This change is made on top of Russell King's patch that added !pfn_valid(pfn) check to arm_dma_get_sgtable() to error out on invalid pages. Coherent memory without struct page will trigger this error. Importer logic: - Add logic to vb2_dc_dmabuf_ops_attach() to identify memory without struct page using DMA_ATTR_DEV_COHERENT_NOPAGE attribute when it copies the sg_table from the exporter. It will copy dma_attrs and dma_address fields. With this logic, dmabuf_ops_attach will no longer trip on an invalid page. - Add logic to arm_dma_map_sg() to avoid mapping the page when sg_table has DMA_ATTR_DEV_COHERENT_NOPAGE buffer. - Add logic to arm_dma_unmap_sg() to do nothing for sg entries with DMA_ATTR_DEV_COHERENT_NOPAGE attribute. Without this change the following use-case that runs into kernel pagefault when importer tries to attach the exported buffer. With this change it works: (what a relief after watching pagefaults for weeks!!) gst-launch-1.0 filesrc location=~/GH3_MOV_HD.mp4 ! qtdemux ! h264parse ! v4l2video4dec capture-io-mode=dmabuf ! v4l2video7convert output-io-mode=dmabuf-import ! kmssink force-modesetting=true I am sending RFC patch to get feedback on the approach and see if I missed anything. Frankly, once You decided to hack around dma-buf and issues with coherent, carved out memory, it might be a bit better to find the ultimate solution instead of the another hack. Please note that it will still not allow to share a buffer allocated from carved-out memory and a device, which is behind IOMMU. With your patch s5p-mfc patch series does address the problem for this use-case for 4.12 onwards. However I am still concerned about prior release and this pagefault is bad. Right. It should simply fail with error code instead of pagefault. Invalid page test partially solves the problem. Would it helpful to at least prevent the pagfault with a definitive test. Please see my response to Russell. Let me know your thoughts on that. I thought a bit about this and the current shape of dma-buf code. IMHO the proper way of solving all those issues would be to replace dma-buf internal representation of the memory from struct scatter_list to pfn array. This would really solve the problem of buffers which cannot be properly represented by scatter lists/struct pages and would even allow sharing buffers between all kinds of devices. Scatter-lists are also quite over-engineered structures to represent a single buffer (pfn array is a bit more compact representation). Also there is a lots of buggy code which use scatter-list in a bit creative way (like assuming that each page maps to a single scatter list entry for example). The only missing piece, required for such change would be extending DMA-mapping with dma_map_pfn() interface. I agree with you on scatterlists being clumsy. Changing over to pfn array could simplify things. I am exploring a slightly different option that might not require too many changes. I will respond with concrete ideas later on this week. It looks that a similar issue is being worked on, see the following thread: https://lkml.org/lkml/2017/4/13/710 This would be however quite large task, especially taking into account all current users of DMA-buf fram
Re: [PATCH] arm: dma: fix sharing of coherent DMA memory without struct page
Hi Shuah, On 2017-04-05 18:02, Shuah Khan wrote: When coherent DMA memory without struct page is shared, importer fails to find the page and runs into kernel page fault when it tries to dmabuf_ops_attach/map_sg/map_page the invalid page found in the sg_table. Please see www.spinics.net/lists/stable/msg164204.html for more information on this problem. This solution allows coherent DMA memory without struct page to be shared by providing a way for the exporter to tag the DMA buffer as a special buffer without struct page association and passing the information in sg_table to the importer. This information is used in attach/map_sg to avoid cleaning D-cache and mapping. The details of the change are: Framework: - Add a new dma_attrs field to struct scatterlist. - Add a new DMA_ATTR_DEV_COHERENT_NOPAGE attribute to clearly identify Coherent memory without struct page. - Add a new dma_check_dev_coherent() interface to check if memory is the device coherent area. There is no way to tell where the memory returned by dma_alloc_attrs() came from. Exporter logic: - Add logic to vb2_dc_alloc() to call dma_check_dev_coherent() and set DMA_ATTR_DEV_COHERENT_NOPAGE based the results of the check. This is done in the exporter context. - Add logic to arm_dma_get_sgtable() to identify memory without struct page using DMA_ATTR_DEV_COHERENT_NOPAGE attribute. If this attr is set, arm_dma_get_sgtable() will set page as the cpu_addr and update dma_address and dma_attrs fields in struct scatterlist for this sgl. This is done in exporter context when buffer is exported. With this Note: This change is made on top of Russell King's patch that added !pfn_valid(pfn) check to arm_dma_get_sgtable() to error out on invalid pages. Coherent memory without struct page will trigger this error. Importer logic: - Add logic to vb2_dc_dmabuf_ops_attach() to identify memory without struct page using DMA_ATTR_DEV_COHERENT_NOPAGE attribute when it copies the sg_table from the exporter. It will copy dma_attrs and dma_address fields. With this logic, dmabuf_ops_attach will no longer trip on an invalid page. - Add logic to arm_dma_map_sg() to avoid mapping the page when sg_table has DMA_ATTR_DEV_COHERENT_NOPAGE buffer. - Add logic to arm_dma_unmap_sg() to do nothing for sg entries with DMA_ATTR_DEV_COHERENT_NOPAGE attribute. Without this change the following use-case that runs into kernel pagefault when importer tries to attach the exported buffer. With this change it works: (what a relief after watching pagefaults for weeks!!) gst-launch-1.0 filesrc location=~/GH3_MOV_HD.mp4 ! qtdemux ! h264parse ! v4l2video4dec capture-io-mode=dmabuf ! v4l2video7convert output-io-mode=dmabuf-import ! kmssink force-modesetting=true I am sending RFC patch to get feedback on the approach and see if I missed anything. Frankly, once You decided to hack around dma-buf and issues with coherent, carved out memory, it might be a bit better to find the ultimate solution instead of the another hack. Please note that it will still not allow to share a buffer allocated from carved-out memory and a device, which is behind IOMMU. I thought a bit about this and the current shape of dma-buf code. IMHO the proper way of solving all those issues would be to replace dma-buf internal representation of the memory from struct scatter_list to pfn array. This would really solve the problem of buffers which cannot be properly represented by scatter lists/struct pages and would even allow sharing buffers between all kinds of devices. Scatter-lists are also quite over-engineered structures to represent a single buffer (pfn array is a bit more compact representation). Also there is a lots of buggy code which use scatter-list in a bit creative way (like assuming that each page maps to a single scatter list entry for example). The only missing piece, required for such change would be extending DMA-mapping with dma_map_pfn() interface. This would be however quite large task, especially taking into account all current users of DMA-buf framework... Signed-off-by: Shuah Khan --- arch/arm/mm/dma-mapping.c | 34 ++ drivers/base/dma-coherent.c| 25 +++ drivers/media/v4l2-core/videobuf2-dma-contig.c | 6 + include/linux/dma-mapping.h| 8 ++ include/linux/scatterlist.h| 1 + 5 files changed, 69 insertions(+), 5 deletions(-) > [...] Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] media: s5p-mfc: Don't allocate codec buffers from pre-allocated region
Further investigation revealed that codec buffers also don't need to be allocated at higher addresses than firmware base for MFC v6+ hardware. Those buffers can be quite large and its size depends on the selected format and framesize. This patch changes the way the codec buffers are allocated - driver will use generic allocator for them instead of the pre-allocated buffer for firmware and contexts. Signed-off-by: Marek Szyprowski --- This patch should solve failure of h264 encoding due to insufficient memory for codec temporary buffers. Please consider it as part of "[PATCH v3 00/16] Exynos MFC v6+ - remove the need for the reserved memory" patchset. --- drivers/media/platform/s5p-mfc/s5p_mfc_opr.c| 28 + drivers/media/platform/s5p-mfc/s5p_mfc_opr.h| 4 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 4 ++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 34a66189d980..7f33cf23947f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -79,6 +79,25 @@ int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, return -ENOMEM; } +int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b) +{ + struct device *mem_dev = dev->mem_dev[mem_ctx]; + + mfc_debug(3, "Allocating generic buf: %zu\n", b->size); + + b->ctx = mem_ctx; + b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); + if (!b->virt) + goto no_mem; + + mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); + return 0; +no_mem: + mfc_err("Allocating generic buffer of size %zu failed\n", b->size); + return -ENOMEM; +} + void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_priv_buf *b) { @@ -97,3 +116,12 @@ void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, b->size = 0; } +void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b) +{ + struct device *mem_dev = dev->mem_dev[b->ctx]; + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); + b->virt = NULL; + b->dma = 0; + b->size = 0; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 108e59382e0c..16d553fcff08 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -319,6 +319,10 @@ int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, struct s5p_mfc_priv_buf *b); void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_priv_buf *b); +int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b); +void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b); #endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 70071a12db16..85880e9106be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -239,7 +239,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) /* Allocate only if memory from bank 1 is necessary */ if (ctx->bank1.size > 0) { - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->bank1); + ret = s5p_mfc_alloc_generic_buf(dev, BANK_L_CTX, &ctx->bank1); if (ret) { mfc_err("Failed to allocate Bank1 memory\n"); return ret; @@ -252,7 +252,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) /* Release buffers allocated for codec */ static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { - s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); + s5p_mfc_release_generic_buf(ctx->dev, &ctx->bank1); } /* Allocate memory for instance data buffer */ -- 1.9.1
Re: [PATCH v2 00/15] Exynos MFC v6+ - remove the need for the reserved memory
Hi Marian, On 2017-03-22 10:33, Marian Mihailescu wrote: Hi, I was testing with the linux-next kernel + the v2 patches HW: odroid xu4 decoding (working): tested with gstreamer encoding: tested with gstreamer && mfc-patched ffmpeg before patches: encoding worked after patches: encoding didn’t work. I moved on from linux-next in the meantime and I cannot give you logs, BUT I’ve seen Hardkernel applied these patches (and all the linux-next MFC patches) on top of their 4.9 tree, and the result is very similar to mine on linux-next: https://github.com/hardkernel/linux/issues/284 Mar 21 13:04:54 odroid kernel: [ 37.165153] s5p_mfc_alloc_priv_buf:78: Allocating private buffer of size 23243744 failed Mar 21 13:04:54 odroid kernel: [ 37.171865] s5p_mfc_alloc_codec_buffers_v6:244: Failed to allocate Bank1 memory Mar 21 13:04:54 odroid kernel: [ 37.179143] vidioc_reqbufs:1174: Failed to allocate encoding buffers A user reported even adding s5p_mfc.mem=64M did not make the encoder work. Any thoughts? s5p_mfc.mem=64M should fix the issue. If not then there is some kind of different issue. We did a bit more tests and in fact encoding h264 requires quite a lot of memory, so the default preallocated size might be not enough. However the codec temporary buffers don't need to be allocated from the preallocated region. In our tests it also worked when codec buffers were allocated in a generic way. Please check if the attached patch (applied on top of v3 patchset) fixes the issue. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland From: Marek Szyprowski Date: Wed, 22 Mar 2017 10:59:26 +0100 Subject: [PATCH] media: s5p-mfc: Don't allocate codec buffers from pre-allocated region Further investigation revealed that codec buffers also don't need to be allocated at higher addresses than firmware base for MFC v6+ hardware. Those buffers can be quite large and its size depends on the selected format and framesize. This patch changes the way the codec buffers are allocated - driver will use generic allocator for them instead of the pre-allocated buffer for firmware and contexts. Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc_opr.c| 28 + drivers/media/platform/s5p-mfc/s5p_mfc_opr.h| 4 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 4 ++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 34a66189d980..7f33cf23947f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -79,6 +79,25 @@ int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, return -ENOMEM; } +int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b) +{ + struct device *mem_dev = dev->mem_dev[mem_ctx]; + + mfc_debug(3, "Allocating generic buf: %zu\n", b->size); + + b->ctx = mem_ctx; + b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); + if (!b->virt) + goto no_mem; + + mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); + return 0; +no_mem: + mfc_err("Allocating generic buffer of size %zu failed\n", b->size); + return -ENOMEM; +} + void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_priv_buf *b) { @@ -97,3 +116,12 @@ void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, b->size = 0; } +void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b) +{ + struct device *mem_dev = dev->mem_dev[b->ctx]; + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); + b->virt = NULL; + b->dma = 0; + b->size = 0; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 108e59382e0c..16d553fcff08 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -319,6 +319,10 @@ int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, struct s5p_mfc_priv_buf *b); void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_priv_buf *b); +int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b); +void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b); #endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 70071a12db16..85880e9106be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -239,7 +239,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) /* Allocate only if memory from
Re: [PATCH v2 00/15] Exynos MFC v6+ - remove the need for the reserved memory
Hi Marian, On 2017-03-22 10:33, Marian Mihailescu wrote: Hi, I was testing with the linux-next kernel + the v2 patches HW: odroid xu4 decoding (working): tested with gstreamer encoding: tested with gstreamer && mfc-patched ffmpeg before patches: encoding worked after patches: encoding didn’t work. I moved on from linux-next in the meantime and I cannot give you logs, BUT I’ve seen Hardkernel applied these patches (and all the linux-next MFC patches) on top of their 4.9 tree, and the result is very similar to mine on linux-next: https://github.com/hardkernel/linux/issues/284 Mar 21 13:04:54 odroid kernel: [ 37.165153] s5p_mfc_alloc_priv_buf:78: Allocating private buffer of size 23243744 failed Mar 21 13:04:54 odroid kernel: [ 37.171865] s5p_mfc_alloc_codec_buffers_v6:244: Failed to allocate Bank1 memory Mar 21 13:04:54 odroid kernel: [ 37.179143] vidioc_reqbufs:1174: Failed to allocate encoding buffers A user reported even adding s5p_mfc.mem=64M did not make the encoder work. Any thoughts? Thanks for the report. Could you provide a bit more information about the encoder configuration (selected format, frame size, etc). 23MiB for the temporary buffer seems to be a bit large value, but I would like to reproduce it here and check what can be done to avoid allocating it from the preallocated buffer. Thanks, M. (resent in plain text format) On 17 Mar. 2017, at 10:36 pm, Andrzej Hajda wrote: Hi Marian, On 15.03.2017 12:36, Marian Mihailescu wrote: Hi, After testing these patches, encoding using MFC fails when requesting buffers for capture (it works for output) with ENOMEM (it complains it cannot allocate memory on bank1). Did anyone else test encoding? I have tested encoding and it works on my test target. Could you provide more details of your setup: - which kernel and patches, - which hw, - which test app. Regards Andrzej Thanks, Marian Either I've been missing something or nothing has been going on. (K. E. Gordon) Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] media: s5p-mfc: Fix unbalanced call to clock management
Clock should be turned off after calling s5p_mfc_init_hw() from the watchdog worker, like it is already done in the s5p_mfc_open() which also calls this function. Signed-off-by: Marek Szyprowski Fixes: af93574678108 ("[media] MFC: Add MFC 5.1 V4L2 driver") CC: sta...@vger.kernel.org # v3.7+ --- This issue was there from the beggining of the driver, but this patch applies cleanly only to v3.7+ kernels. --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 0c7ef6251252..76d4681a1c79 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -211,6 +211,7 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) } s5p_mfc_clock_on(); ret = s5p_mfc_init_hw(dev); + s5p_mfc_clock_off(); if (ret) mfc_err("Failed to reinit FW\n"); } -- 1.9.1
[PATCH v3 03/16] media: s5p-mfc: Replace mem_dev_* entries with an array
Internal MFC driver device structure contains two pointers to devices used for DMA memory allocation: mem_dev_l and mem_dev_r. Replace them with the mem_dev[] array and use defines for accessing particular banks. This will help to simplify code in the next patches. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 31 +--- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 11 - drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 23 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c| 8 +++ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c| 10 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 32 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 15 ++-- 7 files changed, 69 insertions(+), 61 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index af223b0a41a3..c03ed1a737b7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1118,7 +1118,8 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, S5P_MFC_IOMMU_DMA_SIZE); if (ret == 0) - mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; + mfc_dev->mem_dev[BANK1_CTX] = + mfc_dev->mem_dev[BANK2_CTX] = dev; return ret; } @@ -1126,14 +1127,14 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) * Create and initialize virtual devices for accessing * reserved memory regions. */ - mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left", - MFC_BANK1_ALLOC_CTX); - if (!mfc_dev->mem_dev_l) + mfc_dev->mem_dev[BANK1_CTX] = s5p_mfc_alloc_memdev(dev, "left", + BANK1_CTX); + if (!mfc_dev->mem_dev[BANK1_CTX]) return -ENODEV; - mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right", - MFC_BANK2_ALLOC_CTX); - if (!mfc_dev->mem_dev_r) { - device_unregister(mfc_dev->mem_dev_l); + mfc_dev->mem_dev[BANK2_CTX] = s5p_mfc_alloc_memdev(dev, "right", + BANK2_CTX); + if (!mfc_dev->mem_dev[BANK2_CTX]) { + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); return -ENODEV; } @@ -1149,8 +1150,8 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) return; } - device_unregister(mfc_dev->mem_dev_l); - device_unregister(mfc_dev->mem_dev_r); + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); } /* MFC probe function */ @@ -1208,8 +1209,10 @@ static int s5p_mfc_probe(struct platform_device *pdev) goto err_dma; } - vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); - vb2_dma_contig_set_max_seg_size(dev->mem_dev_r, DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK1_CTX], + DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK2_CTX], + DMA_BIT_MASK(32)); mutex_init(&dev->mfc_mutex); init_waitqueue_head(&dev->queue); @@ -1343,8 +1346,8 @@ static int s5p_mfc_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); s5p_mfc_release_firmware(dev); s5p_mfc_unconfigure_dma_memory(dev); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev_l); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev_r); + vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK1_CTX]); + vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK2_CTX]); s5p_mfc_final_pm(dev); return 0; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 2f1387a4c386..27d4c864e06e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -33,8 +33,9 @@ * while mmaping */ #define DST_QUEUE_OFF_BASE (1 << 30) -#define MFC_BANK1_ALLOC_CTX0 -#define MFC_BANK2_ALLOC_CTX1 +#define BANK1_CTX 0 +#define BANK2_CTX 1 +#define BANK_CTX_NUM 2 #define MFC_BANK1_ALIGN_ORDER 13 #define MFC_BA
[PATCH v3 01/16] media: s5p-mfc: Remove unused structures and dead code
Remove unused structures, definitions and functions that are no longer called from the driver code. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy Reviewed-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 21 - drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 13 - drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h | 1 - 3 files changed, 35 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index b99a7d0466a8..4e9f349c1be3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1417,16 +1417,11 @@ static int s5p_mfc_resume(struct device *dev) .priv = &mfc_buf_size_v5, }; -static struct s5p_mfc_buf_align mfc_buf_align_v5 = { - .base = MFC_BASE_ALIGN_ORDER, -}; - static struct s5p_mfc_variant mfc_drvdata_v5 = { .version= MFC_VERSION, .version_bit= MFC_V5_BIT, .port_num = MFC_NUM_PORTS, .buf_size = &buf_size_v5, - .buf_align = &mfc_buf_align_v5, .fw_name[0] = "s5p-mfc.fw", .clk_names = {"mfc", "sclk_mfc"}, .num_clocks = 2, @@ -1447,16 +1442,11 @@ static int s5p_mfc_resume(struct device *dev) .priv = &mfc_buf_size_v6, }; -static struct s5p_mfc_buf_align mfc_buf_align_v6 = { - .base = 0, -}; - static struct s5p_mfc_variant mfc_drvdata_v6 = { .version= MFC_VERSION_V6, .version_bit= MFC_V6_BIT, .port_num = MFC_NUM_PORTS_V6, .buf_size = &buf_size_v6, - .buf_align = &mfc_buf_align_v6, .fw_name[0] = "s5p-mfc-v6.fw", /* * v6-v2 firmware contains bug fixes and interface change @@ -1481,16 +1471,11 @@ static int s5p_mfc_resume(struct device *dev) .priv = &mfc_buf_size_v7, }; -static struct s5p_mfc_buf_align mfc_buf_align_v7 = { - .base = 0, -}; - static struct s5p_mfc_variant mfc_drvdata_v7 = { .version= MFC_VERSION_V7, .version_bit= MFC_V7_BIT, .port_num = MFC_NUM_PORTS_V7, .buf_size = &buf_size_v7, - .buf_align = &mfc_buf_align_v7, .fw_name[0] = "s5p-mfc-v7.fw", .clk_names = {"mfc", "sclk_mfc"}, .num_clocks = 2, @@ -1510,16 +1495,11 @@ static int s5p_mfc_resume(struct device *dev) .priv = &mfc_buf_size_v8, }; -static struct s5p_mfc_buf_align mfc_buf_align_v8 = { - .base = 0, -}; - static struct s5p_mfc_variant mfc_drvdata_v8 = { .version= MFC_VERSION_V8, .version_bit= MFC_V8_BIT, .port_num = MFC_NUM_PORTS_V8, .buf_size = &buf_size_v8, - .buf_align = &mfc_buf_align_v8, .fw_name[0] = "s5p-mfc-v8.fw", .clk_names = {"mfc"}, .num_clocks = 1, @@ -1530,7 +1510,6 @@ static int s5p_mfc_resume(struct device *dev) .version_bit= MFC_V8_BIT, .port_num = MFC_NUM_PORTS_V8, .buf_size = &buf_size_v8, - .buf_align = &mfc_buf_align_v8, .fw_name[0] = "s5p-mfc-v8.fw", .clk_names = {"pclk", "aclk", "aclk_xiu"}, .num_clocks = 3, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index ab23236aa942..3e0e8eaf8bfe 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -44,14 +44,6 @@ #include -static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) -{ - /* Same functionality as the vb2_dma_contig_plane_paddr */ - dma_addr_t *paddr = vb2_dma_contig_memops.cookie(b); - - return *paddr; -} - /* MFC definitions */ #define MFC_MAX_EXTRA_DPB 5 #define MFC_MAX_BUFFERS32 @@ -229,16 +221,11 @@ struct s5p_mfc_buf_size { void *priv; }; -struct s5p_mfc_buf_align { - unsigned int base; -}; - struct s5p_mfc_variant { unsigned int version; unsigned int port_num; u32 version_bit; struct s5p_mfc_buf_size *buf_size; - struct s5p_mfc_buf_align *buf_align; char*fw_name[MFC_FW_MAX_VERSIONS]; const char *clk_names[MFC_MAX_CLOCKS]; int num_clocks; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h index 8e5df041edf7..45c807bf19cc 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h @@ -18,7 +18,6 @@ int s5p_mfc_release_firmware(struct s
[PATCH v3 13/16] media: s5p-mfc: Remove special configuration of IOMMU domain
The main reason for using special configuration of IOMMU domain was the problem with MFC firmware, which failed to operate properly when placed at 0 DMA address. Instead of adding custom code for configuring each variant of IOMMU domain and architecture specific glue code, simply use what arch code provides and if the DMA base address equals zero, skip first 128 KiB to keep required alignment. This patch also make the driver operational on ARM64 architecture, because it no longer depends on ARM specific DMA-mapping and IOMMU glue code functions. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 30 +++ drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 51 +- 2 files changed, 14 insertions(+), 67 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index ea01d0aa8303..f1528054a713 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1179,18 +1179,6 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = &mfc_dev->plat_dev->dev; unsigned long mem_size = SZ_8M; unsigned int bitmap_size; - /* -* When IOMMU is available, we cannot use the default configuration, -* because of MFC firmware requirements: address space limited to -* 256M and non-zero default start address. -* This is still simplified, not optimal configuration, but for now -* IOMMU core doesn't allow to configure device's IOMMUs channel -* separately. -*/ - int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, -S5P_MFC_IOMMU_DMA_SIZE); - if (ret) - return ret; if (mfc_mem_size) mem_size = memparse(mfc_mem_size, NULL); @@ -1198,10 +1186,8 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long); mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!mfc_dev->mem_bitmap) { - exynos_unconfigure_iommu(dev); + if (!mfc_dev->mem_bitmap) return -ENOMEM; - } mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, &mfc_dev->mem_base, GFP_KERNEL); @@ -1209,13 +1195,24 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) kfree(mfc_dev->mem_bitmap); dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", (mem_size / SZ_1M)); - exynos_unconfigure_iommu(dev); return -ENOMEM; } mfc_dev->mem_size = mem_size; mfc_dev->dma_base[BANK1_CTX] = mfc_dev->mem_base; mfc_dev->dma_base[BANK2_CTX] = mfc_dev->mem_base; + /* +* MFC hardware cannot handle 0 as a base address, so mark first 128K +* as used (to keep required base alignment) and adjust base address +*/ + if (mfc_dev->mem_base == (dma_addr_t)0) { + unsigned int offset = 1 << MFC_BASE_ALIGN_ORDER; + + bitmap_set(mfc_dev->mem_bitmap, 0, offset >> PAGE_SHIFT); + mfc_dev->dma_base[BANK1_CTX] += offset; + mfc_dev->dma_base[BANK2_CTX] += offset; + } + /* Firmware allocation cannot fail in this case */ s5p_mfc_alloc_firmware(mfc_dev); @@ -1232,7 +1229,6 @@ static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; - exynos_unconfigure_iommu(dev); dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, mfc_dev->mem_base); kfree(mfc_dev->mem_bitmap); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h index 6962132ae8fa..76667924ee2a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h @@ -11,54 +11,13 @@ #ifndef S5P_MFC_IOMMU_H_ #define S5P_MFC_IOMMU_H_ -#define S5P_MFC_IOMMU_DMA_BASE 0x2000lu -#define S5P_MFC_IOMMU_DMA_SIZE SZ_256M - -#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) - -#include +#if defined(CONFIG_EXYNOS_IOMMU) static inline bool exynos_is_iommu_available(struct device *dev) { return dev->archdata.iommu != NULL; } -static inline void exynos_unconfigure_iommu(struct device *dev) -{ - struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); - - arm_
[PATCH v3 00/16] Exynos MFC v6+ - remove the need for the reserved memory
Dear All, This patchset is a result of my work on enabling full support for MFC device (multimedia codec) on Exynos 5433 on ARM64 architecture. Initially I thought that to let it working on ARM64 architecture with IOMMU, I would need to solve the issue related to the fact that s5p-mfc driver was depending on the first-fit allocation method in the DMA-mapping / IOMMU glue code (ARM64 use different algorithm). It turned out, that there is a much simpler way. During my research I found that some of the requirements for the memory buffers for MFC v6+ devices were blindly copied from the previous hardware (v5) version and simply turned out to be excessive. It turned out that there is no strict requirement for ALL buffers to be allocated on the higher addresses than the firmware base. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. This heavily simplifies memory management in the driver. Such relaxed requirements for the memory buffers can be easily fulfilled by allocating firmware, device and per-context buffers from the probe-time preallocated larger buffer. There is no need to create special reserved memory regions. The only case, when those memory regions are needed is an oldest Exynos series - Exynos4210 or Exyno4412, which both have MFC v5 hardware, and only when IOMMU is disabled. This patchset has been tested on Odroid U3 (Exynos4412 with MFC v5), Google Snow (Exynos5250 with MFC v6), Odroid XU3 (Exynos5422 with MFC v8) and TM2 (Exynos5433 with MFC v8, ARM64) boards. To get it working on TM2/Exynos5433 with IOMMU enabled, the following fixes to Exynos SYSMMU driver are needed: https://www.spinics.net/lists/linux-samsung-soc/msg58832.html https://www.spinics.net/lists/linux-samsung-soc/msg58833.html Patches are based on v4.11-rc3 with "media: s5p-mfc: Fix initialization of internal structures" patch applied: https://patchwork.linuxtv.org/patch/39198/ I've tried to split changes into small pieces to make it easier to review the code. I've also did a bit of cleanup while touching the driver. Best regards Marek Szyprowski Samsung R&D Institute Poland Changelog: v3: - collected tags - added a patch, which renames BANK1/2 to BANK_L/R to match documentation - rebased onto v4.11-rc3 v2: - fixed issues pointed by Javier Martinez Canillas: code compiles now after applying each patch, added missing cleanup - added tags v1: https://www.spinics.net/lists/linux-media/msg56.html - initial version Patch summary: Marek Szyprowski (16): media: s5p-mfc: Remove unused structures and dead code media: s5p-mfc: Use generic of_device_get_match_data helper media: s5p-mfc: Replace mem_dev_* entries with an array media: s5p-mfc: Replace bank1/bank2 entries with an array media: s5p-mfc: Simplify alloc/release private buffer functions media: s5p-mfc: Move setting DMA max segment size to DMA configure function media: s5p-mfc: Put firmware to private buffer structure media: s5p-mfc: Move firmware allocation to DMA configure function media: s5p-mfc: Allocate firmware with internal private buffer alloc function media: s5p-mfc: Reduce firmware buffer size for MFC v6+ variants media: s5p-mfc: Split variant DMA memory configuration into separate functions media: s5p-mfc: Add support for probe-time preallocated block based allocator media: s5p-mfc: Remove special configuration of IOMMU domain media: s5p-mfc: Use preallocated block allocator always for MFC v6+ media: s5p-mfc: Rename BANK1/2 to BANK_L/R to better match documentation ARM: dts: exynos: Remove MFC reserved buffers .../devicetree/bindings/media/s5p-mfc.txt | 2 +- arch/arm/boot/dts/exynos5250-arndale.dts | 1 - arch/arm/boot/dts/exynos5250-smdk5250.dts | 1 - arch/arm/boot/dts/exynos5250-spring.dts| 1 - arch/arm/boot/dts/exynos5420-arndale-octa.dts | 1 - arch/arm/boot/dts/exynos5420-peach-pit.dts | 1 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 1 - arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 1 - arch/arm/boot/dts/exynos5800-peach-pi.dts | 1 - drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 2 +- drivers/media/platform/s5p-mfc/regs-mfc-v7.h | 2 +- drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc.c | 214 + drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c| 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_common.h| 43 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 72 +++ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h | 1 - drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 8 +- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 10 +- drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 51 + drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
[PATCH v3 05/16] media: s5p-mfc: Simplify alloc/release private buffer functions
Change parameters for s5p_mfc_alloc_priv_buf() and s5p_mfc_release_priv_buf() functions. Instead of DMA device pointer and a base, provide common MFC device structure and memory bank context identifier. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 2 ++ drivers/media/platform/s5p-mfc/s5p_mfc_opr.c| 20 +++-- drivers/media/platform/s5p-mfc/s5p_mfc_opr.h| 8 +++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 30 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 15 + 5 files changed, 37 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index da601a2dba2f..9cf860f34c71 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -240,12 +240,14 @@ struct s5p_mfc_variant { * buffer accessed by driver * @dma: DMA address, only valid when kernel DMA API used * @size: size of the buffer + * @ctx: memory context (bank) used for this allocation */ struct s5p_mfc_priv_buf { unsigned long ofs; void*virt; dma_addr_t dma; size_t size; + unsigned intctx; }; /** diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 99f65a92a6be..9294ee124661 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -37,12 +37,16 @@ void s5p_mfc_init_regs(struct s5p_mfc_dev *dev) dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev); } -int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, - struct s5p_mfc_priv_buf *b) +int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b) { + struct device *mem_dev = dev->mem_dev[mem_ctx]; + dma_addr_t base = dev->dma_base[mem_ctx]; + mfc_debug(3, "Allocating priv: %zu\n", b->size); - b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL); + b->ctx = mem_ctx; + b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); if (!b->virt) { mfc_err("Allocating private buffer of size %zu failed\n", @@ -53,7 +57,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, if (b->dma < base) { mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", &b->dma, &base); - dma_free_coherent(dev, b->size, b->virt, b->dma); + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); return -ENOMEM; } @@ -61,11 +65,13 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, return 0; } -void s5p_mfc_release_priv_buf(struct device *dev, - struct s5p_mfc_priv_buf *b) +void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b) { + struct device *mem_dev = dev->mem_dev[b->ctx]; + if (b->virt) { - dma_free_coherent(dev, b->size, b->virt, b->dma); + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); b->virt = NULL; b->dma = 0; b->size = 0; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index b6ac417ab63e..108e59382e0c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -315,10 +315,10 @@ struct s5p_mfc_hw_ops { void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); void s5p_mfc_init_regs(struct s5p_mfc_dev *dev); -int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, - struct s5p_mfc_priv_buf *b); -void s5p_mfc_release_priv_buf(struct device *dev, - struct s5p_mfc_priv_buf *b); +int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b); +void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b); #endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 32ce9ade2edb..20e8a1bdc984 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers
[PATCH v3 07/16] media: s5p-mfc: Put firmware to private buffer structure
Use s5p_mfc_priv_buf structure for keeping the firmware image. This will help handling of firmware buffer allocation in the next patches. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 3 +-- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 36 - 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index 8c4739ca16d6..4c80bb4243be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -47,7 +47,7 @@ static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) struct s5p_mfc_cmd_args h2r_args; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = dev->fw_size; + h2r_args.arg[0] = dev->fw_buf.size; return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 9cf860f34c71..cea17a737ef7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -314,8 +314,7 @@ struct s5p_mfc_dev { int int_type; unsigned int int_err; wait_queue_head_t queue; - size_t fw_size; - void *fw_virt_addr; + struct s5p_mfc_priv_buf fw_buf; dma_addr_t dma_base[BANK_CTX_NUM]; unsigned long hw_lock; struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index c9bff3d0655f..50d698968049 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -29,21 +29,22 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) void *bank2_virt; dma_addr_t bank2_dma_addr; unsigned int align_size = 1 << MFC_BASE_ALIGN_ORDER; + struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf; - dev->fw_size = dev->variant->buf_size->fw; + fw_buf->size = dev->variant->buf_size->fw; - if (dev->fw_virt_addr) { + if (fw_buf->virt) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); return -ENOMEM; } - dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev[BANK1_CTX], - dev->fw_size, &dev->dma_base[BANK1_CTX], - GFP_KERNEL); - if (!dev->fw_virt_addr) { + fw_buf->virt = dma_alloc_coherent(dev->mem_dev[BANK1_CTX], fw_buf->size, +&fw_buf->dma, GFP_KERNEL); + if (!fw_buf->virt) { mfc_err("Allocating bitprocessor buffer failed\n"); return -ENOMEM; } + dev->dma_base[BANK1_CTX] = fw_buf->dma; if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { bank2_virt = dma_alloc_coherent(dev->mem_dev[BANK2_CTX], @@ -51,10 +52,9 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) if (!bank2_virt) { mfc_err("Allocating bank2 base failed\n"); - dma_free_coherent(dev->mem_dev[BANK1_CTX], dev->fw_size, - dev->fw_virt_addr, - dev->dma_base[BANK1_CTX]); - dev->fw_virt_addr = NULL; + dma_free_coherent(dev->mem_dev[BANK1_CTX], fw_buf->size, + fw_buf->virt, fw_buf->dma); + fw_buf->virt = NULL; return -ENOMEM; } @@ -101,17 +101,17 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; } - if (fw_blob->size > dev->fw_size) { + if (fw_blob->size > dev->fw_buf.size) { mfc_err("MFC firmware is too big to be loaded\n"); release_firmware(fw_blob); return -ENOMEM; } - if (!dev->fw_virt_addr) { + if (!dev->fw_buf.virt) { mfc_err("MFC firmware is not allocated\n"); release_firmware(fw_blob); return -EINVAL; } - memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size); + me
[PATCH v3 09/16] media: s5p-mfc: Allocate firmware with internal private buffer alloc function
Once firmware buffer has been converted to use s5p_mfc_priv_buf structure, it is possible to allocate it with existing s5p_mfc_alloc_priv_buf() function. This change will help to reduce code variants in the next patches. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 14 +- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index b0cf3970117a..a1811ee538bd 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -27,6 +27,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) { struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf; + int err; fw_buf->size = dev->variant->buf_size->fw; @@ -35,11 +36,10 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) return -ENOMEM; } - fw_buf->virt = dma_alloc_coherent(dev->mem_dev[BANK1_CTX], fw_buf->size, -&fw_buf->dma, GFP_KERNEL); - if (!fw_buf->virt) { + err = s5p_mfc_alloc_priv_buf(dev, BANK1_CTX, &dev->fw_buf); + if (err) { mfc_err("Allocating bitprocessor buffer failed\n"); - return -ENOMEM; + return err; } return 0; @@ -92,11 +92,7 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) { /* Before calling this function one has to make sure * that MFC is no longer processing */ - if (!dev->fw_buf.virt) - return -EINVAL; - dma_free_coherent(dev->mem_dev[BANK1_CTX], dev->fw_buf.size, - dev->fw_buf.virt, dev->fw_buf.dma); - dev->fw_buf.virt = NULL; + s5p_mfc_release_priv_buf(dev, &dev->fw_buf); return 0; } -- 1.9.1
[PATCH v3 08/16] media: s5p-mfc: Move firmware allocation to DMA configure function
To complete DMA memory configuration for MFC device, allocation of the firmware buffer is needed, because some parameters are dependant on its base address. Till now, this has been handled in the s5p_mfc_alloc_firmware() function. This patch moves that logic to s5p_mfc_configure_dma_memory() to keep DMA memory related operations in a single place. This way s5p_mfc_alloc_firmware() is simplified and does what it name says. The other consequence of this change is moving s5p_mfc_alloc_firmware() call from the s5p_mfc_probe() function to the s5p_mfc_configure_dma_memory(). Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 62 +-- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 31 -- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 1fe790d88e70..16f4ba4f25ee 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1105,6 +1105,11 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; + void *bank2_virt; + dma_addr_t bank2_dma_addr; + unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; + struct s5p_mfc_priv_buf *fw_buf = &mfc_dev->fw_buf; + int ret; /* * When IOMMU is available, we cannot use the default configuration, @@ -1117,14 +1122,21 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) if (exynos_is_iommu_available(dev)) { int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, S5P_MFC_IOMMU_DMA_SIZE); - if (ret == 0) { - mfc_dev->mem_dev[BANK1_CTX] = - mfc_dev->mem_dev[BANK2_CTX] = dev; - vb2_dma_contig_set_max_seg_size(dev, - DMA_BIT_MASK(32)); + if (ret) + return ret; + + mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { + exynos_unconfigure_iommu(dev); + return ret; } - return ret; + mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; + mfc_dev->dma_base[BANK2_CTX] = fw_buf->dma; + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); + + return 0; } /* @@ -1142,6 +1154,35 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return -ENODEV; } + /* Allocate memory for firmware and initialize both banks addresses */ + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + return ret; + } + + mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; + + bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, + &bank2_dma_addr, GFP_KERNEL); + if (!bank2_virt) { + mfc_err("Allocating bank2 base failed\n"); + s5p_mfc_release_firmware(mfc_dev); + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + return -ENOMEM; + } + + /* Valid buffers passed to MFC encoder with LAST_FRAME command +* should not have address of bank2 - MFC will treat it as a null frame. +* To avoid such situation we set bank2 address below the pool address. +*/ + mfc_dev->dma_base[BANK2_CTX] = bank2_dma_addr - align_size; + + dma_free_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, bank2_virt, + bank2_dma_addr); + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK1_CTX], DMA_BIT_MASK(32)); vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK2_CTX], @@ -1154,6 +1195,8 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; + s5p_mfc_release_firmware(mfc_dev); + if (exynos_is_iommu_available(dev)) { exynos_unconfigure_iommu(dev); vb2_dma_contig_clear_max_seg_size(dev); @@ -1230,10 +1273,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) dev->watch
[PATCH v3 10/16] media: s5p-mfc: Reduce firmware buffer size for MFC v6+ variants
Firmware for MFC v6+ variants is not larger than 400 KiB, so there is no need to allocate a full 1 MiB buffer for it. Reduce it to 512 KiB to keep proper alignment of allocated buffer. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 2 +- drivers/media/platform/s5p-mfc/regs-mfc-v7.h | 2 +- drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index d2cd35916dc5..c0166ee9a455 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -403,7 +403,7 @@ #define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K)/* 12KB */ /* MFCv6 variant defines */ -#define MAX_FW_SIZE_V6 (SZ_1M) /* 1MB */ +#define MAX_FW_SIZE_V6 (SZ_512K) /* 512KB */ #define MAX_CPB_SIZE_V6(3 * SZ_1M) /* 3MB */ #define MFC_VERSION_V6 0x61 #define MFC_NUM_PORTS_V6 1 diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h index 1a5c6fdf7846..9f220769d970 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h @@ -34,7 +34,7 @@ #define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4 /* MFCv7 variant defines */ -#define MAX_FW_SIZE_V7 (SZ_1M) /* 1MB */ +#define MAX_FW_SIZE_V7 (SZ_512K) /* 512KB */ #define MAX_CPB_SIZE_V7(3 * SZ_1M) /* 3MB */ #define MFC_VERSION_V7 0x72 #define MFC_NUM_PORTS_V7 1 diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index 4d1c3750eb5e..75f5f7511d72 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -116,7 +116,7 @@ #define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64 /* MFCv8 variant defines */ -#define MAX_FW_SIZE_V8 (SZ_1M) /* 1MB */ +#define MAX_FW_SIZE_V8 (SZ_512K) /* 512KB */ #define MAX_CPB_SIZE_V8(3 * SZ_1M) /* 3MB */ #define MFC_VERSION_V8 0x80 #define MFC_NUM_PORTS_V8 1 -- 1.9.1
[PATCH v3 04/16] media: s5p-mfc: Replace bank1/bank2 entries with an array
Internal MFC driver device structure contains two entries for keeping addresses of the DMA memory banks. Replace them with the dma_base[] array and use defines for accessing particular banks. This will help to simplify code in the next patches. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 6 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 27 +++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 38 + drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 10 +++ 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 27d4c864e06e..da601a2dba2f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -273,8 +273,7 @@ struct s5p_mfc_priv_buf { * @queue: waitqueue for waiting for completion of device commands * @fw_size: size of firmware * @fw_virt_addr: virtual firmware address - * @bank1: address of the beginning of bank 1 memory - * @bank2: address of the beginning of bank 2 memory + * @dma_base[]:address of the beginning of memory banks * @hw_lock: used for hardware locking * @ctx: array of driver contexts * @curr_ctx: number of the currently running context @@ -315,8 +314,7 @@ struct s5p_mfc_dev { wait_queue_head_t queue; size_t fw_size; void *fw_virt_addr; - dma_addr_t bank1; - dma_addr_t bank2; + dma_addr_t dma_base[BANK_CTX_NUM]; unsigned long hw_lock; struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; int curr_ctx; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index cd1406c75d9a..c9bff3d0655f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -38,8 +38,8 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) } dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev[BANK1_CTX], - dev->fw_size, &dev->bank1, GFP_KERNEL); - + dev->fw_size, &dev->dma_base[BANK1_CTX], + GFP_KERNEL); if (!dev->fw_virt_addr) { mfc_err("Allocating bitprocessor buffer failed\n"); return -ENOMEM; @@ -52,7 +52,8 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) if (!bank2_virt) { mfc_err("Allocating bank2 base failed\n"); dma_free_coherent(dev->mem_dev[BANK1_CTX], dev->fw_size, - dev->fw_virt_addr, dev->bank1); + dev->fw_virt_addr, + dev->dma_base[BANK1_CTX]); dev->fw_virt_addr = NULL; return -ENOMEM; } @@ -61,7 +62,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) * should not have address of bank2 - MFC will treat it as a null frame. * To avoid such situation we set bank2 address below the pool address. */ - dev->bank2 = bank2_dma_addr - align_size; + dev->dma_base[BANK2_CTX] = bank2_dma_addr - align_size; dma_free_coherent(dev->mem_dev[BANK2_CTX], align_size, bank2_virt, bank2_dma_addr); @@ -70,7 +71,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) /* In this case bank2 can point to the same address as bank1. * Firmware will always occupy the beginning of this area so it is * impossible having a video frame buffer with zero address. */ - dev->bank2 = dev->bank1; + dev->dma_base[BANK2_CTX] = dev->dma_base[BANK1_CTX]; } return 0; } @@ -125,7 +126,7 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) if (!dev->fw_virt_addr) return -EINVAL; dma_free_coherent(dev->mem_dev[BANK1_CTX], dev->fw_size, - dev->fw_virt_addr, dev->bank1); + dev->fw_virt_addr, dev->dma_base[BANK1_CTX]); dev->fw_virt_addr = NULL; return 0; } @@ -211,13 +212,17 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { if (IS_MFCV6_PLUS(dev)) { - mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); -
[PATCH v3 06/16] media: s5p-mfc: Move setting DMA max segment size to DMA configure function
Setting DMA max segment size to 32 bit mask is a part of DMA memory configuration, so move those calls to s5p_mfc_configure_dma_memory() function. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 21 + 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index c03ed1a737b7..1fe790d88e70 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1117,9 +1117,13 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) if (exynos_is_iommu_available(dev)) { int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, S5P_MFC_IOMMU_DMA_SIZE); - if (ret == 0) + if (ret == 0) { mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; + vb2_dma_contig_set_max_seg_size(dev, + DMA_BIT_MASK(32)); + } + return ret; } @@ -1138,6 +1142,11 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return -ENODEV; } + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK1_CTX], + DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK2_CTX], + DMA_BIT_MASK(32)); + return 0; } @@ -1147,11 +1156,14 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) if (exynos_is_iommu_available(dev)) { exynos_unconfigure_iommu(dev); + vb2_dma_contig_clear_max_seg_size(dev); return; } device_unregister(mfc_dev->mem_dev[BANK1_CTX]); device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK2_CTX]); } /* MFC probe function */ @@ -1209,11 +1221,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) goto err_dma; } - vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK1_CTX], - DMA_BIT_MASK(32)); - vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK2_CTX], - DMA_BIT_MASK(32)); - mutex_init(&dev->mfc_mutex); init_waitqueue_head(&dev->queue); dev->hw_lock = 0; @@ -1346,8 +1353,6 @@ static int s5p_mfc_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); s5p_mfc_release_firmware(dev); s5p_mfc_unconfigure_dma_memory(dev); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK1_CTX]); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK2_CTX]); s5p_mfc_final_pm(dev); return 0; -- 1.9.1
[PATCH v3 16/16] ARM: dts: exynos: Remove MFC reserved buffers
During my research I found that some of the requirements for the memory buffers for MFC v6+ devices were blindly copied from the previous (v5) version and simply turned out to be excessive. The relaxed requirements are applied by the recent patches to the MFC driver and the driver is now fully functional even without the reserved memory blocks for all v6+ variants. This patch removes those reserved memory nodes from all boards having MFC v6+ hardware block. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- arch/arm/boot/dts/exynos5250-arndale.dts | 1 - arch/arm/boot/dts/exynos5250-smdk5250.dts | 1 - arch/arm/boot/dts/exynos5250-spring.dts| 1 - arch/arm/boot/dts/exynos5420-arndale-octa.dts | 1 - arch/arm/boot/dts/exynos5420-peach-pit.dts | 1 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 1 - arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 1 - arch/arm/boot/dts/exynos5800-peach-pi.dts | 1 - 8 files changed, 8 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index 6098dacd09f1..6a432460eb77 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -14,7 +14,6 @@ #include #include #include "exynos5250.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Insignal Arndale evaluation board based on EXYNOS5250"; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index a97a785ccc6b..6632f657394e 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -13,7 +13,6 @@ #include #include #include "exynos5250.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "SAMSUNG SMDK5250 board based on EXYNOS5250"; diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts index 4d7bdb735ed3..95c3bcace9dc 100644 --- a/arch/arm/boot/dts/exynos5250-spring.dts +++ b/arch/arm/boot/dts/exynos5250-spring.dts @@ -14,7 +14,6 @@ #include #include #include "exynos5250.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Google Spring"; diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts index 9cc83c51c925..ee1bb9b8b366 100644 --- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts +++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts @@ -16,7 +16,6 @@ #include #include #include -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Insignal Arndale Octa evaluation board based on EXYNOS5420"; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 1f964ec35c5e..2cd65699a29c 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -16,7 +16,6 @@ #include #include "exynos5420.dtsi" #include "exynos5420-cpus.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Google Peach Pit Rev 6+"; diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index aaccd0da41e5..08c8ab173e87 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -13,7 +13,6 @@ #include "exynos5420.dtsi" #include "exynos5420-cpus.dtsi" #include -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Samsung SMDK5420 board based on EXYNOS5420"; diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi index 05b9afdd6757..657535e2e3cc 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi @@ -18,7 +18,6 @@ #include #include "exynos5800.dtsi" #include "exynos5422-cpus.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { memory@4000 { diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index f9ff7f07ae0c..ecf1c916e8fc 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts @@ -16,7 +16,6 @@ #include #include "exynos5800.dtsi" #include "exynos5420-cpus.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Google Peach Pi Rev 10+"; -- 1.9.1
[PATCH v3 02/16] media: s5p-mfc: Use generic of_device_get_match_data helper
Replace custom code with generic helper to retrieve driver data. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy Reviewed-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 17 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 4 ++-- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 4e9f349c1be3..af223b0a41a3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include "s5p_mfc_common.h" @@ -1152,8 +1153,6 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) device_unregister(mfc_dev->mem_dev_r); } -static void *mfc_get_drv_data(struct platform_device *pdev); - /* MFC probe function */ static int s5p_mfc_probe(struct platform_device *pdev) { @@ -1177,7 +1176,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) return -ENODEV; } - dev->variant = mfc_get_drv_data(pdev); + dev->variant = of_device_get_match_data(&pdev->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->regs_base = devm_ioremap_resource(&pdev->dev, res); @@ -1536,18 +1535,6 @@ static int s5p_mfc_resume(struct device *dev) }; MODULE_DEVICE_TABLE(of, exynos_mfc_match); -static void *mfc_get_drv_data(struct platform_device *pdev) -{ - struct s5p_mfc_variant *driver_data = NULL; - const struct of_device_id *match; - - match = of_match_node(exynos_mfc_match, pdev->dev.of_node); - if (match) - driver_data = (struct s5p_mfc_variant *)match->data; - - return driver_data; -} - static struct platform_driver s5p_mfc_driver = { .probe = s5p_mfc_probe, .remove = s5p_mfc_remove, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 3e0e8eaf8bfe..2f1387a4c386 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -192,7 +192,7 @@ struct s5p_mfc_buf { */ struct s5p_mfc_pm { struct clk *clock_gate; - const char **clk_names; + const char * const *clk_names; struct clk *clocks[MFC_MAX_CLOCKS]; int num_clocks; booluse_clock_gating; @@ -304,7 +304,7 @@ struct s5p_mfc_dev { struct v4l2_ctrl_handler dec_ctrl_handler; struct v4l2_ctrl_handler enc_ctrl_handler; struct s5p_mfc_pm pm; - struct s5p_mfc_variant *variant; + const struct s5p_mfc_variant*variant; int num_inst; spinlock_t irqlock; /* lock when operating on context */ spinlock_t condlock;/* lock when changing/checking if a context is -- 1.9.1
[PATCH v3 12/16] media: s5p-mfc: Add support for probe-time preallocated block based allocator
Current MFC driver depends on the fact that when IOMMU is available, the DMA-mapping framework and its IOMMU glue will use first-fit allocator. This was true for ARM architecture, but its not for ARM64 arch. However, in case of MFC v6+ hardware and latest firmware, it turned out that there is no strict requirement for ALL buffers to be allocated on higher addresses than the firmware base. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Such relaxed requirements for the memory buffers can be easily fulfilled by allocating firmware, device and per-context buffers from the probe-time preallocated larger buffer. This patch adds support for it. This way the driver finally works fine on ARM64 architecture. The size of the preallocated buffer is 8 MiB, what is enough for three instances H264 decoders or encoders (other codecs have smaller memory requirements). If one needs more for particular use case, one can use "mem" module parameter to force larger (or smaller) buffer (for example by adding "s5p_mfc.mem=16M" to kernel command line). Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 43 --- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 4 ++ drivers/media/platform/s5p-mfc/s5p_mfc_opr.c| 57 - 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index ff3bb8af2423..ea01d0aa8303 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -43,6 +43,10 @@ module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); +static char *mfc_mem_size = NULL; +module_param_named(mem, mfc_mem_size, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(mem, "Preallocated memory size for the firmware and context buffers"); + /* Helper functions for interrupt processing */ /* Remove from hw execution round robin */ @@ -1173,6 +1177,8 @@ static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; + unsigned long mem_size = SZ_8M; + unsigned int bitmap_size; /* * When IOMMU is available, we cannot use the default configuration, * because of MFC firmware requirements: address space limited to @@ -1186,17 +1192,39 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) if (ret) return ret; - mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; - ret = s5p_mfc_alloc_firmware(mfc_dev); - if (ret) { + if (mfc_mem_size) + mem_size = memparse(mfc_mem_size, NULL); + + bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long); + + mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!mfc_dev->mem_bitmap) { exynos_unconfigure_iommu(dev); - return ret; + return -ENOMEM; } - mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma; - mfc_dev->dma_base[BANK2_CTX] = mfc_dev->fw_buf.dma; + mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, + &mfc_dev->mem_base, GFP_KERNEL); + if (!mfc_dev->mem_virt) { + kfree(mfc_dev->mem_bitmap); + dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", + (mem_size / SZ_1M)); + exynos_unconfigure_iommu(dev); + return -ENOMEM; + } + mfc_dev->mem_size = mem_size; + mfc_dev->dma_base[BANK1_CTX] = mfc_dev->mem_base; + mfc_dev->dma_base[BANK2_CTX] = mfc_dev->mem_base; + + /* Firmware allocation cannot fail in this case */ + s5p_mfc_alloc_firmware(mfc_dev); + + mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dev_info(dev, "preallocated %ld MiB buffer for the firmware and context buffers\n", +(mem_size / SZ_1M)); + return 0; } @@ -1205,6 +1233,9 @@ static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = &mfc_dev->plat_dev->dev; exynos_unconfigure_iommu(dev); + dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, + mfc_dev->mem_base); +
[PATCH v3 11/16] media: s5p-mfc: Split variant DMA memory configuration into separate functions
Move code for DMA memory configuration with IOMMU into separate function to make it easier to compare what is being done in each case. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 102 ++- 1 file changed, 61 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 16f4ba4f25ee..ff3bb8af2423 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1102,44 +1102,15 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, return NULL; } -static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) +static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; void *bank2_virt; dma_addr_t bank2_dma_addr; unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; - struct s5p_mfc_priv_buf *fw_buf = &mfc_dev->fw_buf; int ret; /* -* When IOMMU is available, we cannot use the default configuration, -* because of MFC firmware requirements: address space limited to -* 256M and non-zero default start address. -* This is still simplified, not optimal configuration, but for now -* IOMMU core doesn't allow to configure device's IOMMUs channel -* separately. -*/ - if (exynos_is_iommu_available(dev)) { - int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, -S5P_MFC_IOMMU_DMA_SIZE); - if (ret) - return ret; - - mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; - ret = s5p_mfc_alloc_firmware(mfc_dev); - if (ret) { - exynos_unconfigure_iommu(dev); - return ret; - } - - mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; - mfc_dev->dma_base[BANK2_CTX] = fw_buf->dma; - vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); - - return 0; - } - - /* * Create and initialize virtual devices for accessing * reserved memory regions. */ @@ -1162,7 +1133,7 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return ret; } - mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; + mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma; bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, &bank2_dma_addr, GFP_KERNEL); @@ -1191,22 +1162,71 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return 0; } -static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) +static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) { - struct device *dev = &mfc_dev->plat_dev->dev; + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK2_CTX]); +} - s5p_mfc_release_firmware(mfc_dev); +static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + /* +* When IOMMU is available, we cannot use the default configuration, +* because of MFC firmware requirements: address space limited to +* 256M and non-zero default start address. +* This is still simplified, not optimal configuration, but for now +* IOMMU core doesn't allow to configure device's IOMMUs channel +* separately. +*/ + int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, +S5P_MFC_IOMMU_DMA_SIZE); + if (ret) + return ret; - if (exynos_is_iommu_available(dev)) { + mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { exynos_unconfigure_iommu(dev); - vb2_dma_contig_clear_max_seg_size(dev); - return; + return ret; } - device_unregister(mfc_dev->mem_dev[BANK1_CTX]); - device_unregister(mfc_dev->mem_dev[BANK2_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK2_CTX]); + mfc_dev->dma_base[BANK1_CTX] = mfc_dev-
[PATCH v3 15/16] media: s5p-mfc: Rename BANK1/2 to BANK_L/R to better match documentation
Documentation for MFC hardware still uses 'left' and 'right' names for the memory channel/banks, so replace BANK1/2 defines with more appropriate BANK_L/R names. Suggested-by: Shuah Khan Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 54 - drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 4 +- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 13 +++--- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c| 8 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c| 10 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 28 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 6 +-- 7 files changed, 62 insertions(+), 61 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index a56031c3263e..dc1f6a96877a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1118,34 +1118,34 @@ static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) * Create and initialize virtual devices for accessing * reserved memory regions. */ - mfc_dev->mem_dev[BANK1_CTX] = s5p_mfc_alloc_memdev(dev, "left", - BANK1_CTX); - if (!mfc_dev->mem_dev[BANK1_CTX]) + mfc_dev->mem_dev[BANK_L_CTX] = s5p_mfc_alloc_memdev(dev, "left", + BANK_L_CTX); + if (!mfc_dev->mem_dev[BANK_L_CTX]) return -ENODEV; - mfc_dev->mem_dev[BANK2_CTX] = s5p_mfc_alloc_memdev(dev, "right", - BANK2_CTX); - if (!mfc_dev->mem_dev[BANK2_CTX]) { - device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + mfc_dev->mem_dev[BANK_R_CTX] = s5p_mfc_alloc_memdev(dev, "right", + BANK_R_CTX); + if (!mfc_dev->mem_dev[BANK_R_CTX]) { + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); return -ENODEV; } /* Allocate memory for firmware and initialize both banks addresses */ ret = s5p_mfc_alloc_firmware(mfc_dev); if (ret) { - device_unregister(mfc_dev->mem_dev[BANK2_CTX]); - device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); return ret; } - mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma; + mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->fw_buf.dma; - bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, - &bank2_dma_addr, GFP_KERNEL); + bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK_R_CTX], + align_size, &bank2_dma_addr, GFP_KERNEL); if (!bank2_virt) { mfc_err("Allocating bank2 base failed\n"); s5p_mfc_release_firmware(mfc_dev); - device_unregister(mfc_dev->mem_dev[BANK2_CTX]); - device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); return -ENOMEM; } @@ -1153,14 +1153,14 @@ static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) * should not have address of bank2 - MFC will treat it as a null frame. * To avoid such situation we set bank2 address below the pool address. */ - mfc_dev->dma_base[BANK2_CTX] = bank2_dma_addr - align_size; + mfc_dev->dma_base[BANK_R_CTX] = bank2_dma_addr - align_size; - dma_free_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, bank2_virt, + dma_free_coherent(mfc_dev->mem_dev[BANK_R_CTX], align_size, bank2_virt, bank2_dma_addr); - vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK1_CTX], + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX], DMA_BIT_MASK(32)); - vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK2_CTX], + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX], DMA_BIT_MASK(32)); return 0; @@ -1168,10 +1168,10 @@ static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) { - device_unregister(mfc_dev->mem_dev[BANK1_CTX]); - device_unregister(mfc_dev->mem_dev[BANK2_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]);
[PATCH v3 14/16] media: s5p-mfc: Use preallocated block allocator always for MFC v6+
It turned out that all versions of MFC v6+ hardware doesn't have a strict requirement for ALL buffers to be allocated on higher addresses than the firmware base like it was documented for MFC v5. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Basing on this fact, the special DMA configuration based on two reserved memory regions is not really needed for MFC v6+ devices, because the memory requirements for the firmware, device and per-context buffers can be fulfilled by the simple probe-time pre-allocated block allocator instroduced in previous patch. This patch enables support for such pre-allocated block based allocator always for MFC v6+ devices. Due to the limitations of the memory management subsystem the largest supported size of the pre-allocated buffer when no CMA (Contiguous Memory Allocator) is enabled is 4MiB. This patch also removes the requirement to provide two reserved memory regions for MFC v6+ devices in device tree. Now the driver is fully functional without them. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Andrzej Hajda Tested-by: Smitha T Murthy --- Documentation/devicetree/bindings/media/s5p-mfc.txt | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc.c| 9 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 2c901286d818..d3404b5d4d17 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -28,7 +28,7 @@ Optional properties: - memory-region : from reserved memory binding: phandles to two reserved memory regions, first is for "left" mfc memory bus interfaces, second if for the "right" mfc memory bus, used when no SYSMMU - support is available + support is available; used only by MFC v5 present in Exynos4 SoCs Obsolete properties: - samsung,mfc-r, samsung,mfc-l : support removed, please use memory-region diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index f1528054a713..a56031c3263e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1177,9 +1177,12 @@ static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; - unsigned long mem_size = SZ_8M; + unsigned long mem_size = SZ_4M; unsigned int bitmap_size; + if (IS_ENABLED(CONFIG_DMA_CMA) || exynos_is_iommu_available(dev)) + mem_size = SZ_8M; + if (mfc_mem_size) mem_size = memparse(mfc_mem_size, NULL); @@ -1239,7 +1242,7 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; - if (exynos_is_iommu_available(dev)) + if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) return s5p_mfc_configure_common_memory(mfc_dev); else return s5p_mfc_configure_2port_memory(mfc_dev); @@ -1250,7 +1253,7 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = &mfc_dev->plat_dev->dev; s5p_mfc_release_firmware(mfc_dev); - if (exynos_is_iommu_available(dev)) + if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) s5p_mfc_unconfigure_common_memory(mfc_dev); else s5p_mfc_unconfigure_2port_memory(mfc_dev); -- 1.9.1
Re: [PATCH 14/15] media: s5p-mfc: Use preallocated block allocator always for MFC v6+
Hi Shuah, On 2017-02-24 15:23, Shuah Khan wrote: On Thu, Feb 23, 2017 at 11:26 PM, Marek Szyprowski wrote: On 2017-02-23 22:43, Shuah Khan wrote: On Tue, Feb 14, 2017 at 12:52 AM, Marek Szyprowski wrote: It turned out that all versions of MFC v6+ hardware doesn't have a strict requirement for ALL buffers to be allocated on higher addresses than the firmware base like it was documented for MFC v5. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Basing on this fact, the special DMA configuration based on two reserved memory regions is not really needed for MFC v6+ devices, because the memory requirements for the firmware, device and per-context buffers can be fulfilled by the simple probe-time pre-allocated block allocator instroduced in previous patch. This patch enables support for such pre-allocated block based allocator always for MFC v6+ devices. Due to the limitations of the memory management subsystem the largest supported size of the pre-allocated buffer when no CMA (Contiguous Memory Allocator) is enabled is 4MiB. This patch also removes the requirement to provide two reserved memory regions for MFC v6+ devices in device tree. Now the driver is fully functional without them. Signed-off-by: Marek Szyprowski Hi Marek, This patch breaks display manager. exynos_drm_gem_create() isn't happy. dmesg and console are flooded with odroid login: [ 209.170566] [drm:exynos_drm_gem_create] *ERROR* failed to allo. [ 212.173222] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 215.354790] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 218.736464] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 221.837128] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 226.284827] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 229.242498] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 232.063150] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 235.73] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 239.472061] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 242.567465] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 246.500541] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 249.996018] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 253.837272] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 257.048782] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 260.084819] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 263.448611] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 266.271074] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 269.011558] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 272.039066] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 275.404938] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 278.339033] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 281.274751] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 284.641202] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 287.461039] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 291.062011] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 294.746870] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 298.246570] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. I don't think this is an acceptable behavior. It is a regression. This is a really poor bug report... Could you elaborate a bit how to reproduce this? Could you provide your kernel config and information about test environment? Yeah. I should have give you more information. My bad. I suspect that you use CMA without IOMMU and you have too small global CMA region. Yes. I have CMA and using exynos_defconfig. Nothing fancy. I think what's happening is s5p_mfc pre-allocates and there is nothing left when disaply manager starts requestuing gem buffers. This failure happens when systemd kicks off lightdm. After this patch MFC driver uses global CMA region instead of the MFC's private ones, so one has to ensure that the global region is large enough. This is still a regression since it requires users to take some action. I think we need some kind of checks to warn users there isn't a large enough CMA region. This is the same config I have been using forever and with this patch, it breaks. Easy to reproduce on odroid-xu4 with HDMI display. You just have to boot the system with exynos_defconfig. Display manager will fail when it requests buffers. That is still a bit strange. MFC pre-allocates 8MiB buffer. The default CMA global region size is 64MiB, which should be enough for a few display
Re: [PATCH 14/15] media: s5p-mfc: Use preallocated block allocator always for MFC v6+
Hi Shuah On 2017-02-23 22:43, Shuah Khan wrote: On Tue, Feb 14, 2017 at 12:52 AM, Marek Szyprowski wrote: It turned out that all versions of MFC v6+ hardware doesn't have a strict requirement for ALL buffers to be allocated on higher addresses than the firmware base like it was documented for MFC v5. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Basing on this fact, the special DMA configuration based on two reserved memory regions is not really needed for MFC v6+ devices, because the memory requirements for the firmware, device and per-context buffers can be fulfilled by the simple probe-time pre-allocated block allocator instroduced in previous patch. This patch enables support for such pre-allocated block based allocator always for MFC v6+ devices. Due to the limitations of the memory management subsystem the largest supported size of the pre-allocated buffer when no CMA (Contiguous Memory Allocator) is enabled is 4MiB. This patch also removes the requirement to provide two reserved memory regions for MFC v6+ devices in device tree. Now the driver is fully functional without them. Signed-off-by: Marek Szyprowski Hi Marek, This patch breaks display manager. exynos_drm_gem_create() isn't happy. dmesg and console are flooded with odroid login: [ 209.170566] [drm:exynos_drm_gem_create] *ERROR* failed to allo. [ 212.173222] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 215.354790] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 218.736464] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 221.837128] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 226.284827] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 229.242498] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 232.063150] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 235.73] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 239.472061] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 242.567465] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 246.500541] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 249.996018] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 253.837272] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 257.048782] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 260.084819] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 263.448611] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 266.271074] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 269.011558] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 272.039066] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 275.404938] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 278.339033] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 281.274751] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 284.641202] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 287.461039] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 291.062011] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 294.746870] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. [ 298.246570] [drm:exynos_drm_gem_create] *ERROR* failed to allocate buffer. I don't think this is an acceptable behavior. It is a regression. This is a really poor bug report... Could you elaborate a bit how to reproduce this? Could you provide your kernel config and information about test environment? I suspect that you use CMA without IOMMU and you have too small global CMA region. After this patch MFC driver uses global CMA region instead of the MFC's private ones, so one has to ensure that the global region is large enough. > [...] Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] media: mfc: Fix race between interrupt routine and device functions
Interrupt routine must wake process waiting for given interrupt AFTER updating driver's internal structures and contexts. Doing it in-between is a serious bug. This patch moves all calls to the wake() function to the end of the interrupt processing block to avoid potential and real races, especially on multi-core platforms. This also fixes following issue reported from clock core (clocks were disabled in interrupt after being unprepared from the other place in the driver, the stack trace however points to the different place than s5p_mfc driver because of the race): WARNING: CPU: 1 PID: 18 at drivers/clk/clk.c:544 clk_core_unprepare+0xc8/0x108 Modules linked in: CPU: 1 PID: 18 Comm: kworker/1:0 Not tainted 4.10.0-next-20170223-00070-g04e18bc99ab9-dirty #2154 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) Workqueue: pm pm_runtime_work [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x74/0x94) [] (dump_stack) from [] (__warn+0xd4/0x100) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (clk_core_unprepare+0xc8/0x108) [] (clk_core_unprepare) from [] (clk_unprepare+0x24/0x2c) [] (clk_unprepare) from [] (exynos_sysmmu_suspend+0x48/0x60) [] (exynos_sysmmu_suspend) from [] (pm_generic_runtime_suspend+0x2c/0x38) [] (pm_generic_runtime_suspend) from [] (genpd_runtime_suspend+0x94/0x220) [] (genpd_runtime_suspend) from [] (__rpm_callback+0x134/0x208) [] (__rpm_callback) from [] (rpm_callback+0x20/0x80) [] (rpm_callback) from [] (rpm_suspend+0xdc/0x458) [] (rpm_suspend) from [] (pm_runtime_work+0x80/0x90) [] (pm_runtime_work) from [] (process_one_work+0x120/0x318) [] (process_one_work) from [] (worker_thread+0x2c/0x4ac) [] (worker_thread) from [] (kthread+0xfc/0x134) [] (kthread) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 1ead49a7bb83f0d8 ]--- Signed-off-by: Marek Szyprowski Fixes: af93574678108 ("[media] MFC: Add MFC 5.1 V4L2 driver") CC: sta...@vger.kernel.org # v4.5+ --- This issue was there from the beggining of the driver, but this patch applies only to v4.5+ kernels. --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 12 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 9e0685beb048..d6cb315dac60 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -657,9 +657,9 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) break; } s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); + wake_up_ctx(ctx, reason, err); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); @@ -673,15 +673,11 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); ctx->state = MFCINST_GOT_INST; - clear_work_bit(ctx); - wake_up(&ctx->queue); goto irq_cleanup_hw; case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: - clear_work_bit(ctx); ctx->inst_no = MFC_NO_INSTANCE_SET; ctx->state = MFCINST_FREE; - wake_up(&ctx->queue); goto irq_cleanup_hw; case S5P_MFC_R2H_CMD_SYS_INIT_RET: @@ -691,9 +687,9 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) if (ctx) clear_work_bit(ctx); s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); + wake_up_dev(dev, reason, err); break; case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: @@ -708,9 +704,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) break; case S5P_MFC_R2H_CMD_DPB_FLUSH_RET: - clear_work_bit(ctx); ctx->state = MFCINST_RUNNING; - wake_up(&ctx->queue); goto irq_cleanup_hw; default: @@ -729,6 +723,8 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) mfc_err("Failed to unlock hw\n"); s5p_mfc_clock_off(); + clear_work_bit(ctx); + wake_up(&ctx->queue); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); spin_unlock(&dev->irqlock); -- 1.9.1
Re: [PATCH v2 08/15] media: s5p-mfc: Move firmware allocation to DMA configure function
Hi Shuah, On 2017-02-22 19:07, Shuah Khan wrote: On Mon, Feb 20, 2017 at 6:38 AM, Marek Szyprowski wrote: To complete DMA memory configuration for MFC device, allocation of the firmware buffer is needed, because some parameters are dependant on its base address. Till now, this has been handled in the s5p_mfc_alloc_firmware() function. This patch moves that logic to s5p_mfc_configure_dma_memory() to keep DMA memory related operations in a single place. This way s5p_mfc_alloc_firmware() is simplified and does what it name says. The other consequence of this change is moving s5p_mfc_alloc_firmware() call from the s5p_mfc_probe() function to the s5p_mfc_configure_dma_memory(). Overall looks good. This patch makes subtle change in the dma and firwmare initialization sequence. Might be okay, but wanted to call out just in case, Before this change: vb2_dma_contig_set_max_seg_size() is done for both iommu and non-iommu case before s5p_mfc_alloc_firmware(). With this change setting dma_contig max size happens after s5p_mfc_alloc_firmware(). From what I can tell this might not be an issue. vb2_dma_contig_clear_max_seg_size() still happens after s5p_mfc_release_firmware(), so that part hasn't changed. Do any of the dma_* calls made from s5p_mfc_alloc_firmware() and later during the dma congiguration sequence depend on dmap_parms being allocated? Doesn't looks like it from what I can tell, but safe to ask. Firmware allocation doesn't depend on dma max segment size at all. The only calls which might depend on it are dma_map_sg(), which are performed much later as a part of video buffer allocation/preparation in videobuf2, when dma-buf or user pointer v4l2 modes are selected. > [...] Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] dma-buf: add support for compat ioctl
Dear All, On 2017-02-21 15:37, Marek Szyprowski wrote: Hi Christian, On 2017-02-21 14:59, Christian König wrote: Am 21.02.2017 um 14:21 schrieb Marek Szyprowski: Add compat ioctl support to dma-buf. This lets one to use DMA_BUF_IOCTL_SYNC ioctl from 32bit application on 64bit kernel. Data structures for both 32 and 64bit modes are same, so there is no need for additional translation layer. Well I might be wrong, but IIRC compat_ioctl was just optional and if not specified unlocked_ioctl was called instead. If that is true your patch wouldn't have any effect at all. Well, then why I got -ENOTTY in the 32bit test app for this ioctl on 64bit ARM64 kernel without this patch? I've checked in fs/compat_ioctl.c, I see no fallback in COMPAT_SYSCALL_DEFINE3, so one has to provide compat_ioctl callback to have ioctl working with 32bit apps. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] dma-buf: add support for compat ioctl
Hi Christian, On 2017-02-21 14:59, Christian König wrote: Am 21.02.2017 um 14:21 schrieb Marek Szyprowski: Add compat ioctl support to dma-buf. This lets one to use DMA_BUF_IOCTL_SYNC ioctl from 32bit application on 64bit kernel. Data structures for both 32 and 64bit modes are same, so there is no need for additional translation layer. Well I might be wrong, but IIRC compat_ioctl was just optional and if not specified unlocked_ioctl was called instead. If that is true your patch wouldn't have any effect at all. Well, then why I got -ENOTTY in the 32bit test app for this ioctl on 64bit ARM64 kernel without this patch? Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
[PATCH] dma-buf: add support for compat ioctl
Add compat ioctl support to dma-buf. This lets one to use DMA_BUF_IOCTL_SYNC ioctl from 32bit application on 64bit kernel. Data structures for both 32 and 64bit modes are same, so there is no need for additional translation layer. Signed-off-by: Marek Szyprowski --- drivers/dma-buf/dma-buf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 718f832a5c71..0007b792827b 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -325,6 +325,9 @@ static long dma_buf_ioctl(struct file *file, .llseek = dma_buf_llseek, .poll = dma_buf_poll, .unlocked_ioctl = dma_buf_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dma_buf_ioctl, +#endif }; /* -- 1.9.1
[PATCH v2 06/15] media: s5p-mfc: Move setting DMA max segment size to DMA configure function
Setting DMA max segment size to 32 bit mask is a part of DMA memory configuration, so move those calls to s5p_mfc_configure_dma_memory() function. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 21 + 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index f7664910f12c..bc1aeb25ebeb 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1122,9 +1122,13 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) if (exynos_is_iommu_available(dev)) { int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, S5P_MFC_IOMMU_DMA_SIZE); - if (ret == 0) + if (ret == 0) { mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; + vb2_dma_contig_set_max_seg_size(dev, + DMA_BIT_MASK(32)); + } + return ret; } @@ -1143,6 +1147,11 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return -ENODEV; } + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK1_CTX], + DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK2_CTX], + DMA_BIT_MASK(32)); + return 0; } @@ -1152,11 +1161,14 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) if (exynos_is_iommu_available(dev)) { exynos_unconfigure_iommu(dev); + vb2_dma_contig_clear_max_seg_size(dev); return; } device_unregister(mfc_dev->mem_dev[BANK1_CTX]); device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK2_CTX]); } /* MFC probe function */ @@ -1214,11 +1226,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) goto err_dma; } - vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK1_CTX], - DMA_BIT_MASK(32)); - vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK2_CTX], - DMA_BIT_MASK(32)); - mutex_init(&dev->mfc_mutex); init_waitqueue_head(&dev->queue); dev->hw_lock = 0; @@ -1351,8 +1358,6 @@ static int s5p_mfc_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); s5p_mfc_release_firmware(dev); s5p_mfc_unconfigure_dma_memory(dev); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK1_CTX]); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK2_CTX]); s5p_mfc_final_pm(dev); return 0; -- 1.9.1
[PATCH v2 03/15] media: s5p-mfc: Replace mem_dev_* entries with an array
Internal MFC driver device structure contains two pointers to devices used for DMA memory allocation: mem_dev_l and mem_dev_r. Replace them with the mem_dev[] array and use defines for accessing particular banks. This will help to simplify code in the next patches. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 31 +--- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 11 - drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 23 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c| 8 +++ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c| 10 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 32 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 15 ++-- 7 files changed, 69 insertions(+), 61 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index ad3d7377f40d..f7664910f12c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1123,7 +1123,8 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, S5P_MFC_IOMMU_DMA_SIZE); if (ret == 0) - mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; + mfc_dev->mem_dev[BANK1_CTX] = + mfc_dev->mem_dev[BANK2_CTX] = dev; return ret; } @@ -1131,14 +1132,14 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) * Create and initialize virtual devices for accessing * reserved memory regions. */ - mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left", - MFC_BANK1_ALLOC_CTX); - if (!mfc_dev->mem_dev_l) + mfc_dev->mem_dev[BANK1_CTX] = s5p_mfc_alloc_memdev(dev, "left", + BANK1_CTX); + if (!mfc_dev->mem_dev[BANK1_CTX]) return -ENODEV; - mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right", - MFC_BANK2_ALLOC_CTX); - if (!mfc_dev->mem_dev_r) { - device_unregister(mfc_dev->mem_dev_l); + mfc_dev->mem_dev[BANK2_CTX] = s5p_mfc_alloc_memdev(dev, "right", + BANK2_CTX); + if (!mfc_dev->mem_dev[BANK2_CTX]) { + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); return -ENODEV; } @@ -1154,8 +1155,8 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) return; } - device_unregister(mfc_dev->mem_dev_l); - device_unregister(mfc_dev->mem_dev_r); + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); } /* MFC probe function */ @@ -1213,8 +1214,10 @@ static int s5p_mfc_probe(struct platform_device *pdev) goto err_dma; } - vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); - vb2_dma_contig_set_max_seg_size(dev->mem_dev_r, DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK1_CTX], + DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(dev->mem_dev[BANK2_CTX], + DMA_BIT_MASK(32)); mutex_init(&dev->mfc_mutex); init_waitqueue_head(&dev->queue); @@ -1348,8 +1351,8 @@ static int s5p_mfc_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); s5p_mfc_release_firmware(dev); s5p_mfc_unconfigure_dma_memory(dev); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev_l); - vb2_dma_contig_clear_max_seg_size(dev->mem_dev_r); + vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK1_CTX]); + vb2_dma_contig_clear_max_seg_size(dev->mem_dev[BANK2_CTX]); s5p_mfc_final_pm(dev); return 0; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 2f1387a4c386..27d4c864e06e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -33,8 +33,9 @@ * while mmaping */ #define DST_QUEUE_OFF_BASE (1 << 30) -#define MFC_BANK1_ALLOC_CTX0 -#define MFC_BANK2_ALLOC_CTX1 +#define BANK1_CTX 0 +#define BANK2_CTX 1 +#define BANK_CTX_NUM 2 #define MFC_BANK1_ALIGN_ORDER 13 #define MFC_BANK2_ALIGN_ORDER 13 @@ -254,8 +255,7 @@ struct s5p_mf
[PATCH v2 02/15] media: s5p-mfc: Use generic of_device_get_match_data helper
Replace custom code with generic helper to retrieve driver data. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 17 ++--- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 4 ++-- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3e1f22eb4339..ad3d7377f40d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include "s5p_mfc_common.h" @@ -1157,8 +1158,6 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) device_unregister(mfc_dev->mem_dev_r); } -static void *mfc_get_drv_data(struct platform_device *pdev); - /* MFC probe function */ static int s5p_mfc_probe(struct platform_device *pdev) { @@ -1182,7 +1181,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) return -ENODEV; } - dev->variant = mfc_get_drv_data(pdev); + dev->variant = of_device_get_match_data(&pdev->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->regs_base = devm_ioremap_resource(&pdev->dev, res); @@ -1541,18 +1540,6 @@ static int s5p_mfc_resume(struct device *dev) }; MODULE_DEVICE_TABLE(of, exynos_mfc_match); -static void *mfc_get_drv_data(struct platform_device *pdev) -{ - struct s5p_mfc_variant *driver_data = NULL; - const struct of_device_id *match; - - match = of_match_node(exynos_mfc_match, pdev->dev.of_node); - if (match) - driver_data = (struct s5p_mfc_variant *)match->data; - - return driver_data; -} - static struct platform_driver s5p_mfc_driver = { .probe = s5p_mfc_probe, .remove = s5p_mfc_remove, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 3e0e8eaf8bfe..2f1387a4c386 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -192,7 +192,7 @@ struct s5p_mfc_buf { */ struct s5p_mfc_pm { struct clk *clock_gate; - const char **clk_names; + const char * const *clk_names; struct clk *clocks[MFC_MAX_CLOCKS]; int num_clocks; booluse_clock_gating; @@ -304,7 +304,7 @@ struct s5p_mfc_dev { struct v4l2_ctrl_handler dec_ctrl_handler; struct v4l2_ctrl_handler enc_ctrl_handler; struct s5p_mfc_pm pm; - struct s5p_mfc_variant *variant; + const struct s5p_mfc_variant*variant; int num_inst; spinlock_t irqlock; /* lock when operating on context */ spinlock_t condlock;/* lock when changing/checking if a context is -- 1.9.1
[PATCH v2 10/15] media: s5p-mfc: Reduce firmware buffer size for MFC v6+ variants
Firmware for MFC v6+ variants is not larger than 400 KiB, so there is no need to allocate a full 1 MiB buffer for it. Reduce it to 512 KiB to keep proper alignment of allocated buffer. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 2 +- drivers/media/platform/s5p-mfc/regs-mfc-v7.h | 2 +- drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index d2cd35916dc5..c0166ee9a455 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -403,7 +403,7 @@ #define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K)/* 12KB */ /* MFCv6 variant defines */ -#define MAX_FW_SIZE_V6 (SZ_1M) /* 1MB */ +#define MAX_FW_SIZE_V6 (SZ_512K) /* 512KB */ #define MAX_CPB_SIZE_V6(3 * SZ_1M) /* 3MB */ #define MFC_VERSION_V6 0x61 #define MFC_NUM_PORTS_V6 1 diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h index 1a5c6fdf7846..9f220769d970 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h @@ -34,7 +34,7 @@ #define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4 /* MFCv7 variant defines */ -#define MAX_FW_SIZE_V7 (SZ_1M) /* 1MB */ +#define MAX_FW_SIZE_V7 (SZ_512K) /* 512KB */ #define MAX_CPB_SIZE_V7(3 * SZ_1M) /* 3MB */ #define MFC_VERSION_V7 0x72 #define MFC_NUM_PORTS_V7 1 diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index 4d1c3750eb5e..75f5f7511d72 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -116,7 +116,7 @@ #define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64 /* MFCv8 variant defines */ -#define MAX_FW_SIZE_V8 (SZ_1M) /* 1MB */ +#define MAX_FW_SIZE_V8 (SZ_512K) /* 512KB */ #define MAX_CPB_SIZE_V8(3 * SZ_1M) /* 3MB */ #define MFC_VERSION_V8 0x80 #define MFC_NUM_PORTS_V8 1 -- 1.9.1
[PATCH v2 07/15] media: s5p-mfc: Put firmware to private buffer structure
Use s5p_mfc_priv_buf structure for keeping the firmware image. This will help handling of firmware buffer allocation in the next patches. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 3 +-- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 36 - 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index 8c4739ca16d6..4c80bb4243be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -47,7 +47,7 @@ static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) struct s5p_mfc_cmd_args h2r_args; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = dev->fw_size; + h2r_args.arg[0] = dev->fw_buf.size; return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 9cf860f34c71..cea17a737ef7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -314,8 +314,7 @@ struct s5p_mfc_dev { int int_type; unsigned int int_err; wait_queue_head_t queue; - size_t fw_size; - void *fw_virt_addr; + struct s5p_mfc_priv_buf fw_buf; dma_addr_t dma_base[BANK_CTX_NUM]; unsigned long hw_lock; struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index c9bff3d0655f..50d698968049 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -29,21 +29,22 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) void *bank2_virt; dma_addr_t bank2_dma_addr; unsigned int align_size = 1 << MFC_BASE_ALIGN_ORDER; + struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf; - dev->fw_size = dev->variant->buf_size->fw; + fw_buf->size = dev->variant->buf_size->fw; - if (dev->fw_virt_addr) { + if (fw_buf->virt) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); return -ENOMEM; } - dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev[BANK1_CTX], - dev->fw_size, &dev->dma_base[BANK1_CTX], - GFP_KERNEL); - if (!dev->fw_virt_addr) { + fw_buf->virt = dma_alloc_coherent(dev->mem_dev[BANK1_CTX], fw_buf->size, +&fw_buf->dma, GFP_KERNEL); + if (!fw_buf->virt) { mfc_err("Allocating bitprocessor buffer failed\n"); return -ENOMEM; } + dev->dma_base[BANK1_CTX] = fw_buf->dma; if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { bank2_virt = dma_alloc_coherent(dev->mem_dev[BANK2_CTX], @@ -51,10 +52,9 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) if (!bank2_virt) { mfc_err("Allocating bank2 base failed\n"); - dma_free_coherent(dev->mem_dev[BANK1_CTX], dev->fw_size, - dev->fw_virt_addr, - dev->dma_base[BANK1_CTX]); - dev->fw_virt_addr = NULL; + dma_free_coherent(dev->mem_dev[BANK1_CTX], fw_buf->size, + fw_buf->virt, fw_buf->dma); + fw_buf->virt = NULL; return -ENOMEM; } @@ -101,17 +101,17 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; } - if (fw_blob->size > dev->fw_size) { + if (fw_blob->size > dev->fw_buf.size) { mfc_err("MFC firmware is too big to be loaded\n"); release_firmware(fw_blob); return -ENOMEM; } - if (!dev->fw_virt_addr) { + if (!dev->fw_buf.virt) { mfc_err("MFC firmware is not allocated\n"); release_firmware(fw_blob); return -EINVAL; } - memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size); + memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->
[PATCH v2 13/15] media: s5p-mfc: Remove special configuration of IOMMU domain
The main reason for using special configuration of IOMMU domain was the problem with MFC firmware, which failed to operate properly when placed at 0 DMA address. Instead of adding custom code for configuring each variant of IOMMU domain and architecture specific glue code, simply use what arch code provides and if the DMA base address equals zero, skip first 128 KiB to keep required alignment. This patch also make the driver operational on ARM64 architecture, because it no longer depends on ARM specific DMA-mapping and IOMMU glue code functions. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 30 +++ drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 51 +- 2 files changed, 14 insertions(+), 67 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 1c5ec8257f4f..b70cbd637851 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1184,18 +1184,6 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = &mfc_dev->plat_dev->dev; unsigned long mem_size = SZ_8M; unsigned int bitmap_size; - /* -* When IOMMU is available, we cannot use the default configuration, -* because of MFC firmware requirements: address space limited to -* 256M and non-zero default start address. -* This is still simplified, not optimal configuration, but for now -* IOMMU core doesn't allow to configure device's IOMMUs channel -* separately. -*/ - int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, -S5P_MFC_IOMMU_DMA_SIZE); - if (ret) - return ret; if (mfc_mem_size) mem_size = memparse(mfc_mem_size, NULL); @@ -1203,10 +1191,8 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long); mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!mfc_dev->mem_bitmap) { - exynos_unconfigure_iommu(dev); + if (!mfc_dev->mem_bitmap) return -ENOMEM; - } mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, &mfc_dev->mem_base, GFP_KERNEL); @@ -1214,13 +1200,24 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) kfree(mfc_dev->mem_bitmap); dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", (mem_size / SZ_1M)); - exynos_unconfigure_iommu(dev); return -ENOMEM; } mfc_dev->mem_size = mem_size; mfc_dev->dma_base[BANK1_CTX] = mfc_dev->mem_base; mfc_dev->dma_base[BANK2_CTX] = mfc_dev->mem_base; + /* +* MFC hardware cannot handle 0 as a base address, so mark first 128K +* as used (to keep required base alignment) and adjust base address +*/ + if (mfc_dev->mem_base == (dma_addr_t)0) { + unsigned int offset = 1 << MFC_BASE_ALIGN_ORDER; + + bitmap_set(mfc_dev->mem_bitmap, 0, offset >> PAGE_SHIFT); + mfc_dev->dma_base[BANK1_CTX] += offset; + mfc_dev->dma_base[BANK2_CTX] += offset; + } + /* Firmware allocation cannot fail in this case */ s5p_mfc_alloc_firmware(mfc_dev); @@ -1237,7 +1234,6 @@ static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; - exynos_unconfigure_iommu(dev); dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, mfc_dev->mem_base); kfree(mfc_dev->mem_bitmap); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h index 6962132ae8fa..76667924ee2a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h @@ -11,54 +11,13 @@ #ifndef S5P_MFC_IOMMU_H_ #define S5P_MFC_IOMMU_H_ -#define S5P_MFC_IOMMU_DMA_BASE 0x2000lu -#define S5P_MFC_IOMMU_DMA_SIZE SZ_256M - -#if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) - -#include +#if defined(CONFIG_EXYNOS_IOMMU) static inline bool exynos_is_iommu_available(struct device *dev) { return dev->archdata.iommu != NULL; } -static inline void exynos_unconfigure_iommu(struct device *dev) -{ - struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); - - arm_iommu_detach_device(dev); - arm_iommu_release_mapp
[PATCH v2 11/15] media: s5p-mfc: Split variant DMA memory configuration into separate functions
Move code for DMA memory configuration with IOMMU into separate function to make it easier to compare what is being done in each case. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 102 ++- 1 file changed, 61 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 4403487a494a..04067bcc3feb 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1107,44 +1107,15 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, return NULL; } -static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) +static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; void *bank2_virt; dma_addr_t bank2_dma_addr; unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; - struct s5p_mfc_priv_buf *fw_buf = &mfc_dev->fw_buf; int ret; /* -* When IOMMU is available, we cannot use the default configuration, -* because of MFC firmware requirements: address space limited to -* 256M and non-zero default start address. -* This is still simplified, not optimal configuration, but for now -* IOMMU core doesn't allow to configure device's IOMMUs channel -* separately. -*/ - if (exynos_is_iommu_available(dev)) { - int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, -S5P_MFC_IOMMU_DMA_SIZE); - if (ret) - return ret; - - mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; - ret = s5p_mfc_alloc_firmware(mfc_dev); - if (ret) { - exynos_unconfigure_iommu(dev); - return ret; - } - - mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; - mfc_dev->dma_base[BANK2_CTX] = fw_buf->dma; - vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); - - return 0; - } - - /* * Create and initialize virtual devices for accessing * reserved memory regions. */ @@ -1167,7 +1138,7 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return ret; } - mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; + mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma; bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, &bank2_dma_addr, GFP_KERNEL); @@ -1196,22 +1167,71 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return 0; } -static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) +static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) { - struct device *dev = &mfc_dev->plat_dev->dev; + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK2_CTX]); +} - s5p_mfc_release_firmware(mfc_dev); +static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + /* +* When IOMMU is available, we cannot use the default configuration, +* because of MFC firmware requirements: address space limited to +* 256M and non-zero default start address. +* This is still simplified, not optimal configuration, but for now +* IOMMU core doesn't allow to configure device's IOMMUs channel +* separately. +*/ + int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, +S5P_MFC_IOMMU_DMA_SIZE); + if (ret) + return ret; - if (exynos_is_iommu_available(dev)) { + mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { exynos_unconfigure_iommu(dev); - vb2_dma_contig_clear_max_seg_size(dev); - return; + return ret; } - device_unregister(mfc_dev->mem_dev[BANK1_CTX]); - device_unregister(mfc_dev->mem_dev[BANK2_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK1_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK2_CTX]); + mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma; + mfc_dev->dma_b
[PATCH v2 08/15] media: s5p-mfc: Move firmware allocation to DMA configure function
To complete DMA memory configuration for MFC device, allocation of the firmware buffer is needed, because some parameters are dependant on its base address. Till now, this has been handled in the s5p_mfc_alloc_firmware() function. This patch moves that logic to s5p_mfc_configure_dma_memory() to keep DMA memory related operations in a single place. This way s5p_mfc_alloc_firmware() is simplified and does what it name says. The other consequence of this change is moving s5p_mfc_alloc_firmware() call from the s5p_mfc_probe() function to the s5p_mfc_configure_dma_memory(). Signed-off-by: Marek Szyprowski --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 62 +-- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 31 -- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index bc1aeb25ebeb..4403487a494a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1110,6 +1110,11 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; + void *bank2_virt; + dma_addr_t bank2_dma_addr; + unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; + struct s5p_mfc_priv_buf *fw_buf = &mfc_dev->fw_buf; + int ret; /* * When IOMMU is available, we cannot use the default configuration, @@ -1122,14 +1127,21 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) if (exynos_is_iommu_available(dev)) { int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, S5P_MFC_IOMMU_DMA_SIZE); - if (ret == 0) { - mfc_dev->mem_dev[BANK1_CTX] = - mfc_dev->mem_dev[BANK2_CTX] = dev; - vb2_dma_contig_set_max_seg_size(dev, - DMA_BIT_MASK(32)); + if (ret) + return ret; + + mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { + exynos_unconfigure_iommu(dev); + return ret; } - return ret; + mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; + mfc_dev->dma_base[BANK2_CTX] = fw_buf->dma; + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); + + return 0; } /* @@ -1147,6 +1159,35 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) return -ENODEV; } + /* Allocate memory for firmware and initialize both banks addresses */ + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + return ret; + } + + mfc_dev->dma_base[BANK1_CTX] = fw_buf->dma; + + bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, + &bank2_dma_addr, GFP_KERNEL); + if (!bank2_virt) { + mfc_err("Allocating bank2 base failed\n"); + s5p_mfc_release_firmware(mfc_dev); + device_unregister(mfc_dev->mem_dev[BANK2_CTX]); + device_unregister(mfc_dev->mem_dev[BANK1_CTX]); + return -ENOMEM; + } + + /* Valid buffers passed to MFC encoder with LAST_FRAME command +* should not have address of bank2 - MFC will treat it as a null frame. +* To avoid such situation we set bank2 address below the pool address. +*/ + mfc_dev->dma_base[BANK2_CTX] = bank2_dma_addr - align_size; + + dma_free_coherent(mfc_dev->mem_dev[BANK2_CTX], align_size, bank2_virt, + bank2_dma_addr); + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK1_CTX], DMA_BIT_MASK(32)); vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK2_CTX], @@ -1159,6 +1200,8 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; + s5p_mfc_release_firmware(mfc_dev); + if (exynos_is_iommu_available(dev)) { exynos_unconfigure_iommu(dev); vb2_dma_contig_clear_max_seg_size(dev); @@ -1235,10 +1278,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) dev->watchdog_timer.data = (unsigned long)dev; dev->watchdog_timer.function = s5p_mfc_watch
[PATCH v2 15/15] ARM: dts: exynos: Remove MFC reserved buffers
During my research I found that some of the requirements for the memory buffers for MFC v6+ devices were blindly copied from the previous (v5) version and simply turned out to be excessive. The relaxed requirements are applied by the recent patches to the MFC driver and the driver is now fully functional even without the reserved memory blocks for all v6+ variants. This patch removes those reserved memory nodes from all boards having MFC v6+ hardware block. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- arch/arm/boot/dts/exynos5250-arndale.dts | 1 - arch/arm/boot/dts/exynos5250-smdk5250.dts | 1 - arch/arm/boot/dts/exynos5250-spring.dts| 1 - arch/arm/boot/dts/exynos5420-arndale-octa.dts | 1 - arch/arm/boot/dts/exynos5420-peach-pit.dts | 1 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 1 - arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 1 - arch/arm/boot/dts/exynos5800-peach-pi.dts | 1 - 8 files changed, 8 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index 6098dacd09f1..6a432460eb77 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -14,7 +14,6 @@ #include #include #include "exynos5250.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Insignal Arndale evaluation board based on EXYNOS5250"; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index a97a785ccc6b..6632f657394e 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -13,7 +13,6 @@ #include #include #include "exynos5250.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "SAMSUNG SMDK5250 board based on EXYNOS5250"; diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts index 4d7bdb735ed3..95c3bcace9dc 100644 --- a/arch/arm/boot/dts/exynos5250-spring.dts +++ b/arch/arm/boot/dts/exynos5250-spring.dts @@ -14,7 +14,6 @@ #include #include #include "exynos5250.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Google Spring"; diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts index 9cc83c51c925..ee1bb9b8b366 100644 --- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts +++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts @@ -16,7 +16,6 @@ #include #include #include -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Insignal Arndale Octa evaluation board based on EXYNOS5420"; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 1f964ec35c5e..2cd65699a29c 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -16,7 +16,6 @@ #include #include "exynos5420.dtsi" #include "exynos5420-cpus.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Google Peach Pit Rev 6+"; diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index aaccd0da41e5..08c8ab173e87 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -13,7 +13,6 @@ #include "exynos5420.dtsi" #include "exynos5420-cpus.dtsi" #include -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Samsung SMDK5420 board based on EXYNOS5420"; diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi index 05b9afdd6757..657535e2e3cc 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi @@ -18,7 +18,6 @@ #include #include "exynos5800.dtsi" #include "exynos5422-cpus.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { memory@4000 { diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index f9ff7f07ae0c..ecf1c916e8fc 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts @@ -16,7 +16,6 @@ #include #include "exynos5800.dtsi" #include "exynos5420-cpus.dtsi" -#include "exynos-mfc-reserved-memory.dtsi" / { model = "Google Peach Pi Rev 10+"; -- 1.9.1
[PATCH v2 14/15] media: s5p-mfc: Use preallocated block allocator always for MFC v6+
It turned out that all versions of MFC v6+ hardware doesn't have a strict requirement for ALL buffers to be allocated on higher addresses than the firmware base like it was documented for MFC v5. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Basing on this fact, the special DMA configuration based on two reserved memory regions is not really needed for MFC v6+ devices, because the memory requirements for the firmware, device and per-context buffers can be fulfilled by the simple probe-time pre-allocated block allocator instroduced in previous patch. This patch enables support for such pre-allocated block based allocator always for MFC v6+ devices. Due to the limitations of the memory management subsystem the largest supported size of the pre-allocated buffer when no CMA (Contiguous Memory Allocator) is enabled is 4MiB. This patch also removes the requirement to provide two reserved memory regions for MFC v6+ devices in device tree. Now the driver is fully functional without them. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- Documentation/devicetree/bindings/media/s5p-mfc.txt | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc.c| 9 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 2c901286d818..d3404b5d4d17 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -28,7 +28,7 @@ Optional properties: - memory-region : from reserved memory binding: phandles to two reserved memory regions, first is for "left" mfc memory bus interfaces, second if for the "right" mfc memory bus, used when no SYSMMU - support is available + support is available; used only by MFC v5 present in Exynos4 SoCs Obsolete properties: - samsung,mfc-r, samsung,mfc-l : support removed, please use memory-region diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index b70cbd637851..b4a13e4cc9d4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1182,9 +1182,12 @@ static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; - unsigned long mem_size = SZ_8M; + unsigned long mem_size = SZ_4M; unsigned int bitmap_size; + if (IS_ENABLED(CONFIG_DMA_CMA) || exynos_is_iommu_available(dev)) + mem_size = SZ_8M; + if (mfc_mem_size) mem_size = memparse(mfc_mem_size, NULL); @@ -1244,7 +1247,7 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; - if (exynos_is_iommu_available(dev)) + if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) return s5p_mfc_configure_common_memory(mfc_dev); else return s5p_mfc_configure_2port_memory(mfc_dev); @@ -1255,7 +1258,7 @@ static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = &mfc_dev->plat_dev->dev; s5p_mfc_release_firmware(mfc_dev); - if (exynos_is_iommu_available(dev)) + if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) s5p_mfc_unconfigure_common_memory(mfc_dev); else s5p_mfc_unconfigure_2port_memory(mfc_dev); -- 1.9.1
[PATCH v2 12/15] media: s5p-mfc: Add support for probe-time preallocated block based allocator
Current MFC driver depends on the fact that when IOMMU is available, the DMA-mapping framework and its IOMMU glue will use first-fit allocator. This was true for ARM architecture, but its not for ARM64 arch. However, in case of MFC v6+ hardware and latest firmware, it turned out that there is no strict requirement for ALL buffers to be allocated on higher addresses than the firmware base. This requirement is true only for the device and per-context buffers. All video data buffers can be allocated anywhere for all MFC v6+ versions. Such relaxed requirements for the memory buffers can be easily fulfilled by allocating firmware, device and per-context buffers from the probe-time preallocated larger buffer. This patch adds support for it. This way the driver finally works fine on ARM64 architecture. The size of the preallocated buffer is 8 MiB, what is enough for three instances H264 decoders or encoders (other codecs have smaller memory requirements). If one needs more for particular use case, one can use "mem" module parameter to force larger (or smaller) buffer (for example by adding "s5p_mfc.mem=16M" to kernel command line). Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas --- drivers/media/platform/s5p-mfc/s5p_mfc.c| 43 --- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 4 ++ drivers/media/platform/s5p-mfc/s5p_mfc_opr.c| 57 - 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 04067bcc3feb..1c5ec8257f4f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -43,6 +43,10 @@ module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); +static char *mfc_mem_size = NULL; +module_param_named(mem, mfc_mem_size, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(mem, "Preallocated memory size for the firmware and context buffers"); + /* Helper functions for interrupt processing */ /* Remove from hw execution round robin */ @@ -1178,6 +1182,8 @@ static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; + unsigned long mem_size = SZ_8M; + unsigned int bitmap_size; /* * When IOMMU is available, we cannot use the default configuration, * because of MFC firmware requirements: address space limited to @@ -1191,17 +1197,39 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) if (ret) return ret; - mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; - ret = s5p_mfc_alloc_firmware(mfc_dev); - if (ret) { + if (mfc_mem_size) + mem_size = memparse(mfc_mem_size, NULL); + + bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long); + + mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!mfc_dev->mem_bitmap) { exynos_unconfigure_iommu(dev); - return ret; + return -ENOMEM; } - mfc_dev->dma_base[BANK1_CTX] = mfc_dev->fw_buf.dma; - mfc_dev->dma_base[BANK2_CTX] = mfc_dev->fw_buf.dma; + mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, + &mfc_dev->mem_base, GFP_KERNEL); + if (!mfc_dev->mem_virt) { + kfree(mfc_dev->mem_bitmap); + dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", + (mem_size / SZ_1M)); + exynos_unconfigure_iommu(dev); + return -ENOMEM; + } + mfc_dev->mem_size = mem_size; + mfc_dev->dma_base[BANK1_CTX] = mfc_dev->mem_base; + mfc_dev->dma_base[BANK2_CTX] = mfc_dev->mem_base; + + /* Firmware allocation cannot fail in this case */ + s5p_mfc_alloc_firmware(mfc_dev); + + mfc_dev->mem_dev[BANK1_CTX] = mfc_dev->mem_dev[BANK2_CTX] = dev; vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dev_info(dev, "preallocated %ld MiB buffer for the firmware and context buffers\n", +(mem_size / SZ_1M)); + return 0; } @@ -1210,6 +1238,9 @@ static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = &mfc_dev->plat_dev->dev; exynos_unconfigure_iommu(dev); + dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, + mfc_dev->mem_base); + kfree(mfc_dev->mem_bitmap); vb2