2012-06-15 07:05:33

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 0/9] dw_dmac: set of cleanups and small fixes

This patchset provides set of the cleanups and small fixes against the
DesignWare DMA controller driver. It's a first portion of the patches to make
the driver usable on other platforms.

Andy Shevchenko (9):
dw_dmac: fix constant in the comment
dw_dmac: use proper casting to print dma_addr_t values
dw_dmac: introduce dwc_dump_chan_regs to dump registers
dw_dmac: print correct number of scanned descriptors
dw_dmac: use __func__ constant in the debug prints
dw_dmac: disable dma in optimal way in probe
dw_dmac: disable BLOCK interrupts
dw_dmac: introduce dwc_fast_fls()
dw_dmac: move from __init to __devinit

drivers/dma/dw_dmac.c | 148 ++++++++++++++++++++------------------------
drivers/dma/dw_dmac_regs.h | 2 +-
2 files changed, 69 insertions(+), 81 deletions(-)

--
1.7.10


2012-06-15 07:05:34

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 1/9] dw_dmac: fix constant in the comment

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac_regs.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index f298f69..e248481 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -82,7 +82,7 @@ struct dw_dma_regs {
DW_REG(ID);
DW_REG(TEST);

- /* optional encoded params, 0x3c8..0x3 */
+ /* optional encoded params, 0x3c8..0x3f7 */
};

/* Bitfields in CTL_LO */
--
1.7.10

2012-06-15 07:05:37

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 5/9] dw_dmac: use __func__ constant in the debug prints

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 763730a..e2ea243 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -346,7 +346,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
return;
}

- dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%llx\n",
+ dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
(unsigned long long)llp);

list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
@@ -533,7 +533,7 @@ static void dw_dma_tasklet(unsigned long data)
status_xfer = dma_readl(dw, RAW.XFER);
status_err = dma_readl(dw, RAW.ERROR);

- dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err);
+ dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err);

for (i = 0; i < dw->dma.chancnt; i++) {
dwc = &dw->chan[i];
@@ -557,7 +557,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
struct dw_dma *dw = dev_id;
u32 status;

- dev_vdbg(dw->dma.dev, "interrupt: status=0x%x\n",
+ dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__,
dma_readl(dw, STATUS_INT));

/*
@@ -603,12 +603,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
* for DMA. But this is hard to do in a race-free manner.
*/
if (list_empty(&dwc->active_list)) {
- dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
+ dev_vdbg(chan2dev(tx->chan), "%s: started %u\n", __func__,
desc->txd.cookie);
list_add_tail(&desc->desc_node, &dwc->active_list);
dwc_dostart(dwc, dwc_first_active(dwc));
} else {
- dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+ dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__,
desc->txd.cookie);

list_add_tail(&desc->desc_node, &dwc->queue);
@@ -634,12 +634,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
u32 ctllo;

dev_vdbg(chan2dev(chan),
- "prep_dma_memcpy d0x%llx s0x%llx l0x%zx f0x%lx\n",
+ "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
(unsigned long long)dest, (unsigned long long)src,
len, flags);

if (unlikely(!len)) {
- dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+ dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
return NULL;
}

@@ -728,7 +728,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct scatterlist *sg;
size_t total_len = 0;

- dev_vdbg(chan2dev(chan), "prep_dma_slave\n");
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);

if (unlikely(!dws || !sg_len))
return NULL;
@@ -1022,7 +1022,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
int i;
unsigned long flags;

- dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);

/* ASSERT: channel is idle */
if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -1065,8 +1065,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)

spin_unlock_irqrestore(&dwc->lock, flags);

- dev_dbg(chan2dev(chan),
- "alloc_chan_resources allocated %d descriptors\n", i);
+ dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);

return i;
}
@@ -1079,7 +1078,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
unsigned long flags;
LIST_HEAD(list);

- dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
+ dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
dwc->descs_allocated);

/* ASSERT: channel is idle */
@@ -1105,7 +1104,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
kfree(desc);
}

- dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
+ dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}

/* --------------------- Cyclic DMA API extensions -------------------- */
@@ -1342,7 +1341,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
int i;
unsigned long flags;

- dev_dbg(chan2dev(&dwc->chan), "cyclic free\n");
+ dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);

if (!cdesc)
return;
--
1.7.10

2012-06-15 07:05:43

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 4/9] dw_dmac: print correct number of scanned descriptors

In case the first descriptor we found is available, the counter still remains 0
value which is wrong. This patch fixes the counter behaviour.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index b6251dc..763730a 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -107,13 +107,13 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)

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);
- i++;
}
spin_unlock_irqrestore(&dwc->lock, flags);

--
1.7.10

2012-06-15 07:05:39

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 9/9] dw_dmac: move from __init to __devinit

We usually have more than one DMA device. Thus, the probe function should serve
for all of them in case when the driver is built as a module.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 5d025d3..5217f71 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1379,7 +1379,7 @@ static void dw_dma_off(struct dw_dma *dw)
dw->chan[i].initialized = false;
}

-static int __init dw_probe(struct platform_device *pdev)
+static int __devinit dw_probe(struct platform_device *pdev)
{
struct dw_dma_platform_data *pdata;
struct resource *io;
@@ -1513,7 +1513,7 @@ err_kfree:
return err;
}

-static int __exit dw_remove(struct platform_device *pdev)
+static int __devexit dw_remove(struct platform_device *pdev)
{
struct dw_dma *dw = platform_get_drvdata(pdev);
struct dw_dma_chan *dwc, *_dwc;
@@ -1592,7 +1592,7 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table);
#endif

static struct platform_driver dw_driver = {
- .remove = __exit_p(dw_remove),
+ .remove = __devexit_p(dw_remove),
.shutdown = dw_shutdown,
.driver = {
.name = "dw_dmac",
--
1.7.10

2012-06-15 07:06:10

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 8/9] dw_dmac: introduce dwc_fast_fls()

There were three places where such function is used. We still avoid to use
native fls() because in one case it requires to use 64bit version which is
suboptimal in our case.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 46 ++++++++++++++++++----------------------------
1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index b2586bd..5d025d3 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -193,6 +193,21 @@ static void dwc_initialize(struct dw_dma_chan *dwc)

/*----------------------------------------------------------------------*/

+static inline unsigned int dwc_fast_fls(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 void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
{
dev_err(chan2dev(&dwc->chan),
@@ -644,18 +659,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
return NULL;
}

- /*
- * We can be a lot more clever here, but this should take care
- * of the most common optimization.
- */
- if (!((src | dest | len) & 7))
- src_width = dst_width = 3;
- else if (!((src | dest | len) & 3))
- src_width = dst_width = 2;
- else if (!((src | dest | len) & 1))
- src_width = dst_width = 1;
- else
- src_width = dst_width = 0;
+ src_width = dst_width = dwc_fast_fls(src | dest | len);

ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width)
@@ -755,14 +759,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);

- if (!((mem | len) & 7))
- mem_width = 3;
- else if (!((mem | len) & 3))
- mem_width = 2;
- else if (!((mem | len) & 1))
- mem_width = 1;
- else
- mem_width = 0;
+ mem_width = dwc_fast_fls(mem | len);

slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc);
@@ -822,14 +819,7 @@ slave_sg_todev_fill_desc:
mem = sg_dma_address(sg);
len = sg_dma_len(sg);

- if (!((mem | len) & 7))
- mem_width = 3;
- else if (!((mem | len) & 3))
- mem_width = 2;
- else if (!((mem | len) & 1))
- mem_width = 1;
- else
- mem_width = 0;
+ mem_width = dwc_fast_fls(mem | len);

slave_sg_fromdev_fill_desc:
desc = dwc_desc_get(dwc);
--
1.7.10

2012-06-15 07:06:37

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 6/9] dw_dmac: disable dma in optimal way in probe

The dw_dma_off call needs to have the all_chan_mask calculated. So, done this
calculations before the call. Moreover, remove duplicate code that masks the
DMA interrupts.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index e2ea243..cffe630 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1433,6 +1433,9 @@ static int __init dw_probe(struct platform_device *pdev)
}
clk_prepare_enable(dw->clk);

+ /* Calculate all channel mask before DMA setup */
+ dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
+
/* force dma off, just in case */
dw_dma_off(dw);

@@ -1444,8 +1447,6 @@ static int __init dw_probe(struct platform_device *pdev)

tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);

- dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
-
INIT_LIST_HEAD(&dw->dma.channels);
for (i = 0; i < pdata->nr_channels; i++) {
struct dw_dma_chan *dwc = &dw->chan[i];
@@ -1481,11 +1482,6 @@ static int __init dw_probe(struct platform_device *pdev)
dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);

- channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
-
dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
if (pdata->is_private)
--
1.7.10

2012-06-15 07:06:35

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 7/9] dw_dmac: disable BLOCK interrupts

Just to be sure we are in known state we disable the BLOCK interupts.

Signed-off-by: Andy Shevchenko <[email protected]>
---
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 cffe630..b2586bd 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -575,6 +575,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)

/* Try to recover */
channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1);
+ channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1);
channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1);
channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1);
channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1);
@@ -1376,6 +1377,7 @@ static void dw_dma_off(struct dw_dma *dw)
dma_writel(dw, CFG, 0);

channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
+ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1478,6 +1480,7 @@ static int __init dw_probe(struct platform_device *pdev)

/* Clear/disable all interrupts on all channels. */
dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
+ dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
--
1.7.10

2012-06-15 07:07:01

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 3/9] dw_dmac: introduce dwc_dump_chan_regs to dump registers

There is three places where values of the most significant registers were
printed. Make such piece of code as separate function.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 37 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 45861b6..b6251dc 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -193,6 +193,19 @@ static void dwc_initialize(struct dw_dma_chan *dwc)

/*----------------------------------------------------------------------*/

+static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+{
+ dev_err(chan2dev(&dwc->chan),
+ " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
+ channel_readl(dwc, SAR),
+ channel_readl(dwc, DAR),
+ channel_readl(dwc, LLP),
+ channel_readl(dwc, CTL_HI),
+ channel_readl(dwc, CTL_LO));
+}
+
+/*----------------------------------------------------------------------*/
+
/* Called with dwc->lock held and bh disabled */
static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
{
@@ -202,13 +215,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
if (dma_readl(dw, CH_EN) & dwc->mask) {
dev_err(chan2dev(&dwc->chan),
"BUG: Attempted to start non-idle channel\n");
- dev_err(chan2dev(&dwc->chan),
- " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
- channel_readl(dwc, SAR),
- channel_readl(dwc, DAR),
- channel_readl(dwc, LLP),
- channel_readl(dwc, CTL_HI),
- channel_readl(dwc, CTL_LO));
+ dwc_dump_chan_regs(dwc);

/* The tasklet will hopefully advance the queue... */
return;
@@ -492,13 +499,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,

spin_lock_irqsave(&dwc->lock, flags);

- dev_err(chan2dev(&dwc->chan),
- " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
- channel_readl(dwc, SAR),
- channel_readl(dwc, DAR),
- channel_readl(dwc, LLP),
- channel_readl(dwc, CTL_HI),
- channel_readl(dwc, CTL_LO));
+ dwc_dump_chan_regs(dwc);

channel_clear_bit(dw, CH_EN, dwc->mask);
while (dma_readl(dw, CH_EN) & dwc->mask)
@@ -1133,13 +1134,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
if (dma_readl(dw, CH_EN) & dwc->mask) {
dev_err(chan2dev(&dwc->chan),
"BUG: Attempted to start non-idle channel\n");
- dev_err(chan2dev(&dwc->chan),
- " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
- channel_readl(dwc, SAR),
- channel_readl(dwc, DAR),
- channel_readl(dwc, LLP),
- channel_readl(dwc, CTL_HI),
- channel_readl(dwc, CTL_LO));
+ dwc_dump_chan_regs(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return -EBUSY;
}
--
1.7.10

2012-06-15 07:07:33

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH 2/9] dw_dmac: use proper casting to print dma_addr_t values

dma_addr_t is sometimes 32 bit and sometimes 64. We normally cast them to
unsigned long long for printk().

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index adbc616..45861b6 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -339,7 +339,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
return;
}

- dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
+ dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%llx\n",
+ (unsigned long long)llp);

list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
/* check first descriptors addr */
@@ -389,8 +390,10 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
{
dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
- " desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
- lli->sar, lli->dar, lli->llp,
+ " desc: s0x%llx d0x%llx l0x%llx c0x%x:%x\n",
+ (unsigned long long)lli->sar,
+ (unsigned long long)lli->dar,
+ (unsigned long long)lli->llp,
lli->ctlhi, lli->ctllo);
}

@@ -629,8 +632,10 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
unsigned int dst_width;
u32 ctllo;

- dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n",
- dest, src, len, flags);
+ dev_vdbg(chan2dev(chan),
+ "prep_dma_memcpy d0x%llx s0x%llx l0x%zx f0x%lx\n",
+ (unsigned long long)dest, (unsigned long long)src,
+ len, flags);

if (unlikely(!len)) {
dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
@@ -1310,9 +1315,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
dma_sync_single_for_device(chan2parent(chan), last->txd.phys,
sizeof(last->lli), DMA_TO_DEVICE);

- dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%08x len %zu "
- "period %zu periods %d\n", buf_addr, buf_len,
- period_len, periods);
+ dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu "
+ "period %zu periods %d\n", (unsigned long long)buf_addr,
+ buf_len, period_len, periods);

cdesc->periods = periods;
dwc->cdesc = cdesc;
--
1.7.10

2012-06-19 10:34:30

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 00/10] dw_dmac: set of cleanups and small fixes

This patchset provides set of the cleanups and small fixes against the
DesignWare DMA controller driver. It's a first portion of the patches to make
the driver usable on other platforms.

since v1:
- add dwc_chan_reset
- disable block interrupts only in probe (discussed with Viresh Kumar)
- fix comment line in probe in patch 6

Andy Shevchenko (10):
dw_dmac: fix constant in the comment
dw_dmac: use proper casting to print dma_addr_t values
dw_dmac: introduce dwc_dump_chan_regs to dump registers
dw_dmac: print correct number of scanned descriptors
dw_dmac: use __func__ constant in the debug prints
dw_dmac: disable dma in optimal way in probe
dw_dmac: disable BLOCK interrupts
dw_dmac: introduce dwc_fast_fls()
dw_dmac: move from __init to __devinit
dw_dmac: introduce dwc_chan_reset

drivers/dma/dw_dmac.c | 183 ++++++++++++++++++++------------------------
drivers/dma/dw_dmac_regs.h | 2 +-
2 files changed, 85 insertions(+), 100 deletions(-)

--
1.7.10

2012-06-19 10:34:34

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 03/10] dw_dmac: introduce dwc_dump_chan_regs to dump registers

There is three places where values of the most significant registers were
printed. Make such piece of code as separate function.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 37 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 45861b6..b6251dc 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -193,6 +193,19 @@ static void dwc_initialize(struct dw_dma_chan *dwc)

/*----------------------------------------------------------------------*/

+static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+{
+ dev_err(chan2dev(&dwc->chan),
+ " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
+ channel_readl(dwc, SAR),
+ channel_readl(dwc, DAR),
+ channel_readl(dwc, LLP),
+ channel_readl(dwc, CTL_HI),
+ channel_readl(dwc, CTL_LO));
+}
+
+/*----------------------------------------------------------------------*/
+
/* Called with dwc->lock held and bh disabled */
static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
{
@@ -202,13 +215,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
if (dma_readl(dw, CH_EN) & dwc->mask) {
dev_err(chan2dev(&dwc->chan),
"BUG: Attempted to start non-idle channel\n");
- dev_err(chan2dev(&dwc->chan),
- " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
- channel_readl(dwc, SAR),
- channel_readl(dwc, DAR),
- channel_readl(dwc, LLP),
- channel_readl(dwc, CTL_HI),
- channel_readl(dwc, CTL_LO));
+ dwc_dump_chan_regs(dwc);

/* The tasklet will hopefully advance the queue... */
return;
@@ -492,13 +499,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,

spin_lock_irqsave(&dwc->lock, flags);

- dev_err(chan2dev(&dwc->chan),
- " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
- channel_readl(dwc, SAR),
- channel_readl(dwc, DAR),
- channel_readl(dwc, LLP),
- channel_readl(dwc, CTL_HI),
- channel_readl(dwc, CTL_LO));
+ dwc_dump_chan_regs(dwc);

channel_clear_bit(dw, CH_EN, dwc->mask);
while (dma_readl(dw, CH_EN) & dwc->mask)
@@ -1133,13 +1134,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
if (dma_readl(dw, CH_EN) & dwc->mask) {
dev_err(chan2dev(&dwc->chan),
"BUG: Attempted to start non-idle channel\n");
- dev_err(chan2dev(&dwc->chan),
- " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
- channel_readl(dwc, SAR),
- channel_readl(dwc, DAR),
- channel_readl(dwc, LLP),
- channel_readl(dwc, CTL_HI),
- channel_readl(dwc, CTL_LO));
+ dwc_dump_chan_regs(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return -EBUSY;
}
--
1.7.10

2012-06-19 10:34:39

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 09/10] dw_dmac: move from __init to __devinit

We usually have more than one DMA device. Thus, the probe function should serve
for all of them in case when the driver is built as a module.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 9c47279..d3845ef 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1377,7 +1377,7 @@ static void dw_dma_off(struct dw_dma *dw)
dw->chan[i].initialized = false;
}

-static int __init dw_probe(struct platform_device *pdev)
+static int __devinit dw_probe(struct platform_device *pdev)
{
struct dw_dma_platform_data *pdata;
struct resource *io;
@@ -1514,7 +1514,7 @@ err_kfree:
return err;
}

-static int __exit dw_remove(struct platform_device *pdev)
+static int __devexit dw_remove(struct platform_device *pdev)
{
struct dw_dma *dw = platform_get_drvdata(pdev);
struct dw_dma_chan *dwc, *_dwc;
@@ -1593,7 +1593,7 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table);
#endif

static struct platform_driver dw_driver = {
- .remove = __exit_p(dw_remove),
+ .remove = __devexit_p(dw_remove),
.shutdown = dw_shutdown,
.driver = {
.name = "dw_dmac",
--
1.7.10

2012-06-19 10:34:38

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 08/10] dw_dmac: introduce dwc_fast_fls()

There were three places where such function is used. We still avoid to use
native fls() because in one case it requires to use 64bit version which is
suboptimal in our case.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 46 ++++++++++++++++++----------------------------
1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 42cffe8..9c47279 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -193,6 +193,21 @@ static void dwc_initialize(struct dw_dma_chan *dwc)

/*----------------------------------------------------------------------*/

+static inline unsigned int dwc_fast_fls(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 void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
{
dev_err(chan2dev(&dwc->chan),
@@ -643,18 +658,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
return NULL;
}

- /*
- * We can be a lot more clever here, but this should take care
- * of the most common optimization.
- */
- if (!((src | dest | len) & 7))
- src_width = dst_width = 3;
- else if (!((src | dest | len) & 3))
- src_width = dst_width = 2;
- else if (!((src | dest | len) & 1))
- src_width = dst_width = 1;
- else
- src_width = dst_width = 0;
+ src_width = dst_width = dwc_fast_fls(src | dest | len);

ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width)
@@ -754,14 +758,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);

- if (!((mem | len) & 7))
- mem_width = 3;
- else if (!((mem | len) & 3))
- mem_width = 2;
- else if (!((mem | len) & 1))
- mem_width = 1;
- else
- mem_width = 0;
+ mem_width = dwc_fast_fls(mem | len);

slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc);
@@ -821,14 +818,7 @@ slave_sg_todev_fill_desc:
mem = sg_dma_address(sg);
len = sg_dma_len(sg);

- if (!((mem | len) & 7))
- mem_width = 3;
- else if (!((mem | len) & 3))
- mem_width = 2;
- else if (!((mem | len) & 1))
- mem_width = 1;
- else
- mem_width = 0;
+ mem_width = dwc_fast_fls(mem | len);

slave_sg_fromdev_fill_desc:
desc = dwc_desc_get(dwc);
--
1.7.10

2012-06-19 10:34:37

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 07/10] dw_dmac: disable BLOCK interrupts

Just to be sure we are in known state we disable the BLOCK interupts.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 23a409b..42cffe8 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1439,6 +1439,9 @@ static int __init dw_probe(struct platform_device *pdev)
/* force dma off, just in case */
dw_dma_off(dw);

+ /* disable BLOCK interrupts as well */
+ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
+
err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw);
if (err)
goto err_irq;
@@ -1478,6 +1481,7 @@ static int __init dw_probe(struct platform_device *pdev)

/* Clear all interrupts on all channels. */
dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
+ dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
--
1.7.10

2012-06-19 10:35:27

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 10/10] dw_dmac: introduce dwc_chan_reset

This piece of code is used often. Make it as a separate function.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 32 ++++++++++++++------------------
1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index d3845ef..14fbee4 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -219,6 +219,14 @@ static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
channel_readl(dwc, CTL_LO));
}

+
+static inline void dwc_chan_reset(struct dw_dma *dw, struct dw_dma_chan *dwc)
+{
+ channel_clear_bit(dw, CH_EN, dwc->mask);
+ while (dma_readl(dw, CH_EN) & dwc->mask)
+ cpu_relax();
+}
+
/*----------------------------------------------------------------------*/

/* Called with dwc->lock held and bh disabled */
@@ -314,9 +322,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
"BUG: XFER bit set, but channel not idle!\n");

/* Try to continue after resetting the channel... */
- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_reset(dw, dwc);
}

/*
@@ -398,9 +404,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
"BUG: All descriptors done, but channel not idle!\n");

/* Try to continue after resetting the channel... */
- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_reset(dw, dwc);

if (!list_empty(&dwc->queue)) {
list_move(dwc->queue.next, &dwc->active_list);
@@ -516,9 +520,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,

dwc_dump_chan_regs(dwc);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_reset(dw, dwc);

/* make sure DMA does not restart by loading a new list */
channel_writel(dwc, LLP, 0);
@@ -948,9 +950,7 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
} else if (cmd == DMA_TERMINATE_ALL) {
spin_lock_irqsave(&dwc->lock, flags);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_reset(dw, dwc);

dwc->paused = false;

@@ -1158,9 +1158,7 @@ void dw_dma_cyclic_stop(struct dma_chan *chan)

spin_lock_irqsave(&dwc->lock, flags);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_reset(dw, dwc);

spin_unlock_irqrestore(&dwc->lock, flags);
}
@@ -1338,9 +1336,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)

spin_lock_irqsave(&dwc->lock, flags);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_reset(dw, dwc);

dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
--
1.7.10

2012-06-19 10:35:47

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 06/10] dw_dmac: disable dma in optimal way in probe

The dw_dma_off call needs to have the all_chan_mask calculated. So, done this
calculations before the call. Moreover, remove duplicate code that masks the
DMA interrupts.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index e2ea243..23a409b 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1433,6 +1433,9 @@ static int __init dw_probe(struct platform_device *pdev)
}
clk_prepare_enable(dw->clk);

+ /* Calculate all channel mask before DMA setup */
+ dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
+
/* force dma off, just in case */
dw_dma_off(dw);

@@ -1444,8 +1447,6 @@ static int __init dw_probe(struct platform_device *pdev)

tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);

- dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
-
INIT_LIST_HEAD(&dw->dma.channels);
for (i = 0; i < pdata->nr_channels; i++) {
struct dw_dma_chan *dwc = &dw->chan[i];
@@ -1475,17 +1476,12 @@ static int __init dw_probe(struct platform_device *pdev)
channel_clear_bit(dw, CH_EN, dwc->mask);
}

- /* Clear/disable all interrupts on all channels. */
+ /* Clear all interrupts on all channels. */
dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);

- channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
-
dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
if (pdata->is_private)
--
1.7.10

2012-06-19 10:36:05

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 05/10] dw_dmac: use __func__ constant in the debug prints

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 763730a..e2ea243 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -346,7 +346,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
return;
}

- dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%llx\n",
+ dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
(unsigned long long)llp);

list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
@@ -533,7 +533,7 @@ static void dw_dma_tasklet(unsigned long data)
status_xfer = dma_readl(dw, RAW.XFER);
status_err = dma_readl(dw, RAW.ERROR);

- dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err);
+ dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err);

for (i = 0; i < dw->dma.chancnt; i++) {
dwc = &dw->chan[i];
@@ -557,7 +557,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
struct dw_dma *dw = dev_id;
u32 status;

- dev_vdbg(dw->dma.dev, "interrupt: status=0x%x\n",
+ dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__,
dma_readl(dw, STATUS_INT));

/*
@@ -603,12 +603,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
* for DMA. But this is hard to do in a race-free manner.
*/
if (list_empty(&dwc->active_list)) {
- dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
+ dev_vdbg(chan2dev(tx->chan), "%s: started %u\n", __func__,
desc->txd.cookie);
list_add_tail(&desc->desc_node, &dwc->active_list);
dwc_dostart(dwc, dwc_first_active(dwc));
} else {
- dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+ dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__,
desc->txd.cookie);

list_add_tail(&desc->desc_node, &dwc->queue);
@@ -634,12 +634,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
u32 ctllo;

dev_vdbg(chan2dev(chan),
- "prep_dma_memcpy d0x%llx s0x%llx l0x%zx f0x%lx\n",
+ "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
(unsigned long long)dest, (unsigned long long)src,
len, flags);

if (unlikely(!len)) {
- dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+ dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
return NULL;
}

@@ -728,7 +728,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct scatterlist *sg;
size_t total_len = 0;

- dev_vdbg(chan2dev(chan), "prep_dma_slave\n");
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);

if (unlikely(!dws || !sg_len))
return NULL;
@@ -1022,7 +1022,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
int i;
unsigned long flags;

- dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);

/* ASSERT: channel is idle */
if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -1065,8 +1065,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)

spin_unlock_irqrestore(&dwc->lock, flags);

- dev_dbg(chan2dev(chan),
- "alloc_chan_resources allocated %d descriptors\n", i);
+ dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);

return i;
}
@@ -1079,7 +1078,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
unsigned long flags;
LIST_HEAD(list);

- dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
+ dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
dwc->descs_allocated);

/* ASSERT: channel is idle */
@@ -1105,7 +1104,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
kfree(desc);
}

- dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
+ dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}

/* --------------------- Cyclic DMA API extensions -------------------- */
@@ -1342,7 +1341,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
int i;
unsigned long flags;

- dev_dbg(chan2dev(&dwc->chan), "cyclic free\n");
+ dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);

if (!cdesc)
return;
--
1.7.10

2012-06-19 10:34:32

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 02/10] dw_dmac: use proper casting to print dma_addr_t values

dma_addr_t is sometimes 32 bit and sometimes 64. We normally cast them to
unsigned long long for printk().

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index adbc616..45861b6 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -339,7 +339,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
return;
}

- dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
+ dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%llx\n",
+ (unsigned long long)llp);

list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
/* check first descriptors addr */
@@ -389,8 +390,10 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
{
dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
- " desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
- lli->sar, lli->dar, lli->llp,
+ " desc: s0x%llx d0x%llx l0x%llx c0x%x:%x\n",
+ (unsigned long long)lli->sar,
+ (unsigned long long)lli->dar,
+ (unsigned long long)lli->llp,
lli->ctlhi, lli->ctllo);
}

@@ -629,8 +632,10 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
unsigned int dst_width;
u32 ctllo;

- dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n",
- dest, src, len, flags);
+ dev_vdbg(chan2dev(chan),
+ "prep_dma_memcpy d0x%llx s0x%llx l0x%zx f0x%lx\n",
+ (unsigned long long)dest, (unsigned long long)src,
+ len, flags);

if (unlikely(!len)) {
dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
@@ -1310,9 +1315,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
dma_sync_single_for_device(chan2parent(chan), last->txd.phys,
sizeof(last->lli), DMA_TO_DEVICE);

- dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%08x len %zu "
- "period %zu periods %d\n", buf_addr, buf_len,
- period_len, periods);
+ dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu "
+ "period %zu periods %d\n", (unsigned long long)buf_addr,
+ buf_len, period_len, periods);

cdesc->periods = periods;
dwc->cdesc = cdesc;
--
1.7.10

2012-06-19 10:36:33

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 04/10] dw_dmac: print correct number of scanned descriptors

In case the first descriptor we found is available, the counter still remains 0
value which is wrong. This patch fixes the counter behaviour.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index b6251dc..763730a 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -107,13 +107,13 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)

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);
- i++;
}
spin_unlock_irqrestore(&dwc->lock, flags);

--
1.7.10

2012-06-19 10:36:53

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2 01/10] dw_dmac: fix constant in the comment

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac_regs.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index f298f69..e248481 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -82,7 +82,7 @@ struct dw_dma_regs {
DW_REG(ID);
DW_REG(TEST);

- /* optional encoded params, 0x3c8..0x3 */
+ /* optional encoded params, 0x3c8..0x3f7 */
};

/* Bitfields in CTL_LO */
--
1.7.10

2012-06-19 10:39:41

by viresh kumar

[permalink] [raw]
Subject: Re: [PATCHv2 10/10] dw_dmac: introduce dwc_chan_reset

On Tue, Jun 19, 2012 at 11:34 AM, Andy Shevchenko
<[email protected]> wrote:
> This piece of code is used often. Make it as a separate function.
>
> Signed-off-by: Andy Shevchenko <[email protected]>
> ---
> ?drivers/dma/dw_dmac.c | ? 32 ++++++++++++++------------------
> ?1 file changed, 14 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> index d3845ef..14fbee4 100644
> --- a/drivers/dma/dw_dmac.c
> +++ b/drivers/dma/dw_dmac.c
> @@ -219,6 +219,14 @@ static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
> ? ? ? ? ? ? ? ?channel_readl(dwc, CTL_LO));
> ?}
>
> +
> +static inline void dwc_chan_reset(struct dw_dma *dw, struct dw_dma_chan *dwc)
> +{
> + ? ? ? channel_clear_bit(dw, CH_EN, dwc->mask);
> + ? ? ? while (dma_readl(dw, CH_EN) & dwc->mask)
> + ? ? ? ? ? ? ? cpu_relax();
> +}

Hmm... This is not really a reset but disable.

Can you consider naming it more closer to what it is doing?

--
viresh

2012-06-19 10:40:53

by viresh kumar

[permalink] [raw]
Subject: Re: [PATCHv2 00/10] dw_dmac: set of cleanups and small fixes

On Tue, Jun 19, 2012 at 11:34 AM, Andy Shevchenko
<[email protected]> wrote:
> This patchset provides set of the cleanups and small fixes against the
> DesignWare DMA controller driver. It's a first portion of the patches to make
> the driver usable on other platforms.
>
> since v1:
> ?- add dwc_chan_reset
> ?- disable block interrupts only in probe (discussed with Viresh Kumar)
> ?- fix comment line in probe in patch 6
>
> Andy Shevchenko (10):
> ?dw_dmac: fix constant in the comment
> ?dw_dmac: use proper casting to print dma_addr_t values
> ?dw_dmac: introduce dwc_dump_chan_regs to dump registers
> ?dw_dmac: print correct number of scanned descriptors
> ?dw_dmac: use __func__ constant in the debug prints
> ?dw_dmac: disable dma in optimal way in probe
> ?dw_dmac: disable BLOCK interrupts
> ?dw_dmac: introduce dwc_fast_fls()
> ?dw_dmac: move from __init to __devinit
> ?dw_dmac: introduce dwc_chan_reset

Leaving minor comment on Patch 10/10, It Looks good.

Acked-by: Viresh Kumar <[email protected]>

2012-06-19 10:46:52

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCHv2.1] dw_dmac: introduce dwc_chan_disable

This piece of code is used often. Make it as a separate function.

Signed-off-by: Andy Shevchenko <[email protected]>
---
drivers/dma/dw_dmac.c | 32 ++++++++++++++------------------
1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index d3845ef..cefc2c3b 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -219,6 +219,14 @@ static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
channel_readl(dwc, CTL_LO));
}

+
+static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
+{
+ channel_clear_bit(dw, CH_EN, dwc->mask);
+ while (dma_readl(dw, CH_EN) & dwc->mask)
+ cpu_relax();
+}
+
/*----------------------------------------------------------------------*/

/* Called with dwc->lock held and bh disabled */
@@ -314,9 +322,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
"BUG: XFER bit set, but channel not idle!\n");

/* Try to continue after resetting the channel... */
- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_disable(dw, dwc);
}

/*
@@ -398,9 +404,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
"BUG: All descriptors done, but channel not idle!\n");

/* Try to continue after resetting the channel... */
- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_disable(dw, dwc);

if (!list_empty(&dwc->queue)) {
list_move(dwc->queue.next, &dwc->active_list);
@@ -516,9 +520,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,

dwc_dump_chan_regs(dwc);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_disable(dw, dwc);

/* make sure DMA does not restart by loading a new list */
channel_writel(dwc, LLP, 0);
@@ -948,9 +950,7 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
} else if (cmd == DMA_TERMINATE_ALL) {
spin_lock_irqsave(&dwc->lock, flags);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_disable(dw, dwc);

dwc->paused = false;

@@ -1158,9 +1158,7 @@ void dw_dma_cyclic_stop(struct dma_chan *chan)

spin_lock_irqsave(&dwc->lock, flags);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_disable(dw, dwc);

spin_unlock_irqrestore(&dwc->lock, flags);
}
@@ -1338,9 +1336,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)

spin_lock_irqsave(&dwc->lock, flags);

- channel_clear_bit(dw, CH_EN, dwc->mask);
- while (dma_readl(dw, CH_EN) & dwc->mask)
- cpu_relax();
+ dwc_chan_disable(dw, dwc);

dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
--
1.7.10

2012-06-19 10:52:24

by viresh kumar

[permalink] [raw]
Subject: Re: [PATCHv2.1] dw_dmac: introduce dwc_chan_disable

On Tue, Jun 19, 2012 at 11:46 AM, Andy Shevchenko
<[email protected]> wrote:
> This piece of code is used often. Make it as a separate function.
>
> Signed-off-by: Andy Shevchenko <[email protected]>
> ---
> ?drivers/dma/dw_dmac.c | ? 32 ++++++++++++++------------------
> ?1 file changed, 14 insertions(+), 18 deletions(-)

Perfect.

Acked-by: Viresh Kumar <[email protected]>

2012-06-21 02:47:20

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCHv2 00/10] dw_dmac: set of cleanups and small fixes

On Tue, 2012-06-19 at 13:34 +0300, Andy Shevchenko wrote:
> This patchset provides set of the cleanups and small fixes against the
> DesignWare DMA controller driver. It's a first portion of the patches to make
> the driver usable on other platforms.
Applied 1-9 in this. Thanks


--
~Vinod

2012-06-21 02:47:37

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCHv2.1] dw_dmac: introduce dwc_chan_disable

On Tue, 2012-06-19 at 13:46 +0300, Andy Shevchenko wrote:
> This piece of code is used often. Make it as a separate function.
>
Applied, Thanks

--
~Vinod