| From 7667819385457b4aeb5fac94f67f52ab52cc10d5 Mon Sep 17 00:00:00 2001 |
| From: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> |
| Date: Thu, 17 Oct 2019 08:26:06 -0700 |
| Subject: dmaengine: qcom: bam_dma: Fix resource leak |
| |
| From: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> |
| |
| commit 7667819385457b4aeb5fac94f67f52ab52cc10d5 upstream. |
| |
| bam_dma_terminate_all() will leak resources if any of the transactions are |
| committed to the hardware (present in the desc fifo), and not complete. |
| Since bam_dma_terminate_all() does not cause the hardware to be updated, |
| the hardware will still operate on any previously committed transactions. |
| This can cause memory corruption if the memory for the transaction has been |
| reassigned, and will cause a sync issue between the BAM and its client(s). |
| |
| Fix this by properly updating the hardware in bam_dma_terminate_all(). |
| |
| Fixes: e7c0fe2a5c84 ("dmaengine: add Qualcomm BAM dma driver") |
| Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> |
| Cc: stable@vger.kernel.org |
| Link: https://lore.kernel.org/r/20191017152606.34120-1-jeffrey.l.hugo@gmail.com |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/dma/qcom/bam_dma.c | 19 +++++++++++++++++++ |
| 1 file changed, 19 insertions(+) |
| |
| --- a/drivers/dma/qcom/bam_dma.c |
| +++ b/drivers/dma/qcom/bam_dma.c |
| @@ -694,6 +694,25 @@ static int bam_dma_terminate_all(struct |
| |
| /* remove all transactions, including active transaction */ |
| spin_lock_irqsave(&bchan->vc.lock, flag); |
| + /* |
| + * If we have transactions queued, then some might be committed to the |
| + * hardware in the desc fifo. The only way to reset the desc fifo is |
| + * to do a hardware reset (either by pipe or the entire block). |
| + * bam_chan_init_hw() will trigger a pipe reset, and also reinit the |
| + * pipe. If the pipe is left disabled (default state after pipe reset) |
| + * and is accessed by a connected hardware engine, a fatal error in |
| + * the BAM will occur. There is a small window where this could happen |
| + * with bam_chan_init_hw(), but it is assumed that the caller has |
| + * stopped activity on any attached hardware engine. Make sure to do |
| + * this first so that the BAM hardware doesn't cause memory corruption |
| + * by accessing freed resources. |
| + */ |
| + if (!list_empty(&bchan->desc_list)) { |
| + async_desc = list_first_entry(&bchan->desc_list, |
| + struct bam_async_desc, desc_node); |
| + bam_chan_init_hw(bchan, async_desc->dir); |
| + } |
| + |
| list_for_each_entry_safe(async_desc, tmp, |
| &bchan->desc_list, desc_node) { |
| list_add(&async_desc->vd.node, &bchan->vc.desc_issued); |