| From 9c58697b70610e0fd108bd31cf76595f3d8f7b56 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 3 Mar 2020 14:05:18 +0100 |
| Subject: dmaengine: xilinx_dma: Add missing check for empty list |
| |
| From: Sebastian von Ohr <vonohr@smaract.com> |
| |
| [ Upstream commit b269426011bcfd97b7c3101abfe1a99147b6f40b ] |
| |
| The DMA transfer might finish just after checking the state with |
| dma_cookie_status, but before the lock is acquired. Not checking |
| for an empty list in xilinx_dma_tx_status may result in reading |
| random data or data corruption when desc is written to. This can |
| be reliably triggered by using dma_sync_wait to wait for DMA |
| completion. |
| |
| Signed-off-by: Sebastian von Ohr <vonohr@smaract.com> |
| Tested-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com> |
| Link: https://lore.kernel.org/r/20200303130518.333-1-vonohr@smaract.com |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/dma/xilinx/xilinx_dma.c | 20 ++++++++++---------- |
| 1 file changed, 10 insertions(+), 10 deletions(-) |
| |
| diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c |
| index a9c5d5cc9f2bd..5d5f1d0ce16cb 100644 |
| --- a/drivers/dma/xilinx/xilinx_dma.c |
| +++ b/drivers/dma/xilinx/xilinx_dma.c |
| @@ -1229,16 +1229,16 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan, |
| return ret; |
| |
| spin_lock_irqsave(&chan->lock, flags); |
| - |
| - desc = list_last_entry(&chan->active_list, |
| - struct xilinx_dma_tx_descriptor, node); |
| - /* |
| - * VDMA and simple mode do not support residue reporting, so the |
| - * residue field will always be 0. |
| - */ |
| - if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA) |
| - residue = xilinx_dma_get_residue(chan, desc); |
| - |
| + if (!list_empty(&chan->active_list)) { |
| + desc = list_last_entry(&chan->active_list, |
| + struct xilinx_dma_tx_descriptor, node); |
| + /* |
| + * VDMA and simple mode do not support residue reporting, so the |
| + * residue field will always be 0. |
| + */ |
| + if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA) |
| + residue = xilinx_dma_get_residue(chan, desc); |
| + } |
| spin_unlock_irqrestore(&chan->lock, flags); |
| |
| dma_set_residue(txstate, residue); |
| -- |
| 2.20.1 |
| |