OSDN Git Service

media: stm32-dcmi: fix DMA corruption when stopping streaming
authorHugues Fruchet <hugues.fruchet@st.com>
Thu, 28 Feb 2019 17:10:53 +0000 (12:10 -0500)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Tue, 19 Mar 2019 17:50:08 +0000 (13:50 -0400)
Avoid call of dmaengine_terminate_all() between
dmaengine_prep_slave_single() and dmaengine_submit() by locking
the whole DMA submission sequence.

Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/platform/stm32/stm32-dcmi.c

index 37e9fb0..098431d 100644 (file)
@@ -164,6 +164,9 @@ struct stm32_dcmi {
        int                             errors_count;
        int                             overrun_count;
        int                             buffers_count;
+
+       /* Ensure DMA operations atomicity */
+       struct mutex                    dma_lock;
 };
 
 static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n)
@@ -314,6 +317,13 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
                return ret;
        }
 
+       /*
+        * Avoid call of dmaengine_terminate_all() between
+        * dmaengine_prep_slave_single() and dmaengine_submit()
+        * by locking the whole DMA submission sequence
+        */
+       mutex_lock(&dcmi->dma_lock);
+
        /* Prepare a DMA transaction */
        desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr,
                                           buf->size,
@@ -322,6 +332,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
        if (!desc) {
                dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n",
                        __func__, &buf->paddr, buf->size);
+               mutex_unlock(&dcmi->dma_lock);
                return -EINVAL;
        }
 
@@ -333,9 +344,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
        dcmi->dma_cookie = dmaengine_submit(desc);
        if (dma_submit_error(dcmi->dma_cookie)) {
                dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
+               mutex_unlock(&dcmi->dma_lock);
                return -ENXIO;
        }
 
+       mutex_unlock(&dcmi->dma_lock);
+
        dma_async_issue_pending(dcmi->dma_chan);
 
        return 0;
@@ -720,7 +734,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
        spin_unlock_irq(&dcmi->irqlock);
 
        /* Stop all pending DMA operations */
+       mutex_lock(&dcmi->dma_lock);
        dmaengine_terminate_all(dcmi->dma_chan);
+       mutex_unlock(&dcmi->dma_lock);
 
        pm_runtime_put(dcmi->dev);
 
@@ -1711,6 +1727,7 @@ static int dcmi_probe(struct platform_device *pdev)
 
        spin_lock_init(&dcmi->irqlock);
        mutex_init(&dcmi->lock);
+       mutex_init(&dcmi->dma_lock);
        init_completion(&dcmi->complete);
        INIT_LIST_HEAD(&dcmi->buffers);