Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20698c92 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'dmaengine-fix-4.5' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine fixes from Vinod Koul:
 "Two fixes showed up in last few days, and they should be included in
  4.5.  Summary:

  Two more late fixes to drivers, nothing major here:

   - A memory leak fix in fsdma unmap the dma descriptors on freeup

   - A fix in xdmac driver for residue calculation of dma descriptor"

* tag 'dmaengine-fix-4.5' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: at_xdmac: fix residue computation
  dmaengine: fsldma: fix memory leak
parents 7ae9c768 25c5e962
Loading
Loading
Loading
Loading
+39 −3
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@
#define AT_XDMAC_MAX_CHAN	0x20
#define AT_XDMAC_MAX_CSIZE	16	/* 16 data */
#define AT_XDMAC_MAX_DWIDTH	8	/* 64 bits */
#define AT_XDMAC_RESIDUE_MAX_RETRIES	5

#define AT_XDMAC_DMA_BUSWIDTHS\
	(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
@@ -1395,8 +1396,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
	struct at_xdmac_desc	*desc, *_desc;
	struct list_head	*descs_list;
	enum dma_status		ret;
	int			residue;
	u32			cur_nda, mask, value;
	int			residue, retry;
	u32			cur_nda, check_nda, cur_ubc, mask, value;
	u8			dwidth = 0;
	unsigned long		flags;

@@ -1433,7 +1434,42 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
			cpu_relax();
	}

	/*
	 * When processing the residue, we need to read two registers but we
	 * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where
	 * we stand in the descriptor list and AT_XDMAC_CUBC is used
	 * to know how many data are remaining for the current descriptor.
	 * Since the dma channel is not paused to not loose data, between the
	 * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of
	 * descriptor.
	 * For that reason, after reading AT_XDMAC_CUBC, we check if we are
	 * still using the same descriptor by reading a second time
	 * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to
	 * read again AT_XDMAC_CUBC.
	 * Memory barriers are used to ensure the read order of the registers.
	 * A max number of retries is set because unlikely it can never ends if
	 * we are transferring a lot of data with small buffers.
	 */
	cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
	rmb();
	cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
	for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
		rmb();
		check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;

		if (likely(cur_nda == check_nda))
			break;

		cur_nda = check_nda;
		rmb();
		cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
	}

	if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) {
		ret = DMA_ERROR;
		goto spin_unlock;
	}

	/*
	 * Remove size of all microblocks already transferred and the current
	 * one. Then add the remaining size to transfer of the current
@@ -1446,7 +1482,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
		if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
			break;
	}
	residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth;
	residue += cur_ubc << dwidth;

	dma_set_residue(txstate, residue);

+2 −0
Original line number Diff line number Diff line
@@ -522,6 +522,8 @@ static dma_cookie_t fsldma_run_tx_complete_actions(struct fsldma_chan *chan,
			chan_dbg(chan, "LD %p callback\n", desc);
			txd->callback(txd->callback_param);
		}

		dma_descriptor_unmap(txd);
	}

	/* Run any dependencies */