media: stm32-dcmi: fix DMA corruption when stopping streaming
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>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
ab41b99e7e
commit
b3ce6f6ff3
@@ -164,6 +164,9 @@ struct stm32_dcmi {
|
|||||||
int errors_count;
|
int errors_count;
|
||||||
int overrun_count;
|
int overrun_count;
|
||||||
int buffers_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)
|
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;
|
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 */
|
/* Prepare a DMA transaction */
|
||||||
desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr,
|
desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr,
|
||||||
buf->size,
|
buf->size,
|
||||||
@@ -322,6 +332,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
|
|||||||
if (!desc) {
|
if (!desc) {
|
||||||
dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n",
|
dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n",
|
||||||
__func__, &buf->paddr, buf->size);
|
__func__, &buf->paddr, buf->size);
|
||||||
|
mutex_unlock(&dcmi->dma_lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,9 +344,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
|
|||||||
dcmi->dma_cookie = dmaengine_submit(desc);
|
dcmi->dma_cookie = dmaengine_submit(desc);
|
||||||
if (dma_submit_error(dcmi->dma_cookie)) {
|
if (dma_submit_error(dcmi->dma_cookie)) {
|
||||||
dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
|
dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
|
||||||
|
mutex_unlock(&dcmi->dma_lock);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&dcmi->dma_lock);
|
||||||
|
|
||||||
dma_async_issue_pending(dcmi->dma_chan);
|
dma_async_issue_pending(dcmi->dma_chan);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -720,7 +734,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
|
|||||||
spin_unlock_irq(&dcmi->irqlock);
|
spin_unlock_irq(&dcmi->irqlock);
|
||||||
|
|
||||||
/* Stop all pending DMA operations */
|
/* Stop all pending DMA operations */
|
||||||
|
mutex_lock(&dcmi->dma_lock);
|
||||||
dmaengine_terminate_all(dcmi->dma_chan);
|
dmaengine_terminate_all(dcmi->dma_chan);
|
||||||
|
mutex_unlock(&dcmi->dma_lock);
|
||||||
|
|
||||||
pm_runtime_put(dcmi->dev);
|
pm_runtime_put(dcmi->dev);
|
||||||
|
|
||||||
@@ -1711,6 +1727,7 @@ static int dcmi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
spin_lock_init(&dcmi->irqlock);
|
spin_lock_init(&dcmi->irqlock);
|
||||||
mutex_init(&dcmi->lock);
|
mutex_init(&dcmi->lock);
|
||||||
|
mutex_init(&dcmi->dma_lock);
|
||||||
init_completion(&dcmi->complete);
|
init_completion(&dcmi->complete);
|
||||||
INIT_LIST_HEAD(&dcmi->buffers);
|
INIT_LIST_HEAD(&dcmi->buffers);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user