* [PATCH v4 1/4] dw_dmac: remove unnecessary tx_list field in dw_dma_chan
2013-01-25 9:47 [PATCH v4 0/4] dw_dmac: return actual residue value Andy Shevchenko
@ 2013-01-25 9:48 ` Andy Shevchenko
2013-01-25 9:48 ` [PATCH v4 2/4] dw_dmac: introduce total_len field in struct dw_desc Andy Shevchenko
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2013-01-25 9:48 UTC (permalink / raw)
To: Viresh Kumar, Vinod Koul, linux-kernel, spear-devel; +Cc: Andy Shevchenko
The soft LLP mode is working for active descriptor only. So, we do not need to
have a copy of its pointer.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/dma/dw_dmac.c | 20 +++++++++++++++-----
drivers/dma/dw_dmac_regs.h | 1 -
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 72e6316..e4e4ff2 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -284,9 +284,9 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
dwc_initialize(dwc);
- dwc->tx_list = &first->tx_list;
dwc->tx_node_active = &first->tx_list;
+ /* Submit first block */
dwc_do_single_block(dwc, first);
return;
@@ -404,15 +404,25 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
dma_writel(dw, CLEAR.XFER, dwc->mask);
if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
- if (dwc->tx_node_active != dwc->tx_list) {
- desc = to_dw_desc(dwc->tx_node_active);
+ struct list_head *head, *active = dwc->tx_node_active;
+
+ /*
+ * We are inside first active descriptor.
+ * Otherwise something is really wrong.
+ */
+ desc = dwc_first_active(dwc);
+
+ head = &desc->tx_list;
+ if (active != head) {
+ child = to_dw_desc(active);
/* Submit next block */
- dwc_do_single_block(dwc, desc);
- spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc_do_single_block(dwc, child);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
+
/* We are done here */
clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
}
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index fef296d..13000d2 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -194,7 +194,6 @@ struct dw_dma_chan {
bool initialized;
/* software emulation of the LLP transfers */
- struct list_head *tx_list;
struct list_head *tx_node_active;
spinlock_t lock;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 2/4] dw_dmac: introduce total_len field in struct dw_desc
2013-01-25 9:47 [PATCH v4 0/4] dw_dmac: return actual residue value Andy Shevchenko
2013-01-25 9:48 ` [PATCH v4 1/4] dw_dmac: remove unnecessary tx_list field in dw_dma_chan Andy Shevchenko
@ 2013-01-25 9:48 ` Andy Shevchenko
2013-01-25 9:48 ` [PATCH v4 3/4] dw_dmac: fill individual length of descriptor Andy Shevchenko
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2013-01-25 9:48 UTC (permalink / raw)
To: Viresh Kumar, Vinod Koul, linux-kernel, spear-devel; +Cc: Andy Shevchenko
By this new field we distinguish a total length of the chain and the individual
length of each descriptor in the chain.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/dma/dw_dmac.c | 12 ++++++------
drivers/dma/dw_dmac_regs.h | 1 +
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index e4e4ff2..7b5a088 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -335,18 +335,18 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
dma_unmap_single(parent, desc->lli.dar,
- desc->len, DMA_FROM_DEVICE);
+ desc->total_len, DMA_FROM_DEVICE);
else
dma_unmap_page(parent, desc->lli.dar,
- desc->len, DMA_FROM_DEVICE);
+ desc->total_len, DMA_FROM_DEVICE);
}
if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
dma_unmap_single(parent, desc->lli.sar,
- desc->len, DMA_TO_DEVICE);
+ desc->total_len, DMA_TO_DEVICE);
else
dma_unmap_page(parent, desc->lli.sar,
- desc->len, DMA_TO_DEVICE);
+ desc->total_len, DMA_TO_DEVICE);
}
}
@@ -776,7 +776,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
prev->lli.llp = 0;
first->txd.flags = flags;
- first->len = len;
+ first->total_len = len;
return &first->txd;
@@ -939,7 +939,7 @@ slave_sg_fromdev_fill_desc:
prev->lli.ctllo |= DWC_CTLL_INT_EN;
prev->lli.llp = 0;
- first->len = total_len;
+ first->total_len = total_len;
return &first->txd;
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 13000d2..833b4cf 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -296,6 +296,7 @@ struct dw_desc {
struct list_head tx_list;
struct dma_async_tx_descriptor txd;
size_t len;
+ size_t total_len;
};
#define to_dw_desc(h) list_entry(h, struct dw_desc, desc_node)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 3/4] dw_dmac: fill individual length of descriptor
2013-01-25 9:47 [PATCH v4 0/4] dw_dmac: return actual residue value Andy Shevchenko
2013-01-25 9:48 ` [PATCH v4 1/4] dw_dmac: remove unnecessary tx_list field in dw_dma_chan Andy Shevchenko
2013-01-25 9:48 ` [PATCH v4 2/4] dw_dmac: introduce total_len field in struct dw_desc Andy Shevchenko
@ 2013-01-25 9:48 ` Andy Shevchenko
2013-01-25 9:48 ` [PATCH v4 4/4] dw_dmac: return proper residue value Andy Shevchenko
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2013-01-25 9:48 UTC (permalink / raw)
To: Viresh Kumar, Vinod Koul, linux-kernel, spear-devel; +Cc: Andy Shevchenko
It will be useful to have the length of the transfer in the descriptor. The
cyclic transfer functions remained untouched.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/dma/dw_dmac.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 7b5a088..3b788c8 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -759,6 +759,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
desc->lli.dar = dest + offset;
desc->lli.ctllo = ctllo;
desc->lli.ctlhi = xfer_count;
+ desc->len = xfer_count << src_width;
if (!first) {
first = desc;
@@ -857,6 +858,7 @@ slave_sg_todev_fill_desc:
}
desc->lli.ctlhi = dlen >> mem_width;
+ desc->len = dlen;
if (!first) {
first = desc;
@@ -915,6 +917,7 @@ slave_sg_fromdev_fill_desc:
len = 0;
}
desc->lli.ctlhi = dlen >> reg_width;
+ desc->len = dlen;
if (!first) {
first = desc;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 4/4] dw_dmac: return proper residue value
2013-01-25 9:47 [PATCH v4 0/4] dw_dmac: return actual residue value Andy Shevchenko
` (2 preceding siblings ...)
2013-01-25 9:48 ` [PATCH v4 3/4] dw_dmac: fill individual length of descriptor Andy Shevchenko
@ 2013-01-25 9:48 ` Andy Shevchenko
2013-01-25 9:55 ` [PATCH v4 0/4] dw_dmac: return actual " Viresh Kumar
2013-01-28 12:06 ` Vinod Koul
5 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2013-01-25 9:48 UTC (permalink / raw)
To: Viresh Kumar, Vinod Koul, linux-kernel, spear-devel; +Cc: Andy Shevchenko
Currently the driver returns full length of the active descriptor which is
wrong. We have to go throught the active descriptor and substract the length of
each sent children in the chain from the total length along with the actual
data in the DMA channel registers.
The cyclic case is not handled by this patch due to len field in the descriptor
structure is left untouched by the original code.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/dma/dw_dmac.c | 47 ++++++++++++++++++++++++++++++++++++++++++--
drivers/dma/dw_dmac_regs.h | 1 +
2 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 3b788c8..b5c3f3a 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -284,6 +284,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
dwc_initialize(dwc);
+ dwc->residue = first->total_len;
dwc->tx_node_active = &first->tx_list;
/* Submit first block */
@@ -387,6 +388,15 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
dwc_descriptor_complete(dwc, desc, true);
}
+/* Returns how many bytes were already received from source */
+static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
+{
+ u32 ctlhi = channel_readl(dwc, CTL_HI);
+ u32 ctllo = channel_readl(dwc, CTL_LO);
+
+ return (ctlhi & DWC_CTLH_BLOCK_TS_MASK) * (1 << (ctllo >> 4 & 7));
+}
+
static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
{
dma_addr_t llp;
@@ -414,6 +424,12 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
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;
+
child = to_dw_desc(active);
/* Submit next block */
@@ -426,6 +442,9 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
/* We are done here */
clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
}
+
+ dwc->residue = 0;
+
spin_unlock_irqrestore(&dwc->lock, flags);
dwc_complete_all(dw, dwc);
@@ -433,6 +452,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
}
if (list_empty(&dwc->active_list)) {
+ dwc->residue = 0;
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
@@ -447,6 +467,9 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
(unsigned long long)llp);
list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
+ /* initial residue value */
+ dwc->residue = desc->total_len;
+
/* check first descriptors addr */
if (desc->txd.phys == llp) {
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -456,16 +479,21 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
/* check first descriptors llp */
if (desc->lli.llp == llp) {
/* This one is currently in progress */
+ dwc->residue -= dwc_get_sent(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
- list_for_each_entry(child, &desc->tx_list, desc_node)
+ dwc->residue -= desc->len;
+ list_for_each_entry(child, &desc->tx_list, desc_node) {
if (child->lli.llp == llp) {
/* Currently in progress */
+ dwc->residue -= dwc_get_sent(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
+ dwc->residue -= child->len;
+ }
/*
* No descriptors so far seem to be in progress, i.e.
@@ -1056,6 +1084,21 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
return 0;
}
+static inline u32 dwc_get_residue(struct dw_dma_chan *dwc)
+{
+ 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);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return residue;
+}
+
static enum dma_status
dwc_tx_status(struct dma_chan *chan,
dma_cookie_t cookie,
@@ -1072,7 +1115,7 @@ dwc_tx_status(struct dma_chan *chan,
}
if (ret != DMA_SUCCESS)
- dma_set_residue(txstate, dwc_first_active(dwc)->len);
+ dma_set_residue(txstate, dwc_get_residue(dwc));
if (dwc->paused)
return DMA_PAUSED;
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 833b4cf..88dd8eb 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -203,6 +203,7 @@ struct dw_dma_chan {
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;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v4 0/4] dw_dmac: return actual residue value
2013-01-25 9:47 [PATCH v4 0/4] dw_dmac: return actual residue value Andy Shevchenko
` (3 preceding siblings ...)
2013-01-25 9:48 ` [PATCH v4 4/4] dw_dmac: return proper residue value Andy Shevchenko
@ 2013-01-25 9:55 ` Viresh Kumar
2013-01-28 12:06 ` Vinod Koul
5 siblings, 0 replies; 7+ messages in thread
From: Viresh Kumar @ 2013-01-25 9:55 UTC (permalink / raw)
To: Andy Shevchenko; +Cc: Vinod Koul, linux-kernel, spear-devel
On Fri, Jan 25, 2013 at 3:17 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> The patch series is targeted for getting proper residue value.
>
> Since v3:
> - split dwc_get_residue() from dwc_tx_status and improve locking there
> - patch 1/4 "dw_dmac: remove unnecessary tx_list field in dw_dma_chan" was
> amended a bit to simplify patch 4/4
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v4 0/4] dw_dmac: return actual residue value
2013-01-25 9:47 [PATCH v4 0/4] dw_dmac: return actual residue value Andy Shevchenko
` (4 preceding siblings ...)
2013-01-25 9:55 ` [PATCH v4 0/4] dw_dmac: return actual " Viresh Kumar
@ 2013-01-28 12:06 ` Vinod Koul
5 siblings, 0 replies; 7+ messages in thread
From: Vinod Koul @ 2013-01-28 12:06 UTC (permalink / raw)
To: Andy Shevchenko; +Cc: Viresh Kumar, linux-kernel, spear-devel
On Fri, Jan 25, 2013 at 11:47:59AM +0200, Andy Shevchenko wrote:
> The patch series is targeted for getting proper residue value.
Applied, thanks
--
~Vinod
^ permalink raw reply [flat|nested] 7+ messages in thread