Refresh patches for all targets that support kernel 4.4. Compile-tested on all targets that use kernel 4.4 and aren't marked broken. Runtime-tested on ar71xx, octeon and x86/64. Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
		
			
				
	
	
		
			1518 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1518 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 | 
						|
Subject: [PATCH v6 0/4] Fixes / cleanups in dw_dmac (affects on few subsystems)
 | 
						|
Date: Mon, 25 Apr 2016 15:35:05 +0300
 | 
						|
 | 
						|
This patch series (v3: http://www.spinics.net/lists/kernel/msg2215303.html)
 | 
						|
contains a number of mostly minor fixes and cleanups for the DW DMA driver. A
 | 
						|
couple of them affect the DT binding so these may need to be updated to
 | 
						|
maintain compatibility (old format is still supported though). The rest should
 | 
						|
be relatively straight-forward.
 | 
						|
 | 
						|
This version has been tested on the following bare metal platforms:
 | 
						|
- ATNGW100 (avr32 based platform) with dmatest
 | 
						|
- Sam460ex (powerpc 44x based platform) with SATA
 | 
						|
- Intel Braswell with UART
 | 
						|
- Intel Galileo (Intel Quark based platform) with UART
 | 
						|
 | 
						|
(SATA driver and Intel Galileo UART support are based on this series and just
 | 
						|
 published recently for a review)
 | 
						|
 | 
						|
Vinod, there are few patch sets developed on top of this one, so, the idea is
 | 
						|
to keep this in an immuutable branch / tag.
 | 
						|
 | 
						|
Changes since v5:
 | 
						|
- fixed an issue found by kbuildbot
 | 
						|
 | 
						|
Changes since v4:
 | 
						|
- send proper set of patches
 | 
						|
- add changelog
 | 
						|
 | 
						|
Changes since v3:
 | 
						|
- add patch 1 to check value of dma-masters property
 | 
						|
- drop the upstreamed patches
 | 
						|
- update patch 2 to keep an array for data-width property as well
 | 
						|
 | 
						|
Changes since v2:
 | 
						|
- add patch 1 to fix master selection which was broken for long time
 | 
						|
- remove "use field-by-field initialization" patch since like Mans metioned in
 | 
						|
  has mostly no value and even might increase error prone
 | 
						|
- rebase on top of recent linux-next
 | 
						|
- wide testing on several platforms
 | 
						|
 | 
						|
Changes since v1:
 | 
						|
- zeroing struct dw_dma_slave before use
 | 
						|
- fall back to old data_width property if data-width is not found
 | 
						|
- append tags for few patches
 | 
						|
- correct title of cover letter
 | 
						|
- rebase on top of recent linux-next
 | 
						|
 | 
						|
Andy Shevchenko (4):
 | 
						|
  dmaengine: dw: platform: check nr_masters to be non-zero
 | 
						|
  dmaengine: dw: revisit data_width property
 | 
						|
  dmaengine: dw: keep entire platform data in struct dw_dma
 | 
						|
  dmaengine: dw: pass platform data via struct dw_dma_chip
 | 
						|
 | 
						|
 Documentation/devicetree/bindings/dma/snps-dma.txt |  6 +-
 | 
						|
 arch/arc/boot/dts/abilis_tb10x.dtsi                |  2 +-
 | 
						|
 arch/arm/boot/dts/spear13xx.dtsi                   |  4 +-
 | 
						|
 drivers/ata/sata_dwc_460ex.c                       |  2 +-
 | 
						|
 drivers/dma/dw/core.c                              | 75 ++++++++--------------
 | 
						|
 drivers/dma/dw/pci.c                               |  5 +-
 | 
						|
 drivers/dma/dw/platform.c                          | 32 +++++----
 | 
						|
 drivers/dma/dw/regs.h                              |  5 +-
 | 
						|
 include/linux/dma/dw.h                             |  5 +-
 | 
						|
 include/linux/platform_data/dma-dw.h               |  4 +-
 | 
						|
 sound/soc/intel/common/sst-firmware.c              |  2 +-
 | 
						|
 11 files changed, 64 insertions(+), 78 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/dma/dw/core.c
 | 
						|
+++ b/drivers/dma/dw/core.c
 | 
						|
@@ -45,22 +45,19 @@
 | 
						|
 			DW_DMA_MSIZE_16;			\
 | 
						|
 		u8 _dmsize = _is_slave ? _sconfig->dst_maxburst :	\
 | 
						|
 			DW_DMA_MSIZE_16;			\
 | 
						|
+		u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ?		\
 | 
						|
+			_dwc->p_master : _dwc->m_master;		\
 | 
						|
+		u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ?		\
 | 
						|
+			_dwc->p_master : _dwc->m_master;		\
 | 
						|
 								\
 | 
						|
 		(DWC_CTLL_DST_MSIZE(_dmsize)			\
 | 
						|
 		 | DWC_CTLL_SRC_MSIZE(_smsize)			\
 | 
						|
 		 | DWC_CTLL_LLP_D_EN				\
 | 
						|
 		 | DWC_CTLL_LLP_S_EN				\
 | 
						|
-		 | DWC_CTLL_DMS(_dwc->dst_master)		\
 | 
						|
-		 | DWC_CTLL_SMS(_dwc->src_master));		\
 | 
						|
+		 | DWC_CTLL_DMS(_dms)				\
 | 
						|
+		 | DWC_CTLL_SMS(_sms));				\
 | 
						|
 	})
 | 
						|
 
 | 
						|
-/*
 | 
						|
- * Number of descriptors to allocate for each channel. This should be
 | 
						|
- * made configurable somehow; preferably, the clients (at least the
 | 
						|
- * ones using slave transfers) should be able to give us a hint.
 | 
						|
- */
 | 
						|
-#define NR_DESCS_PER_CHANNEL	64
 | 
						|
-
 | 
						|
 /* The set of bus widths supported by the DMA controller */
 | 
						|
 #define DW_DMA_BUSWIDTHS			  \
 | 
						|
 	BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED)	| \
 | 
						|
@@ -80,51 +77,65 @@ static struct dw_desc *dwc_first_active(
 | 
						|
 	return to_dw_desc(dwc->active_list.next);
 | 
						|
 }
 | 
						|
 
 | 
						|
-static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
 | 
						|
+static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
 | 
						|
 {
 | 
						|
-	struct dw_desc *desc, *_desc;
 | 
						|
-	struct dw_desc *ret = NULL;
 | 
						|
-	unsigned int i = 0;
 | 
						|
-	unsigned long flags;
 | 
						|
+	struct dw_desc		*desc = txd_to_dw_desc(tx);
 | 
						|
+	struct dw_dma_chan	*dwc = to_dw_dma_chan(tx->chan);
 | 
						|
+	dma_cookie_t		cookie;
 | 
						|
+	unsigned long		flags;
 | 
						|
 
 | 
						|
 	spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
-	list_for_each_entry_safe(desc, _desc, &dwc->free_list, desc_node) {
 | 
						|
-		i++;
 | 
						|
-		if (async_tx_test_ack(&desc->txd)) {
 | 
						|
-			list_del(&desc->desc_node);
 | 
						|
-			ret = desc;
 | 
						|
-			break;
 | 
						|
-		}
 | 
						|
-		dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc);
 | 
						|
-	}
 | 
						|
+	cookie = dma_cookie_assign(tx);
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * REVISIT: We should attempt to chain as many descriptors as
 | 
						|
+	 * possible, perhaps even appending to those already submitted
 | 
						|
+	 * for DMA. But this is hard to do in a race-free manner.
 | 
						|
+	 */
 | 
						|
+
 | 
						|
+	list_add_tail(&desc->desc_node, &dwc->queue);
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
+	dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n",
 | 
						|
+		 __func__, desc->txd.cookie);
 | 
						|
 
 | 
						|
-	dev_vdbg(chan2dev(&dwc->chan), "scanned %u descriptors on freelist\n", i);
 | 
						|
+	return cookie;
 | 
						|
+}
 | 
						|
 
 | 
						|
-	return ret;
 | 
						|
+static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
 | 
						|
+{
 | 
						|
+	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
 | 
						|
+	struct dw_desc *desc;
 | 
						|
+	dma_addr_t phys;
 | 
						|
+
 | 
						|
+	desc = dma_pool_zalloc(dw->desc_pool, GFP_ATOMIC, &phys);
 | 
						|
+	if (!desc)
 | 
						|
+		return NULL;
 | 
						|
+
 | 
						|
+	dwc->descs_allocated++;
 | 
						|
+	INIT_LIST_HEAD(&desc->tx_list);
 | 
						|
+	dma_async_tx_descriptor_init(&desc->txd, &dwc->chan);
 | 
						|
+	desc->txd.tx_submit = dwc_tx_submit;
 | 
						|
+	desc->txd.flags = DMA_CTRL_ACK;
 | 
						|
+	desc->txd.phys = phys;
 | 
						|
+	return desc;
 | 
						|
 }
 | 
						|
 
 | 
						|
-/*
 | 
						|
- * Move a descriptor, including any children, to the free list.
 | 
						|
- * `desc' must not be on any lists.
 | 
						|
- */
 | 
						|
 static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
 | 
						|
 {
 | 
						|
-	unsigned long flags;
 | 
						|
+	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
 | 
						|
+	struct dw_desc *child, *_next;
 | 
						|
 
 | 
						|
-	if (desc) {
 | 
						|
-		struct dw_desc *child;
 | 
						|
+	if (unlikely(!desc))
 | 
						|
+		return;
 | 
						|
 
 | 
						|
-		spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
-		list_for_each_entry(child, &desc->tx_list, desc_node)
 | 
						|
-			dev_vdbg(chan2dev(&dwc->chan),
 | 
						|
-					"moving child desc %p to freelist\n",
 | 
						|
-					child);
 | 
						|
-		list_splice_init(&desc->tx_list, &dwc->free_list);
 | 
						|
-		dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc);
 | 
						|
-		list_add(&desc->desc_node, &dwc->free_list);
 | 
						|
-		spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
+	list_for_each_entry_safe(child, _next, &desc->tx_list, desc_node) {
 | 
						|
+		list_del(&child->desc_node);
 | 
						|
+		dma_pool_free(dw->desc_pool, child, child->txd.phys);
 | 
						|
+		dwc->descs_allocated--;
 | 
						|
 	}
 | 
						|
+
 | 
						|
+	dma_pool_free(dw->desc_pool, desc, desc->txd.phys);
 | 
						|
+	dwc->descs_allocated--;
 | 
						|
 }
 | 
						|
 
 | 
						|
 static void dwc_initialize(struct dw_dma_chan *dwc)
 | 
						|
@@ -133,7 +144,7 @@ static void dwc_initialize(struct dw_dma
 | 
						|
 	u32 cfghi = DWC_CFGH_FIFO_MODE;
 | 
						|
 	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
 | 
						|
 
 | 
						|
-	if (dwc->initialized == true)
 | 
						|
+	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
 | 
						|
 		return;
 | 
						|
 
 | 
						|
 	cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
 | 
						|
@@ -146,26 +157,11 @@ static void dwc_initialize(struct dw_dma
 | 
						|
 	channel_set_bit(dw, MASK.XFER, dwc->mask);
 | 
						|
 	channel_set_bit(dw, MASK.ERROR, dwc->mask);
 | 
						|
 
 | 
						|
-	dwc->initialized = true;
 | 
						|
+	set_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
 | 
						|
 }
 | 
						|
 
 | 
						|
 /*----------------------------------------------------------------------*/
 | 
						|
 
 | 
						|
-static inline unsigned int dwc_fast_ffs(unsigned long long v)
 | 
						|
-{
 | 
						|
-	/*
 | 
						|
-	 * We can be a lot more clever here, but this should take care
 | 
						|
-	 * of the most common optimization.
 | 
						|
-	 */
 | 
						|
-	if (!(v & 7))
 | 
						|
-		return 3;
 | 
						|
-	else if (!(v & 3))
 | 
						|
-		return 2;
 | 
						|
-	else if (!(v & 1))
 | 
						|
-		return 1;
 | 
						|
-	return 0;
 | 
						|
-}
 | 
						|
-
 | 
						|
 static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
 | 
						|
 {
 | 
						|
 	dev_err(chan2dev(&dwc->chan),
 | 
						|
@@ -197,12 +193,12 @@ static inline void dwc_do_single_block(s
 | 
						|
 	 * Software emulation of LLP mode relies on interrupts to continue
 | 
						|
 	 * multi block transfer.
 | 
						|
 	 */
 | 
						|
-	ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
 | 
						|
+	ctllo = lli_read(desc, ctllo) | DWC_CTLL_INT_EN;
 | 
						|
 
 | 
						|
-	channel_writel(dwc, SAR, desc->lli.sar);
 | 
						|
-	channel_writel(dwc, DAR, desc->lli.dar);
 | 
						|
+	channel_writel(dwc, SAR, lli_read(desc, sar));
 | 
						|
+	channel_writel(dwc, DAR, lli_read(desc, dar));
 | 
						|
 	channel_writel(dwc, CTL_LO, ctllo);
 | 
						|
-	channel_writel(dwc, CTL_HI, desc->lli.ctlhi);
 | 
						|
+	channel_writel(dwc, CTL_HI, lli_read(desc, ctlhi));
 | 
						|
 	channel_set_bit(dw, CH_EN, dwc->mask);
 | 
						|
 
 | 
						|
 	/* Move pointer to next descriptor */
 | 
						|
@@ -213,6 +209,7 @@ static inline void dwc_do_single_block(s
 | 
						|
 static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 | 
						|
 {
 | 
						|
 	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
 | 
						|
+	u8		lms = DWC_LLP_LMS(dwc->m_master);
 | 
						|
 	unsigned long	was_soft_llp;
 | 
						|
 
 | 
						|
 	/* ASSERT:  channel is idle */
 | 
						|
@@ -237,7 +234,7 @@ static void dwc_dostart(struct dw_dma_ch
 | 
						|
 
 | 
						|
 		dwc_initialize(dwc);
 | 
						|
 
 | 
						|
-		dwc->residue = first->total_len;
 | 
						|
+		first->residue = first->total_len;
 | 
						|
 		dwc->tx_node_active = &first->tx_list;
 | 
						|
 
 | 
						|
 		/* Submit first block */
 | 
						|
@@ -248,9 +245,8 @@ static void dwc_dostart(struct dw_dma_ch
 | 
						|
 
 | 
						|
 	dwc_initialize(dwc);
 | 
						|
 
 | 
						|
-	channel_writel(dwc, LLP, first->txd.phys);
 | 
						|
-	channel_writel(dwc, CTL_LO,
 | 
						|
-			DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
 | 
						|
+	channel_writel(dwc, LLP, first->txd.phys | lms);
 | 
						|
+	channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
 | 
						|
 	channel_writel(dwc, CTL_HI, 0);
 | 
						|
 	channel_set_bit(dw, CH_EN, dwc->mask);
 | 
						|
 }
 | 
						|
@@ -293,11 +289,7 @@ dwc_descriptor_complete(struct dw_dma_ch
 | 
						|
 	list_for_each_entry(child, &desc->tx_list, desc_node)
 | 
						|
 		async_tx_ack(&child->txd);
 | 
						|
 	async_tx_ack(&desc->txd);
 | 
						|
-
 | 
						|
-	list_splice_init(&desc->tx_list, &dwc->free_list);
 | 
						|
-	list_move(&desc->desc_node, &dwc->free_list);
 | 
						|
-
 | 
						|
-	dma_descriptor_unmap(txd);
 | 
						|
+	dwc_desc_put(dwc, desc);
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 
 | 
						|
 	if (callback)
 | 
						|
@@ -368,11 +360,11 @@ static void dwc_scan_descriptors(struct
 | 
						|
 
 | 
						|
 			head = &desc->tx_list;
 | 
						|
 			if (active != head) {
 | 
						|
-				/* Update desc to reflect last sent one */
 | 
						|
-				if (active != head->next)
 | 
						|
-					desc = to_dw_desc(active->prev);
 | 
						|
-
 | 
						|
-				dwc->residue -= desc->len;
 | 
						|
+				/* Update residue to reflect last sent descriptor */
 | 
						|
+				if (active == head->next)
 | 
						|
+					desc->residue -= desc->len;
 | 
						|
+				else
 | 
						|
+					desc->residue -= to_dw_desc(active->prev)->len;
 | 
						|
 
 | 
						|
 				child = to_dw_desc(active);
 | 
						|
 
 | 
						|
@@ -387,8 +379,6 @@ static void dwc_scan_descriptors(struct
 | 
						|
 			clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
 | 
						|
 		}
 | 
						|
 
 | 
						|
-		dwc->residue = 0;
 | 
						|
-
 | 
						|
 		spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 
 | 
						|
 		dwc_complete_all(dw, dwc);
 | 
						|
@@ -396,7 +386,6 @@ static void dwc_scan_descriptors(struct
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	if (list_empty(&dwc->active_list)) {
 | 
						|
-		dwc->residue = 0;
 | 
						|
 		spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 		return;
 | 
						|
 	}
 | 
						|
@@ -411,31 +400,31 @@ static void dwc_scan_descriptors(struct
 | 
						|
 
 | 
						|
 	list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
 | 
						|
 		/* Initial residue value */
 | 
						|
-		dwc->residue = desc->total_len;
 | 
						|
+		desc->residue = desc->total_len;
 | 
						|
 
 | 
						|
 		/* Check first descriptors addr */
 | 
						|
-		if (desc->txd.phys == llp) {
 | 
						|
+		if (desc->txd.phys == DWC_LLP_LOC(llp)) {
 | 
						|
 			spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 			return;
 | 
						|
 		}
 | 
						|
 
 | 
						|
 		/* Check first descriptors llp */
 | 
						|
-		if (desc->lli.llp == llp) {
 | 
						|
+		if (lli_read(desc, llp) == llp) {
 | 
						|
 			/* This one is currently in progress */
 | 
						|
-			dwc->residue -= dwc_get_sent(dwc);
 | 
						|
+			desc->residue -= dwc_get_sent(dwc);
 | 
						|
 			spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 			return;
 | 
						|
 		}
 | 
						|
 
 | 
						|
-		dwc->residue -= desc->len;
 | 
						|
+		desc->residue -= desc->len;
 | 
						|
 		list_for_each_entry(child, &desc->tx_list, desc_node) {
 | 
						|
-			if (child->lli.llp == llp) {
 | 
						|
+			if (lli_read(child, llp) == llp) {
 | 
						|
 				/* Currently in progress */
 | 
						|
-				dwc->residue -= dwc_get_sent(dwc);
 | 
						|
+				desc->residue -= dwc_get_sent(dwc);
 | 
						|
 				spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 				return;
 | 
						|
 			}
 | 
						|
-			dwc->residue -= child->len;
 | 
						|
+			desc->residue -= child->len;
 | 
						|
 		}
 | 
						|
 
 | 
						|
 		/*
 | 
						|
@@ -457,10 +446,14 @@ static void dwc_scan_descriptors(struct
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 }
 | 
						|
 
 | 
						|
-static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
 | 
						|
+static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_desc *desc)
 | 
						|
 {
 | 
						|
 	dev_crit(chan2dev(&dwc->chan), "  desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
 | 
						|
-		 lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo);
 | 
						|
+		 lli_read(desc, sar),
 | 
						|
+		 lli_read(desc, dar),
 | 
						|
+		 lli_read(desc, llp),
 | 
						|
+		 lli_read(desc, ctlhi),
 | 
						|
+		 lli_read(desc, ctllo));
 | 
						|
 }
 | 
						|
 
 | 
						|
 static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
 | 
						|
@@ -496,9 +489,9 @@ static void dwc_handle_error(struct dw_d
 | 
						|
 	 */
 | 
						|
 	dev_WARN(chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"
 | 
						|
 				       "  cookie: %d\n", bad_desc->txd.cookie);
 | 
						|
-	dwc_dump_lli(dwc, &bad_desc->lli);
 | 
						|
+	dwc_dump_lli(dwc, bad_desc);
 | 
						|
 	list_for_each_entry(child, &bad_desc->tx_list, desc_node)
 | 
						|
-		dwc_dump_lli(dwc, &child->lli);
 | 
						|
+		dwc_dump_lli(dwc, child);
 | 
						|
 
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 
 | 
						|
@@ -549,7 +542,7 @@ static void dwc_handle_cyclic(struct dw_
 | 
						|
 	 */
 | 
						|
 	if (unlikely(status_err & dwc->mask) ||
 | 
						|
 			unlikely(status_xfer & dwc->mask)) {
 | 
						|
-		int i;
 | 
						|
+		unsigned int i;
 | 
						|
 
 | 
						|
 		dev_err(chan2dev(&dwc->chan),
 | 
						|
 			"cyclic DMA unexpected %s interrupt, stopping DMA transfer\n",
 | 
						|
@@ -571,7 +564,7 @@ static void dwc_handle_cyclic(struct dw_
 | 
						|
 		dma_writel(dw, CLEAR.XFER, dwc->mask);
 | 
						|
 
 | 
						|
 		for (i = 0; i < dwc->cdesc->periods; i++)
 | 
						|
-			dwc_dump_lli(dwc, &dwc->cdesc->desc[i]->lli);
 | 
						|
+			dwc_dump_lli(dwc, dwc->cdesc->desc[i]);
 | 
						|
 
 | 
						|
 		spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 	}
 | 
						|
@@ -589,7 +582,7 @@ static void dw_dma_tasklet(unsigned long
 | 
						|
 	u32 status_block;
 | 
						|
 	u32 status_xfer;
 | 
						|
 	u32 status_err;
 | 
						|
-	int i;
 | 
						|
+	unsigned int i;
 | 
						|
 
 | 
						|
 	status_block = dma_readl(dw, RAW.BLOCK);
 | 
						|
 	status_xfer = dma_readl(dw, RAW.XFER);
 | 
						|
@@ -616,12 +609,17 @@ static void dw_dma_tasklet(unsigned long
 | 
						|
 static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
 | 
						|
 {
 | 
						|
 	struct dw_dma *dw = dev_id;
 | 
						|
-	u32 status = dma_readl(dw, STATUS_INT);
 | 
						|
+	u32 status;
 | 
						|
+
 | 
						|
+	/* Check if we have any interrupt from the DMAC which is not in use */
 | 
						|
+	if (!dw->in_use)
 | 
						|
+		return IRQ_NONE;
 | 
						|
 
 | 
						|
+	status = dma_readl(dw, STATUS_INT);
 | 
						|
 	dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
 | 
						|
 
 | 
						|
 	/* Check if we have any interrupt from the DMAC */
 | 
						|
-	if (!status || !dw->in_use)
 | 
						|
+	if (!status)
 | 
						|
 		return IRQ_NONE;
 | 
						|
 
 | 
						|
 	/*
 | 
						|
@@ -653,30 +651,6 @@ static irqreturn_t dw_dma_interrupt(int
 | 
						|
 
 | 
						|
 /*----------------------------------------------------------------------*/
 | 
						|
 
 | 
						|
-static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
 | 
						|
-{
 | 
						|
-	struct dw_desc		*desc = txd_to_dw_desc(tx);
 | 
						|
-	struct dw_dma_chan	*dwc = to_dw_dma_chan(tx->chan);
 | 
						|
-	dma_cookie_t		cookie;
 | 
						|
-	unsigned long		flags;
 | 
						|
-
 | 
						|
-	spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
-	cookie = dma_cookie_assign(tx);
 | 
						|
-
 | 
						|
-	/*
 | 
						|
-	 * REVISIT: We should attempt to chain as many descriptors as
 | 
						|
-	 * possible, perhaps even appending to those already submitted
 | 
						|
-	 * for DMA. But this is hard to do in a race-free manner.
 | 
						|
-	 */
 | 
						|
-
 | 
						|
-	dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__, desc->txd.cookie);
 | 
						|
-	list_add_tail(&desc->desc_node, &dwc->queue);
 | 
						|
-
 | 
						|
-	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
-
 | 
						|
-	return cookie;
 | 
						|
-}
 | 
						|
-
 | 
						|
 static struct dma_async_tx_descriptor *
 | 
						|
 dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 | 
						|
 		size_t len, unsigned long flags)
 | 
						|
@@ -688,10 +662,12 @@ dwc_prep_dma_memcpy(struct dma_chan *cha
 | 
						|
 	struct dw_desc		*prev;
 | 
						|
 	size_t			xfer_count;
 | 
						|
 	size_t			offset;
 | 
						|
+	u8			m_master = dwc->m_master;
 | 
						|
 	unsigned int		src_width;
 | 
						|
 	unsigned int		dst_width;
 | 
						|
-	unsigned int		data_width;
 | 
						|
+	unsigned int		data_width = dw->pdata->data_width[m_master];
 | 
						|
 	u32			ctllo;
 | 
						|
+	u8			lms = DWC_LLP_LMS(m_master);
 | 
						|
 
 | 
						|
 	dev_vdbg(chan2dev(chan),
 | 
						|
 			"%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
 | 
						|
@@ -704,11 +680,7 @@ dwc_prep_dma_memcpy(struct dma_chan *cha
 | 
						|
 
 | 
						|
 	dwc->direction = DMA_MEM_TO_MEM;
 | 
						|
 
 | 
						|
-	data_width = min_t(unsigned int, dw->data_width[dwc->src_master],
 | 
						|
-			   dw->data_width[dwc->dst_master]);
 | 
						|
-
 | 
						|
-	src_width = dst_width = min_t(unsigned int, data_width,
 | 
						|
-				      dwc_fast_ffs(src | dest | len));
 | 
						|
+	src_width = dst_width = __ffs(data_width | src | dest | len);
 | 
						|
 
 | 
						|
 	ctllo = DWC_DEFAULT_CTLLO(chan)
 | 
						|
 			| DWC_CTLL_DST_WIDTH(dst_width)
 | 
						|
@@ -726,27 +698,27 @@ dwc_prep_dma_memcpy(struct dma_chan *cha
 | 
						|
 		if (!desc)
 | 
						|
 			goto err_desc_get;
 | 
						|
 
 | 
						|
-		desc->lli.sar = src + offset;
 | 
						|
-		desc->lli.dar = dest + offset;
 | 
						|
-		desc->lli.ctllo = ctllo;
 | 
						|
-		desc->lli.ctlhi = xfer_count;
 | 
						|
+		lli_write(desc, sar, src + offset);
 | 
						|
+		lli_write(desc, dar, dest + offset);
 | 
						|
+		lli_write(desc, ctllo, ctllo);
 | 
						|
+		lli_write(desc, ctlhi, xfer_count);
 | 
						|
 		desc->len = xfer_count << src_width;
 | 
						|
 
 | 
						|
 		if (!first) {
 | 
						|
 			first = desc;
 | 
						|
 		} else {
 | 
						|
-			prev->lli.llp = desc->txd.phys;
 | 
						|
-			list_add_tail(&desc->desc_node,
 | 
						|
-					&first->tx_list);
 | 
						|
+			lli_write(prev, llp, desc->txd.phys | lms);
 | 
						|
+			list_add_tail(&desc->desc_node, &first->tx_list);
 | 
						|
 		}
 | 
						|
 		prev = desc;
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	if (flags & DMA_PREP_INTERRUPT)
 | 
						|
 		/* Trigger interrupt after last block */
 | 
						|
-		prev->lli.ctllo |= DWC_CTLL_INT_EN;
 | 
						|
+		lli_set(prev, ctllo, DWC_CTLL_INT_EN);
 | 
						|
 
 | 
						|
 	prev->lli.llp = 0;
 | 
						|
+	lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
 | 
						|
 	first->txd.flags = flags;
 | 
						|
 	first->total_len = len;
 | 
						|
 
 | 
						|
@@ -768,10 +740,12 @@ dwc_prep_slave_sg(struct dma_chan *chan,
 | 
						|
 	struct dw_desc		*prev;
 | 
						|
 	struct dw_desc		*first;
 | 
						|
 	u32			ctllo;
 | 
						|
+	u8			m_master = dwc->m_master;
 | 
						|
+	u8			lms = DWC_LLP_LMS(m_master);
 | 
						|
 	dma_addr_t		reg;
 | 
						|
 	unsigned int		reg_width;
 | 
						|
 	unsigned int		mem_width;
 | 
						|
-	unsigned int		data_width;
 | 
						|
+	unsigned int		data_width = dw->pdata->data_width[m_master];
 | 
						|
 	unsigned int		i;
 | 
						|
 	struct scatterlist	*sg;
 | 
						|
 	size_t			total_len = 0;
 | 
						|
@@ -797,8 +771,6 @@ dwc_prep_slave_sg(struct dma_chan *chan,
 | 
						|
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
 | 
						|
 			DWC_CTLL_FC(DW_DMA_FC_D_M2P);
 | 
						|
 
 | 
						|
-		data_width = dw->data_width[dwc->src_master];
 | 
						|
-
 | 
						|
 		for_each_sg(sgl, sg, sg_len, i) {
 | 
						|
 			struct dw_desc	*desc;
 | 
						|
 			u32		len, dlen, mem;
 | 
						|
@@ -806,17 +778,16 @@ dwc_prep_slave_sg(struct dma_chan *chan,
 | 
						|
 			mem = sg_dma_address(sg);
 | 
						|
 			len = sg_dma_len(sg);
 | 
						|
 
 | 
						|
-			mem_width = min_t(unsigned int,
 | 
						|
-					  data_width, dwc_fast_ffs(mem | len));
 | 
						|
+			mem_width = __ffs(data_width | mem | len);
 | 
						|
 
 | 
						|
 slave_sg_todev_fill_desc:
 | 
						|
 			desc = dwc_desc_get(dwc);
 | 
						|
 			if (!desc)
 | 
						|
 				goto err_desc_get;
 | 
						|
 
 | 
						|
-			desc->lli.sar = mem;
 | 
						|
-			desc->lli.dar = reg;
 | 
						|
-			desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
 | 
						|
+			lli_write(desc, sar, mem);
 | 
						|
+			lli_write(desc, dar, reg);
 | 
						|
+			lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
 | 
						|
 			if ((len >> mem_width) > dwc->block_size) {
 | 
						|
 				dlen = dwc->block_size << mem_width;
 | 
						|
 				mem += dlen;
 | 
						|
@@ -826,15 +797,14 @@ slave_sg_todev_fill_desc:
 | 
						|
 				len = 0;
 | 
						|
 			}
 | 
						|
 
 | 
						|
-			desc->lli.ctlhi = dlen >> mem_width;
 | 
						|
+			lli_write(desc, ctlhi, dlen >> mem_width);
 | 
						|
 			desc->len = dlen;
 | 
						|
 
 | 
						|
 			if (!first) {
 | 
						|
 				first = desc;
 | 
						|
 			} else {
 | 
						|
-				prev->lli.llp = desc->txd.phys;
 | 
						|
-				list_add_tail(&desc->desc_node,
 | 
						|
-						&first->tx_list);
 | 
						|
+				lli_write(prev, llp, desc->txd.phys | lms);
 | 
						|
+				list_add_tail(&desc->desc_node, &first->tx_list);
 | 
						|
 			}
 | 
						|
 			prev = desc;
 | 
						|
 			total_len += dlen;
 | 
						|
@@ -854,8 +824,6 @@ slave_sg_todev_fill_desc:
 | 
						|
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
 | 
						|
 			DWC_CTLL_FC(DW_DMA_FC_D_P2M);
 | 
						|
 
 | 
						|
-		data_width = dw->data_width[dwc->dst_master];
 | 
						|
-
 | 
						|
 		for_each_sg(sgl, sg, sg_len, i) {
 | 
						|
 			struct dw_desc	*desc;
 | 
						|
 			u32		len, dlen, mem;
 | 
						|
@@ -863,17 +831,16 @@ slave_sg_todev_fill_desc:
 | 
						|
 			mem = sg_dma_address(sg);
 | 
						|
 			len = sg_dma_len(sg);
 | 
						|
 
 | 
						|
-			mem_width = min_t(unsigned int,
 | 
						|
-					  data_width, dwc_fast_ffs(mem | len));
 | 
						|
+			mem_width = __ffs(data_width | mem | len);
 | 
						|
 
 | 
						|
 slave_sg_fromdev_fill_desc:
 | 
						|
 			desc = dwc_desc_get(dwc);
 | 
						|
 			if (!desc)
 | 
						|
 				goto err_desc_get;
 | 
						|
 
 | 
						|
-			desc->lli.sar = reg;
 | 
						|
-			desc->lli.dar = mem;
 | 
						|
-			desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
 | 
						|
+			lli_write(desc, sar, reg);
 | 
						|
+			lli_write(desc, dar, mem);
 | 
						|
+			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
 | 
						|
 			if ((len >> reg_width) > dwc->block_size) {
 | 
						|
 				dlen = dwc->block_size << reg_width;
 | 
						|
 				mem += dlen;
 | 
						|
@@ -882,15 +849,14 @@ slave_sg_fromdev_fill_desc:
 | 
						|
 				dlen = len;
 | 
						|
 				len = 0;
 | 
						|
 			}
 | 
						|
-			desc->lli.ctlhi = dlen >> reg_width;
 | 
						|
+			lli_write(desc, ctlhi, dlen >> reg_width);
 | 
						|
 			desc->len = dlen;
 | 
						|
 
 | 
						|
 			if (!first) {
 | 
						|
 				first = desc;
 | 
						|
 			} else {
 | 
						|
-				prev->lli.llp = desc->txd.phys;
 | 
						|
-				list_add_tail(&desc->desc_node,
 | 
						|
-						&first->tx_list);
 | 
						|
+				lli_write(prev, llp, desc->txd.phys | lms);
 | 
						|
+				list_add_tail(&desc->desc_node, &first->tx_list);
 | 
						|
 			}
 | 
						|
 			prev = desc;
 | 
						|
 			total_len += dlen;
 | 
						|
@@ -905,9 +871,10 @@ slave_sg_fromdev_fill_desc:
 | 
						|
 
 | 
						|
 	if (flags & DMA_PREP_INTERRUPT)
 | 
						|
 		/* Trigger interrupt after last block */
 | 
						|
-		prev->lli.ctllo |= DWC_CTLL_INT_EN;
 | 
						|
+		lli_set(prev, ctllo, DWC_CTLL_INT_EN);
 | 
						|
 
 | 
						|
 	prev->lli.llp = 0;
 | 
						|
+	lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
 | 
						|
 	first->total_len = total_len;
 | 
						|
 
 | 
						|
 	return &first->txd;
 | 
						|
@@ -932,8 +899,8 @@ bool dw_dma_filter(struct dma_chan *chan
 | 
						|
 	dwc->src_id = dws->src_id;
 | 
						|
 	dwc->dst_id = dws->dst_id;
 | 
						|
 
 | 
						|
-	dwc->src_master = dws->src_master;
 | 
						|
-	dwc->dst_master = dws->dst_master;
 | 
						|
+	dwc->m_master = dws->m_master;
 | 
						|
+	dwc->p_master = dws->p_master;
 | 
						|
 
 | 
						|
 	return true;
 | 
						|
 }
 | 
						|
@@ -986,7 +953,7 @@ static int dwc_pause(struct dma_chan *ch
 | 
						|
 	while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
 | 
						|
 		udelay(2);
 | 
						|
 
 | 
						|
-	dwc->paused = true;
 | 
						|
+	set_bit(DW_DMA_IS_PAUSED, &dwc->flags);
 | 
						|
 
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 
 | 
						|
@@ -999,7 +966,7 @@ static inline void dwc_chan_resume(struc
 | 
						|
 
 | 
						|
 	channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP);
 | 
						|
 
 | 
						|
-	dwc->paused = false;
 | 
						|
+	clear_bit(DW_DMA_IS_PAUSED, &dwc->flags);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int dwc_resume(struct dma_chan *chan)
 | 
						|
@@ -1007,12 +974,10 @@ static int dwc_resume(struct dma_chan *c
 | 
						|
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
 | 
						|
 	unsigned long		flags;
 | 
						|
 
 | 
						|
-	if (!dwc->paused)
 | 
						|
-		return 0;
 | 
						|
-
 | 
						|
 	spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
 
 | 
						|
-	dwc_chan_resume(dwc);
 | 
						|
+	if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags))
 | 
						|
+		dwc_chan_resume(dwc);
 | 
						|
 
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 
 | 
						|
@@ -1048,16 +1013,37 @@ static int dwc_terminate_all(struct dma_
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static inline u32 dwc_get_residue(struct dw_dma_chan *dwc)
 | 
						|
+static struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
 | 
						|
+{
 | 
						|
+	struct dw_desc *desc;
 | 
						|
+
 | 
						|
+	list_for_each_entry(desc, &dwc->active_list, desc_node)
 | 
						|
+		if (desc->txd.cookie == c)
 | 
						|
+			return desc;
 | 
						|
+
 | 
						|
+	return NULL;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static u32 dwc_get_residue(struct dw_dma_chan *dwc, dma_cookie_t cookie)
 | 
						|
 {
 | 
						|
+	struct dw_desc *desc;
 | 
						|
 	unsigned long flags;
 | 
						|
 	u32 residue;
 | 
						|
 
 | 
						|
 	spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
 
 | 
						|
-	residue = dwc->residue;
 | 
						|
-	if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue)
 | 
						|
-		residue -= dwc_get_sent(dwc);
 | 
						|
+	desc = dwc_find_desc(dwc, cookie);
 | 
						|
+	if (desc) {
 | 
						|
+		if (desc == dwc_first_active(dwc)) {
 | 
						|
+			residue = desc->residue;
 | 
						|
+			if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue)
 | 
						|
+				residue -= dwc_get_sent(dwc);
 | 
						|
+		} else {
 | 
						|
+			residue = desc->total_len;
 | 
						|
+		}
 | 
						|
+	} else {
 | 
						|
+		residue = 0;
 | 
						|
+	}
 | 
						|
 
 | 
						|
 	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
 	return residue;
 | 
						|
@@ -1078,10 +1064,12 @@ dwc_tx_status(struct dma_chan *chan,
 | 
						|
 	dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
 | 
						|
 
 | 
						|
 	ret = dma_cookie_status(chan, cookie, txstate);
 | 
						|
-	if (ret != DMA_COMPLETE)
 | 
						|
-		dma_set_residue(txstate, dwc_get_residue(dwc));
 | 
						|
+	if (ret == DMA_COMPLETE)
 | 
						|
+		return ret;
 | 
						|
+
 | 
						|
+	dma_set_residue(txstate, dwc_get_residue(dwc, cookie));
 | 
						|
 
 | 
						|
-	if (dwc->paused && ret == DMA_IN_PROGRESS)
 | 
						|
+	if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags) && ret == DMA_IN_PROGRESS)
 | 
						|
 		return DMA_PAUSED;
 | 
						|
 
 | 
						|
 	return ret;
 | 
						|
@@ -1102,7 +1090,7 @@ static void dwc_issue_pending(struct dma
 | 
						|
 
 | 
						|
 static void dw_dma_off(struct dw_dma *dw)
 | 
						|
 {
 | 
						|
-	int i;
 | 
						|
+	unsigned int i;
 | 
						|
 
 | 
						|
 	dma_writel(dw, CFG, 0);
 | 
						|
 
 | 
						|
@@ -1116,7 +1104,7 @@ static void dw_dma_off(struct dw_dma *dw
 | 
						|
 		cpu_relax();
 | 
						|
 
 | 
						|
 	for (i = 0; i < dw->dma.chancnt; i++)
 | 
						|
-		dw->chan[i].initialized = false;
 | 
						|
+		clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static void dw_dma_on(struct dw_dma *dw)
 | 
						|
@@ -1128,9 +1116,6 @@ static int dwc_alloc_chan_resources(stru
 | 
						|
 {
 | 
						|
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
 | 
						|
 	struct dw_dma		*dw = to_dw_dma(chan->device);
 | 
						|
-	struct dw_desc		*desc;
 | 
						|
-	int			i;
 | 
						|
-	unsigned long		flags;
 | 
						|
 
 | 
						|
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
 | 
						|
 
 | 
						|
@@ -1161,48 +1146,13 @@ static int dwc_alloc_chan_resources(stru
 | 
						|
 		dw_dma_on(dw);
 | 
						|
 	dw->in_use |= dwc->mask;
 | 
						|
 
 | 
						|
-	spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
-	i = dwc->descs_allocated;
 | 
						|
-	while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) {
 | 
						|
-		dma_addr_t phys;
 | 
						|
-
 | 
						|
-		spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
-
 | 
						|
-		desc = dma_pool_alloc(dw->desc_pool, GFP_ATOMIC, &phys);
 | 
						|
-		if (!desc)
 | 
						|
-			goto err_desc_alloc;
 | 
						|
-
 | 
						|
-		memset(desc, 0, sizeof(struct dw_desc));
 | 
						|
-
 | 
						|
-		INIT_LIST_HEAD(&desc->tx_list);
 | 
						|
-		dma_async_tx_descriptor_init(&desc->txd, chan);
 | 
						|
-		desc->txd.tx_submit = dwc_tx_submit;
 | 
						|
-		desc->txd.flags = DMA_CTRL_ACK;
 | 
						|
-		desc->txd.phys = phys;
 | 
						|
-
 | 
						|
-		dwc_desc_put(dwc, desc);
 | 
						|
-
 | 
						|
-		spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
-		i = ++dwc->descs_allocated;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						|
-
 | 
						|
-	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);
 | 
						|
-
 | 
						|
-	return i;
 | 
						|
-
 | 
						|
-err_desc_alloc:
 | 
						|
-	dev_info(chan2dev(chan), "only allocated %d descriptors\n", i);
 | 
						|
-
 | 
						|
-	return i;
 | 
						|
+	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
 static void dwc_free_chan_resources(struct dma_chan *chan)
 | 
						|
 {
 | 
						|
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
 | 
						|
 	struct dw_dma		*dw = to_dw_dma(chan->device);
 | 
						|
-	struct dw_desc		*desc, *_desc;
 | 
						|
 	unsigned long		flags;
 | 
						|
 	LIST_HEAD(list);
 | 
						|
 
 | 
						|
@@ -1215,17 +1165,15 @@ static void dwc_free_chan_resources(stru
 | 
						|
 	BUG_ON(dma_readl(to_dw_dma(chan->device), CH_EN) & dwc->mask);
 | 
						|
 
 | 
						|
 	spin_lock_irqsave(&dwc->lock, flags);
 | 
						|
-	list_splice_init(&dwc->free_list, &list);
 | 
						|
-	dwc->descs_allocated = 0;
 | 
						|
 
 | 
						|
 	/* Clear custom channel configuration */
 | 
						|
 	dwc->src_id = 0;
 | 
						|
 	dwc->dst_id = 0;
 | 
						|
 
 | 
						|
-	dwc->src_master = 0;
 | 
						|
-	dwc->dst_master = 0;
 | 
						|
+	dwc->m_master = 0;
 | 
						|
+	dwc->p_master = 0;
 | 
						|
 
 | 
						|
-	dwc->initialized = false;
 | 
						|
+	clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
 | 
						|
 
 | 
						|
 	/* Disable interrupts */
 | 
						|
 	channel_clear_bit(dw, MASK.XFER, dwc->mask);
 | 
						|
@@ -1239,11 +1187,6 @@ static void dwc_free_chan_resources(stru
 | 
						|
 	if (!dw->in_use)
 | 
						|
 		dw_dma_off(dw);
 | 
						|
 
 | 
						|
-	list_for_each_entry_safe(desc, _desc, &list, desc_node) {
 | 
						|
-		dev_vdbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
 | 
						|
-		dma_pool_free(dw->desc_pool, desc, desc->txd.phys);
 | 
						|
-	}
 | 
						|
-
 | 
						|
 	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -1321,6 +1264,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_pre
 | 
						|
 	struct dw_cyclic_desc		*retval = NULL;
 | 
						|
 	struct dw_desc			*desc;
 | 
						|
 	struct dw_desc			*last = NULL;
 | 
						|
+	u8				lms = DWC_LLP_LMS(dwc->m_master);
 | 
						|
 	unsigned long			was_cyclic;
 | 
						|
 	unsigned int			reg_width;
 | 
						|
 	unsigned int			periods;
 | 
						|
@@ -1374,9 +1318,6 @@ struct dw_cyclic_desc *dw_dma_cyclic_pre
 | 
						|
 
 | 
						|
 	retval = ERR_PTR(-ENOMEM);
 | 
						|
 
 | 
						|
-	if (periods > NR_DESCS_PER_CHANNEL)
 | 
						|
-		goto out_err;
 | 
						|
-
 | 
						|
 	cdesc = kzalloc(sizeof(struct dw_cyclic_desc), GFP_KERNEL);
 | 
						|
 	if (!cdesc)
 | 
						|
 		goto out_err;
 | 
						|
@@ -1392,50 +1333,50 @@ struct dw_cyclic_desc *dw_dma_cyclic_pre
 | 
						|
 
 | 
						|
 		switch (direction) {
 | 
						|
 		case DMA_MEM_TO_DEV:
 | 
						|
-			desc->lli.dar = sconfig->dst_addr;
 | 
						|
-			desc->lli.sar = buf_addr + (period_len * i);
 | 
						|
-			desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
 | 
						|
-					| DWC_CTLL_DST_WIDTH(reg_width)
 | 
						|
-					| DWC_CTLL_SRC_WIDTH(reg_width)
 | 
						|
-					| DWC_CTLL_DST_FIX
 | 
						|
-					| DWC_CTLL_SRC_INC
 | 
						|
-					| DWC_CTLL_INT_EN);
 | 
						|
-
 | 
						|
-			desc->lli.ctllo |= sconfig->device_fc ?
 | 
						|
-				DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
 | 
						|
-				DWC_CTLL_FC(DW_DMA_FC_D_M2P);
 | 
						|
+			lli_write(desc, dar, sconfig->dst_addr);
 | 
						|
+			lli_write(desc, sar, buf_addr + period_len * i);
 | 
						|
+			lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan)
 | 
						|
+				| DWC_CTLL_DST_WIDTH(reg_width)
 | 
						|
+				| DWC_CTLL_SRC_WIDTH(reg_width)
 | 
						|
+				| DWC_CTLL_DST_FIX
 | 
						|
+				| DWC_CTLL_SRC_INC
 | 
						|
+				| DWC_CTLL_INT_EN));
 | 
						|
+
 | 
						|
+			lli_set(desc, ctllo, sconfig->device_fc ?
 | 
						|
+					DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
 | 
						|
+					DWC_CTLL_FC(DW_DMA_FC_D_M2P));
 | 
						|
 
 | 
						|
 			break;
 | 
						|
 		case DMA_DEV_TO_MEM:
 | 
						|
-			desc->lli.dar = buf_addr + (period_len * i);
 | 
						|
-			desc->lli.sar = sconfig->src_addr;
 | 
						|
-			desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
 | 
						|
-					| DWC_CTLL_SRC_WIDTH(reg_width)
 | 
						|
-					| DWC_CTLL_DST_WIDTH(reg_width)
 | 
						|
-					| DWC_CTLL_DST_INC
 | 
						|
-					| DWC_CTLL_SRC_FIX
 | 
						|
-					| DWC_CTLL_INT_EN);
 | 
						|
-
 | 
						|
-			desc->lli.ctllo |= sconfig->device_fc ?
 | 
						|
-				DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
 | 
						|
-				DWC_CTLL_FC(DW_DMA_FC_D_P2M);
 | 
						|
+			lli_write(desc, dar, buf_addr + period_len * i);
 | 
						|
+			lli_write(desc, sar, sconfig->src_addr);
 | 
						|
+			lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan)
 | 
						|
+				| DWC_CTLL_SRC_WIDTH(reg_width)
 | 
						|
+				| DWC_CTLL_DST_WIDTH(reg_width)
 | 
						|
+				| DWC_CTLL_DST_INC
 | 
						|
+				| DWC_CTLL_SRC_FIX
 | 
						|
+				| DWC_CTLL_INT_EN));
 | 
						|
+
 | 
						|
+			lli_set(desc, ctllo, sconfig->device_fc ?
 | 
						|
+					DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
 | 
						|
+					DWC_CTLL_FC(DW_DMA_FC_D_P2M));
 | 
						|
 
 | 
						|
 			break;
 | 
						|
 		default:
 | 
						|
 			break;
 | 
						|
 		}
 | 
						|
 
 | 
						|
-		desc->lli.ctlhi = (period_len >> reg_width);
 | 
						|
+		lli_write(desc, ctlhi, period_len >> reg_width);
 | 
						|
 		cdesc->desc[i] = desc;
 | 
						|
 
 | 
						|
 		if (last)
 | 
						|
-			last->lli.llp = desc->txd.phys;
 | 
						|
+			lli_write(last, llp, desc->txd.phys | lms);
 | 
						|
 
 | 
						|
 		last = desc;
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	/* Let's make a cyclic list */
 | 
						|
-	last->lli.llp = cdesc->desc[0]->txd.phys;
 | 
						|
+	lli_write(last, llp, cdesc->desc[0]->txd.phys | lms);
 | 
						|
 
 | 
						|
 	dev_dbg(chan2dev(&dwc->chan),
 | 
						|
 			"cyclic prepared buf %pad len %zu period %zu periods %d\n",
 | 
						|
@@ -1466,7 +1407,7 @@ void dw_dma_cyclic_free(struct dma_chan
 | 
						|
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
 | 
						|
 	struct dw_dma		*dw = to_dw_dma(dwc->chan.device);
 | 
						|
 	struct dw_cyclic_desc	*cdesc = dwc->cdesc;
 | 
						|
-	int			i;
 | 
						|
+	unsigned int		i;
 | 
						|
 	unsigned long		flags;
 | 
						|
 
 | 
						|
 	dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);
 | 
						|
@@ -1490,32 +1431,38 @@ void dw_dma_cyclic_free(struct dma_chan
 | 
						|
 	kfree(cdesc->desc);
 | 
						|
 	kfree(cdesc);
 | 
						|
 
 | 
						|
+	dwc->cdesc = NULL;
 | 
						|
+
 | 
						|
 	clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
 | 
						|
 }
 | 
						|
 EXPORT_SYMBOL(dw_dma_cyclic_free);
 | 
						|
 
 | 
						|
 /*----------------------------------------------------------------------*/
 | 
						|
 
 | 
						|
-int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
 | 
						|
+int dw_dma_probe(struct dw_dma_chip *chip)
 | 
						|
 {
 | 
						|
+	struct dw_dma_platform_data *pdata;
 | 
						|
 	struct dw_dma		*dw;
 | 
						|
 	bool			autocfg = false;
 | 
						|
 	unsigned int		dw_params;
 | 
						|
-	unsigned int		max_blk_size = 0;
 | 
						|
+	unsigned int		i;
 | 
						|
 	int			err;
 | 
						|
-	int			i;
 | 
						|
 
 | 
						|
 	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
 | 
						|
 	if (!dw)
 | 
						|
 		return -ENOMEM;
 | 
						|
 
 | 
						|
+	dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
 | 
						|
+	if (!dw->pdata)
 | 
						|
+		return -ENOMEM;
 | 
						|
+
 | 
						|
 	dw->regs = chip->regs;
 | 
						|
 	chip->dw = dw;
 | 
						|
 
 | 
						|
 	pm_runtime_get_sync(chip->dev);
 | 
						|
 
 | 
						|
-	if (!pdata) {
 | 
						|
-		dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
 | 
						|
+	if (!chip->pdata) {
 | 
						|
+		dw_params = dma_readl(dw, DW_PARAMS);
 | 
						|
 		dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
 | 
						|
 
 | 
						|
 		autocfg = dw_params >> DW_PARAMS_EN & 1;
 | 
						|
@@ -1524,29 +1471,31 @@ int dw_dma_probe(struct dw_dma_chip *chi
 | 
						|
 			goto err_pdata;
 | 
						|
 		}
 | 
						|
 
 | 
						|
-		pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
 | 
						|
-		if (!pdata) {
 | 
						|
-			err = -ENOMEM;
 | 
						|
-			goto err_pdata;
 | 
						|
-		}
 | 
						|
+		/* Reassign the platform data pointer */
 | 
						|
+		pdata = dw->pdata;
 | 
						|
 
 | 
						|
 		/* Get hardware configuration parameters */
 | 
						|
 		pdata->nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 7) + 1;
 | 
						|
 		pdata->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
 | 
						|
 		for (i = 0; i < pdata->nr_masters; i++) {
 | 
						|
 			pdata->data_width[i] =
 | 
						|
-				(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
 | 
						|
+				4 << (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3);
 | 
						|
 		}
 | 
						|
-		max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
 | 
						|
+		pdata->block_size = dma_readl(dw, MAX_BLK_SIZE);
 | 
						|
 
 | 
						|
 		/* Fill platform data with the default values */
 | 
						|
 		pdata->is_private = true;
 | 
						|
 		pdata->is_memcpy = true;
 | 
						|
 		pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING;
 | 
						|
 		pdata->chan_priority = CHAN_PRIORITY_ASCENDING;
 | 
						|
-	} else if (pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
 | 
						|
+	} else if (chip->pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
 | 
						|
 		err = -EINVAL;
 | 
						|
 		goto err_pdata;
 | 
						|
+	} else {
 | 
						|
+		memcpy(dw->pdata, chip->pdata, sizeof(*dw->pdata));
 | 
						|
+
 | 
						|
+		/* Reassign the platform data pointer */
 | 
						|
+		pdata = dw->pdata;
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	dw->chan = devm_kcalloc(chip->dev, pdata->nr_channels, sizeof(*dw->chan),
 | 
						|
@@ -1556,11 +1505,6 @@ int dw_dma_probe(struct dw_dma_chip *chi
 | 
						|
 		goto err_pdata;
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	/* Get hardware configuration parameters */
 | 
						|
-	dw->nr_masters = pdata->nr_masters;
 | 
						|
-	for (i = 0; i < dw->nr_masters; i++)
 | 
						|
-		dw->data_width[i] = pdata->data_width[i];
 | 
						|
-
 | 
						|
 	/* Calculate all channel mask before DMA setup */
 | 
						|
 	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
 | 
						|
 
 | 
						|
@@ -1607,7 +1551,6 @@ int dw_dma_probe(struct dw_dma_chip *chi
 | 
						|
 
 | 
						|
 		INIT_LIST_HEAD(&dwc->active_list);
 | 
						|
 		INIT_LIST_HEAD(&dwc->queue);
 | 
						|
-		INIT_LIST_HEAD(&dwc->free_list);
 | 
						|
 
 | 
						|
 		channel_clear_bit(dw, CH_EN, dwc->mask);
 | 
						|
 
 | 
						|
@@ -1615,11 +1558,9 @@ int dw_dma_probe(struct dw_dma_chip *chi
 | 
						|
 
 | 
						|
 		/* Hardware configuration */
 | 
						|
 		if (autocfg) {
 | 
						|
-			unsigned int dwc_params;
 | 
						|
 			unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1;
 | 
						|
-			void __iomem *addr = chip->regs + r * sizeof(u32);
 | 
						|
-
 | 
						|
-			dwc_params = dma_read_byaddr(addr, DWC_PARAMS);
 | 
						|
+			void __iomem *addr = &__dw_regs(dw)->DWC_PARAMS[r];
 | 
						|
+			unsigned int dwc_params = dma_readl_native(addr);
 | 
						|
 
 | 
						|
 			dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
 | 
						|
 					   dwc_params);
 | 
						|
@@ -1630,16 +1571,15 @@ int dw_dma_probe(struct dw_dma_chip *chi
 | 
						|
 			 * up to 0x0a for 4095.
 | 
						|
 			 */
 | 
						|
 			dwc->block_size =
 | 
						|
-				(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
 | 
						|
+				(4 << ((pdata->block_size >> 4 * i) & 0xf)) - 1;
 | 
						|
 			dwc->nollp =
 | 
						|
 				(dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
 | 
						|
 		} else {
 | 
						|
 			dwc->block_size = pdata->block_size;
 | 
						|
 
 | 
						|
 			/* Check if channel supports multi block transfer */
 | 
						|
-			channel_writel(dwc, LLP, 0xfffffffc);
 | 
						|
-			dwc->nollp =
 | 
						|
-				(channel_readl(dwc, LLP) & 0xfffffffc) == 0;
 | 
						|
+			channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff));
 | 
						|
+			dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0;
 | 
						|
 			channel_writel(dwc, LLP, 0);
 | 
						|
 		}
 | 
						|
 	}
 | 
						|
--- a/drivers/dma/dw/pci.c
 | 
						|
+++ b/drivers/dma/dw/pci.c
 | 
						|
@@ -17,8 +17,8 @@
 | 
						|
 
 | 
						|
 static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 | 
						|
 {
 | 
						|
+	const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
 | 
						|
 	struct dw_dma_chip *chip;
 | 
						|
-	struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
 | 
						|
 	int ret;
 | 
						|
 
 | 
						|
 	ret = pcim_enable_device(pdev);
 | 
						|
@@ -49,8 +49,9 @@ static int dw_pci_probe(struct pci_dev *
 | 
						|
 	chip->dev = &pdev->dev;
 | 
						|
 	chip->regs = pcim_iomap_table(pdev)[0];
 | 
						|
 	chip->irq = pdev->irq;
 | 
						|
+	chip->pdata = pdata;
 | 
						|
 
 | 
						|
-	ret = dw_dma_probe(chip, pdata);
 | 
						|
+	ret = dw_dma_probe(chip);
 | 
						|
 	if (ret)
 | 
						|
 		return ret;
 | 
						|
 
 | 
						|
@@ -108,6 +109,10 @@ static const struct pci_device_id dw_pci
 | 
						|
 
 | 
						|
 	/* Haswell */
 | 
						|
 	{ PCI_VDEVICE(INTEL, 0x9c60) },
 | 
						|
+
 | 
						|
+	/* Broadwell */
 | 
						|
+	{ PCI_VDEVICE(INTEL, 0x9ce0) },
 | 
						|
+
 | 
						|
 	{ }
 | 
						|
 };
 | 
						|
 MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
 | 
						|
--- a/drivers/dma/dw/platform.c
 | 
						|
+++ b/drivers/dma/dw/platform.c
 | 
						|
@@ -42,13 +42,13 @@ static struct dma_chan *dw_dma_of_xlate(
 | 
						|
 
 | 
						|
 	slave.src_id = dma_spec->args[0];
 | 
						|
 	slave.dst_id = dma_spec->args[0];
 | 
						|
-	slave.src_master = dma_spec->args[1];
 | 
						|
-	slave.dst_master = dma_spec->args[2];
 | 
						|
+	slave.m_master = dma_spec->args[1];
 | 
						|
+	slave.p_master = dma_spec->args[2];
 | 
						|
 
 | 
						|
 	if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS ||
 | 
						|
 		    slave.dst_id >= DW_DMA_MAX_NR_REQUESTS ||
 | 
						|
-		    slave.src_master >= dw->nr_masters ||
 | 
						|
-		    slave.dst_master >= dw->nr_masters))
 | 
						|
+		    slave.m_master >= dw->pdata->nr_masters ||
 | 
						|
+		    slave.p_master >= dw->pdata->nr_masters))
 | 
						|
 		return NULL;
 | 
						|
 
 | 
						|
 	dma_cap_zero(cap);
 | 
						|
@@ -66,8 +66,8 @@ static bool dw_dma_acpi_filter(struct dm
 | 
						|
 		.dma_dev = dma_spec->dev,
 | 
						|
 		.src_id = dma_spec->slave_id,
 | 
						|
 		.dst_id = dma_spec->slave_id,
 | 
						|
-		.src_master = 1,
 | 
						|
-		.dst_master = 0,
 | 
						|
+		.m_master = 0,
 | 
						|
+		.p_master = 1,
 | 
						|
 	};
 | 
						|
 
 | 
						|
 	return dw_dma_filter(chan, &slave);
 | 
						|
@@ -103,18 +103,28 @@ dw_dma_parse_dt(struct platform_device *
 | 
						|
 	struct device_node *np = pdev->dev.of_node;
 | 
						|
 	struct dw_dma_platform_data *pdata;
 | 
						|
 	u32 tmp, arr[DW_DMA_MAX_NR_MASTERS];
 | 
						|
+	u32 nr_masters;
 | 
						|
+	u32 nr_channels;
 | 
						|
 
 | 
						|
 	if (!np) {
 | 
						|
 		dev_err(&pdev->dev, "Missing DT data\n");
 | 
						|
 		return NULL;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	if (of_property_read_u32(np, "dma-masters", &nr_masters))
 | 
						|
+		return NULL;
 | 
						|
+	if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS)
 | 
						|
+		return NULL;
 | 
						|
+
 | 
						|
+	if (of_property_read_u32(np, "dma-channels", &nr_channels))
 | 
						|
+		return NULL;
 | 
						|
+
 | 
						|
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 | 
						|
 	if (!pdata)
 | 
						|
 		return NULL;
 | 
						|
 
 | 
						|
-	if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
 | 
						|
-		return NULL;
 | 
						|
+	pdata->nr_masters = nr_masters;
 | 
						|
+	pdata->nr_channels = nr_channels;
 | 
						|
 
 | 
						|
 	if (of_property_read_bool(np, "is_private"))
 | 
						|
 		pdata->is_private = true;
 | 
						|
@@ -128,17 +138,13 @@ dw_dma_parse_dt(struct platform_device *
 | 
						|
 	if (!of_property_read_u32(np, "block_size", &tmp))
 | 
						|
 		pdata->block_size = tmp;
 | 
						|
 
 | 
						|
-	if (!of_property_read_u32(np, "dma-masters", &tmp)) {
 | 
						|
-		if (tmp > DW_DMA_MAX_NR_MASTERS)
 | 
						|
-			return NULL;
 | 
						|
-
 | 
						|
-		pdata->nr_masters = tmp;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	if (!of_property_read_u32_array(np, "data_width", arr,
 | 
						|
-				pdata->nr_masters))
 | 
						|
-		for (tmp = 0; tmp < pdata->nr_masters; tmp++)
 | 
						|
+	if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) {
 | 
						|
+		for (tmp = 0; tmp < nr_masters; tmp++)
 | 
						|
 			pdata->data_width[tmp] = arr[tmp];
 | 
						|
+	} else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) {
 | 
						|
+		for (tmp = 0; tmp < nr_masters; tmp++)
 | 
						|
+			pdata->data_width[tmp] = BIT(arr[tmp] & 0x07);
 | 
						|
+	}
 | 
						|
 
 | 
						|
 	return pdata;
 | 
						|
 }
 | 
						|
@@ -155,8 +161,7 @@ static int dw_probe(struct platform_devi
 | 
						|
 	struct dw_dma_chip *chip;
 | 
						|
 	struct device *dev = &pdev->dev;
 | 
						|
 	struct resource *mem;
 | 
						|
-	const struct acpi_device_id *id;
 | 
						|
-	struct dw_dma_platform_data *pdata;
 | 
						|
+	const struct dw_dma_platform_data *pdata;
 | 
						|
 	int err;
 | 
						|
 
 | 
						|
 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
 | 
						|
@@ -179,13 +184,9 @@ static int dw_probe(struct platform_devi
 | 
						|
 	pdata = dev_get_platdata(dev);
 | 
						|
 	if (!pdata)
 | 
						|
 		pdata = dw_dma_parse_dt(pdev);
 | 
						|
-	if (!pdata && has_acpi_companion(dev)) {
 | 
						|
-		id = acpi_match_device(dev->driver->acpi_match_table, dev);
 | 
						|
-		if (id)
 | 
						|
-			pdata = (struct dw_dma_platform_data *)id->driver_data;
 | 
						|
-	}
 | 
						|
 
 | 
						|
 	chip->dev = dev;
 | 
						|
+	chip->pdata = pdata;
 | 
						|
 
 | 
						|
 	chip->clk = devm_clk_get(chip->dev, "hclk");
 | 
						|
 	if (IS_ERR(chip->clk))
 | 
						|
@@ -196,7 +197,7 @@ static int dw_probe(struct platform_devi
 | 
						|
 
 | 
						|
 	pm_runtime_enable(&pdev->dev);
 | 
						|
 
 | 
						|
-	err = dw_dma_probe(chip, pdata);
 | 
						|
+	err = dw_dma_probe(chip);
 | 
						|
 	if (err)
 | 
						|
 		goto err_dw_dma_probe;
 | 
						|
 
 | 
						|
@@ -239,7 +240,19 @@ static void dw_shutdown(struct platform_
 | 
						|
 {
 | 
						|
 	struct dw_dma_chip *chip = platform_get_drvdata(pdev);
 | 
						|
 
 | 
						|
+	/*
 | 
						|
+	 * We have to call dw_dma_disable() to stop any ongoing transfer. On
 | 
						|
+	 * some platforms we can't do that since DMA device is powered off.
 | 
						|
+	 * Moreover we have no possibility to check if the platform is affected
 | 
						|
+	 * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put()
 | 
						|
+	 * unconditionally. On the other hand we can't use
 | 
						|
+	 * pm_runtime_suspended() because runtime PM framework is not fully
 | 
						|
+	 * used by the driver.
 | 
						|
+	 */
 | 
						|
+	pm_runtime_get_sync(chip->dev);
 | 
						|
 	dw_dma_disable(chip);
 | 
						|
+	pm_runtime_put_sync_suspend(chip->dev);
 | 
						|
+
 | 
						|
 	clk_disable_unprepare(chip->clk);
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -252,17 +265,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_tab
 | 
						|
 #endif
 | 
						|
 
 | 
						|
 #ifdef CONFIG_ACPI
 | 
						|
-static struct dw_dma_platform_data dw_dma_acpi_pdata = {
 | 
						|
-	.nr_channels = 8,
 | 
						|
-	.is_private = true,
 | 
						|
-	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
 | 
						|
-	.chan_priority = CHAN_PRIORITY_ASCENDING,
 | 
						|
-	.block_size = 4095,
 | 
						|
-	.nr_masters = 2,
 | 
						|
-};
 | 
						|
-
 | 
						|
 static const struct acpi_device_id dw_dma_acpi_id_table[] = {
 | 
						|
-	{ "INTL9C60", (kernel_ulong_t)&dw_dma_acpi_pdata },
 | 
						|
+	{ "INTL9C60", 0 },
 | 
						|
 	{ }
 | 
						|
 };
 | 
						|
 MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
 | 
						|
--- a/drivers/dma/dw/regs.h
 | 
						|
+++ b/drivers/dma/dw/regs.h
 | 
						|
@@ -114,10 +114,6 @@ struct dw_dma_regs {
 | 
						|
 #define dma_writel_native writel
 | 
						|
 #endif
 | 
						|
 
 | 
						|
-/* To access the registers in early stage of probe */
 | 
						|
-#define dma_read_byaddr(addr, name) \
 | 
						|
-	dma_readl_native((addr) + offsetof(struct dw_dma_regs, name))
 | 
						|
-
 | 
						|
 /* Bitfields in DW_PARAMS */
 | 
						|
 #define DW_PARAMS_NR_CHAN	8		/* number of channels */
 | 
						|
 #define DW_PARAMS_NR_MASTER	11		/* number of AHB masters */
 | 
						|
@@ -143,6 +139,10 @@ enum dw_dma_msize {
 | 
						|
 	DW_DMA_MSIZE_256,
 | 
						|
 };
 | 
						|
 
 | 
						|
+/* Bitfields in LLP */
 | 
						|
+#define DWC_LLP_LMS(x)		((x) & 3)	/* list master select */
 | 
						|
+#define DWC_LLP_LOC(x)		((x) & ~3)	/* next lli */
 | 
						|
+
 | 
						|
 /* Bitfields in CTL_LO */
 | 
						|
 #define DWC_CTLL_INT_EN		(1 << 0)	/* irqs enabled? */
 | 
						|
 #define DWC_CTLL_DST_WIDTH(n)	((n)<<1)	/* bytes per element */
 | 
						|
@@ -150,7 +150,7 @@ enum dw_dma_msize {
 | 
						|
 #define DWC_CTLL_DST_INC	(0<<7)		/* DAR update/not */
 | 
						|
 #define DWC_CTLL_DST_DEC	(1<<7)
 | 
						|
 #define DWC_CTLL_DST_FIX	(2<<7)
 | 
						|
-#define DWC_CTLL_SRC_INC	(0<<7)		/* SAR update/not */
 | 
						|
+#define DWC_CTLL_SRC_INC	(0<<9)		/* SAR update/not */
 | 
						|
 #define DWC_CTLL_SRC_DEC	(1<<9)
 | 
						|
 #define DWC_CTLL_SRC_FIX	(2<<9)
 | 
						|
 #define DWC_CTLL_DST_MSIZE(n)	((n)<<11)	/* burst, #elements */
 | 
						|
@@ -216,6 +216,8 @@ enum dw_dma_msize {
 | 
						|
 enum dw_dmac_flags {
 | 
						|
 	DW_DMA_IS_CYCLIC = 0,
 | 
						|
 	DW_DMA_IS_SOFT_LLP = 1,
 | 
						|
+	DW_DMA_IS_PAUSED = 2,
 | 
						|
+	DW_DMA_IS_INITIALIZED = 3,
 | 
						|
 };
 | 
						|
 
 | 
						|
 struct dw_dma_chan {
 | 
						|
@@ -224,8 +226,6 @@ struct dw_dma_chan {
 | 
						|
 	u8				mask;
 | 
						|
 	u8				priority;
 | 
						|
 	enum dma_transfer_direction	direction;
 | 
						|
-	bool				paused;
 | 
						|
-	bool				initialized;
 | 
						|
 
 | 
						|
 	/* software emulation of the LLP transfers */
 | 
						|
 	struct list_head	*tx_node_active;
 | 
						|
@@ -236,8 +236,6 @@ struct dw_dma_chan {
 | 
						|
 	unsigned long		flags;
 | 
						|
 	struct list_head	active_list;
 | 
						|
 	struct list_head	queue;
 | 
						|
-	struct list_head	free_list;
 | 
						|
-	u32			residue;
 | 
						|
 	struct dw_cyclic_desc	*cdesc;
 | 
						|
 
 | 
						|
 	unsigned int		descs_allocated;
 | 
						|
@@ -249,8 +247,8 @@ struct dw_dma_chan {
 | 
						|
 	/* custom slave configuration */
 | 
						|
 	u8			src_id;
 | 
						|
 	u8			dst_id;
 | 
						|
-	u8			src_master;
 | 
						|
-	u8			dst_master;
 | 
						|
+	u8			m_master;
 | 
						|
+	u8			p_master;
 | 
						|
 
 | 
						|
 	/* configuration passed via .device_config */
 | 
						|
 	struct dma_slave_config dma_sconfig;
 | 
						|
@@ -283,9 +281,8 @@ struct dw_dma {
 | 
						|
 	u8			all_chan_mask;
 | 
						|
 	u8			in_use;
 | 
						|
 
 | 
						|
-	/* hardware configuration */
 | 
						|
-	unsigned char		nr_masters;
 | 
						|
-	unsigned char		data_width[DW_DMA_MAX_NR_MASTERS];
 | 
						|
+	/* platform data */
 | 
						|
+	struct dw_dma_platform_data	*pdata;
 | 
						|
 };
 | 
						|
 
 | 
						|
 static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
 | 
						|
@@ -308,32 +305,51 @@ static inline struct dw_dma *to_dw_dma(s
 | 
						|
 	return container_of(ddev, struct dw_dma, dma);
 | 
						|
 }
 | 
						|
 
 | 
						|
+#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
 | 
						|
+typedef __be32 __dw32;
 | 
						|
+#else
 | 
						|
+typedef __le32 __dw32;
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 /* LLI == Linked List Item; a.k.a. DMA block descriptor */
 | 
						|
 struct dw_lli {
 | 
						|
 	/* values that are not changed by hardware */
 | 
						|
-	u32		sar;
 | 
						|
-	u32		dar;
 | 
						|
-	u32		llp;		/* chain to next lli */
 | 
						|
-	u32		ctllo;
 | 
						|
+	__dw32		sar;
 | 
						|
+	__dw32		dar;
 | 
						|
+	__dw32		llp;		/* chain to next lli */
 | 
						|
+	__dw32		ctllo;
 | 
						|
 	/* values that may get written back: */
 | 
						|
-	u32		ctlhi;
 | 
						|
+	__dw32		ctlhi;
 | 
						|
 	/* sstat and dstat can snapshot peripheral register state.
 | 
						|
 	 * silicon config may discard either or both...
 | 
						|
 	 */
 | 
						|
-	u32		sstat;
 | 
						|
-	u32		dstat;
 | 
						|
+	__dw32		sstat;
 | 
						|
+	__dw32		dstat;
 | 
						|
 };
 | 
						|
 
 | 
						|
 struct dw_desc {
 | 
						|
 	/* FIRST values the hardware uses */
 | 
						|
 	struct dw_lli			lli;
 | 
						|
 
 | 
						|
+#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
 | 
						|
+#define lli_set(d, reg, v)		((d)->lli.reg |= cpu_to_be32(v))
 | 
						|
+#define lli_clear(d, reg, v)		((d)->lli.reg &= ~cpu_to_be32(v))
 | 
						|
+#define lli_read(d, reg)		be32_to_cpu((d)->lli.reg)
 | 
						|
+#define lli_write(d, reg, v)		((d)->lli.reg = cpu_to_be32(v))
 | 
						|
+#else
 | 
						|
+#define lli_set(d, reg, v)		((d)->lli.reg |= cpu_to_le32(v))
 | 
						|
+#define lli_clear(d, reg, v)		((d)->lli.reg &= ~cpu_to_le32(v))
 | 
						|
+#define lli_read(d, reg)		le32_to_cpu((d)->lli.reg)
 | 
						|
+#define lli_write(d, reg, v)		((d)->lli.reg = cpu_to_le32(v))
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 	/* THEN values for driver housekeeping */
 | 
						|
 	struct list_head		desc_node;
 | 
						|
 	struct list_head		tx_list;
 | 
						|
 	struct dma_async_tx_descriptor	txd;
 | 
						|
 	size_t				len;
 | 
						|
 	size_t				total_len;
 | 
						|
+	u32				residue;
 | 
						|
 };
 | 
						|
 
 | 
						|
 #define to_dw_desc(h)	list_entry(h, struct dw_desc, desc_node)
 | 
						|
--- a/include/linux/dma/dw.h
 | 
						|
+++ b/include/linux/dma/dw.h
 | 
						|
@@ -27,6 +27,7 @@ struct dw_dma;
 | 
						|
  * @regs:		memory mapped I/O space
 | 
						|
  * @clk:		hclk clock
 | 
						|
  * @dw:			struct dw_dma that is filed by dw_dma_probe()
 | 
						|
+ * @pdata:		pointer to platform data
 | 
						|
  */
 | 
						|
 struct dw_dma_chip {
 | 
						|
 	struct device	*dev;
 | 
						|
@@ -34,10 +35,12 @@ struct dw_dma_chip {
 | 
						|
 	void __iomem	*regs;
 | 
						|
 	struct clk	*clk;
 | 
						|
 	struct dw_dma	*dw;
 | 
						|
+
 | 
						|
+	const struct dw_dma_platform_data	*pdata;
 | 
						|
 };
 | 
						|
 
 | 
						|
 /* Export to the platform drivers */
 | 
						|
-int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata);
 | 
						|
+int dw_dma_probe(struct dw_dma_chip *chip);
 | 
						|
 int dw_dma_remove(struct dw_dma_chip *chip);
 | 
						|
 
 | 
						|
 /* DMA API extensions */
 | 
						|
--- a/include/linux/platform_data/dma-dw.h
 | 
						|
+++ b/include/linux/platform_data/dma-dw.h
 | 
						|
@@ -21,15 +21,15 @@
 | 
						|
  * @dma_dev:	required DMA master device
 | 
						|
  * @src_id:	src request line
 | 
						|
  * @dst_id:	dst request line
 | 
						|
- * @src_master: src master for transfers on allocated channel.
 | 
						|
- * @dst_master: dest master for transfers on allocated channel.
 | 
						|
+ * @m_master:	memory master for transfers on allocated channel
 | 
						|
+ * @p_master:	peripheral master for transfers on allocated channel
 | 
						|
  */
 | 
						|
 struct dw_dma_slave {
 | 
						|
 	struct device		*dma_dev;
 | 
						|
 	u8			src_id;
 | 
						|
 	u8			dst_id;
 | 
						|
-	u8			src_master;
 | 
						|
-	u8			dst_master;
 | 
						|
+	u8			m_master;
 | 
						|
+	u8			p_master;
 | 
						|
 };
 | 
						|
 
 | 
						|
 /**
 | 
						|
@@ -43,7 +43,7 @@ struct dw_dma_slave {
 | 
						|
  * @block_size: Maximum block size supported by the controller
 | 
						|
  * @nr_masters: Number of AHB masters supported by the controller
 | 
						|
  * @data_width: Maximum data width supported by hardware per AHB master
 | 
						|
- *		(0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
 | 
						|
+ *		(in bytes, power of 2)
 | 
						|
  */
 | 
						|
 struct dw_dma_platform_data {
 | 
						|
 	unsigned int	nr_channels;
 | 
						|
@@ -55,7 +55,7 @@ struct dw_dma_platform_data {
 | 
						|
 #define CHAN_PRIORITY_ASCENDING		0	/* chan0 highest */
 | 
						|
 #define CHAN_PRIORITY_DESCENDING	1	/* chan7 highest */
 | 
						|
 	unsigned char	chan_priority;
 | 
						|
-	unsigned short	block_size;
 | 
						|
+	unsigned int	block_size;
 | 
						|
 	unsigned char	nr_masters;
 | 
						|
 	unsigned char	data_width[DW_DMA_MAX_NR_MASTERS];
 | 
						|
 };
 |