diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2014-07-30 19:08:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-30 20:16:13 -0400 |
commit | 0193ed8225e1a79ed64632106ec3cc81798cb13c (patch) | |
tree | 130e54dc330c11d9e7baf1fe54f9cb84139f1a13 /drivers/rapidio/devices | |
parent | b104a35d32025ca740539db2808aa3385d0f30eb (diff) |
rapidio/tsi721_dma: fix failure to obtain transaction descriptor
This is a bug fix for the situation when function tsi721_desc_get() fails
to obtain a free transaction descriptor.
The bug usually results in a memory access crash dump when data transfer
scatter-gather list has more entries than size of hardware buffer
descriptors ring. This fix ensures that error is properly returned to a
caller instead of an invalid entry.
This patch is applicable to kernel versions starting from v3.5.
Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: <stable@vger.kernel.org> [3.5+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio/devices')
-rw-r--r-- | drivers/rapidio/devices/tsi721_dma.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c index 9b60b1f3261c..44341dc5b148 100644 --- a/drivers/rapidio/devices/tsi721_dma.c +++ b/drivers/rapidio/devices/tsi721_dma.c | |||
@@ -287,6 +287,12 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan) | |||
287 | "desc %p not ACKed\n", tx_desc); | 287 | "desc %p not ACKed\n", tx_desc); |
288 | } | 288 | } |
289 | 289 | ||
290 | if (ret == NULL) { | ||
291 | dev_dbg(bdma_chan->dchan.device->dev, | ||
292 | "%s: unable to obtain tx descriptor\n", __func__); | ||
293 | goto err_out; | ||
294 | } | ||
295 | |||
290 | i = bdma_chan->wr_count_next % bdma_chan->bd_num; | 296 | i = bdma_chan->wr_count_next % bdma_chan->bd_num; |
291 | if (i == bdma_chan->bd_num - 1) { | 297 | if (i == bdma_chan->bd_num - 1) { |
292 | i = 0; | 298 | i = 0; |
@@ -297,7 +303,7 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan) | |||
297 | tx_desc->txd.phys = bdma_chan->bd_phys + | 303 | tx_desc->txd.phys = bdma_chan->bd_phys + |
298 | i * sizeof(struct tsi721_dma_desc); | 304 | i * sizeof(struct tsi721_dma_desc); |
299 | tx_desc->hw_desc = &((struct tsi721_dma_desc *)bdma_chan->bd_base)[i]; | 305 | tx_desc->hw_desc = &((struct tsi721_dma_desc *)bdma_chan->bd_base)[i]; |
300 | 306 | err_out: | |
301 | spin_unlock_bh(&bdma_chan->lock); | 307 | spin_unlock_bh(&bdma_chan->lock); |
302 | 308 | ||
303 | return ret; | 309 | return ret; |