]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
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)
committerMarcelo Henrique Cerri <marcelo.cerri@canonical.com>
Fri, 17 Jan 2020 17:21:49 +0000 (14:21 -0300)
BugLink: https://bugs.launchpad.net/bugs/1855787
commit b3ce6f6ff3c260ee53b0f2236e5fd950d46957da upstream.

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>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/media/platform/stm32/stm32-dcmi.c

index 969330fd252de36a7612a17ad8176eff1cd2c3c8..edbf553820f7159c5ef87916295a0177cafaa004 100644 (file)
@@ -161,6 +161,9 @@ struct stm32_dcmi {
        u32                             misr;
        int                             errors_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)
@@ -291,6 +294,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,
@@ -298,6 +308,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 size %zu\n",
                        __func__, buf->size);
+               mutex_unlock(&dcmi->dma_lock);
                return -EINVAL;
        }
 
@@ -309,9 +320,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;
@@ -690,7 +704,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);
 
        clk_disable(dcmi->mclk);
 
@@ -1668,6 +1684,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);