Skip to contentSkip to conversation

dmaengine: pl330: Set residue in tx_status callback

PATCH New Padmavathi Venna 6 participants 17 messages Nov 26, 2014 – Mar 12, 2015

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Fill txstate.residue with the amount of bytes remaining in the current transfer if the transfer is not complete. This will be of particular use to i2s DMA transfers, providing more accurate hw_ptr values to ASoC.

I had taken the code from Dylan Reid <[email protected]> patch from the below link and modified according to the current dmaengine framework.
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/23007

---

This patch has been tested for audio playback on exynos5420 peach-pit.

 drivers/dma/pl330.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 65 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +65 -2
index b7493d2..db880ae 100644
@@ -2182,11 +2182,74 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
 }
 
+static inline int
+pl330_src_addr_in_desc(struct dma_pl330_desc *desc, unsigned int sar)
+{
+	return ((desc->px.src_addr <= sar) &&
+		(sar <= (desc->px.src_addr + desc->px.bytes)));
+}
+
+static inline int
+pl330_dst_addr_in_desc(struct dma_pl330_desc *desc, unsigned int dar)
+{
+	return ((desc->px.dst_addr <= dar) &&
+		(dar <= (desc->px.dst_addr + desc->px.bytes)));
+}
+
 static enum dma_status
 pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 		 struct dma_tx_state *txstate)
 {
-	return dma_cookie_status(chan, cookie, txstate);
+	dma_addr_t sar, dar;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	void __iomem *regs = pch->dmac->base;
+	struct pl330_thread *thrd = pch->thread;
+	struct dma_pl330_desc *desc;
+	unsigned int residue = 0;
+	unsigned long flags;
+	bool first = true;
+	dma_cookie_t first_c, current_c;
+	dma_cookie_t used;
+	enum dma_status ret;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	used = txstate->used;
+
+	spin_lock_irqsave(&pch->lock, flags);
+	sar = readl(regs + SA(thrd->id));
+	dar = readl(regs + DA(thrd->id));
+
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY) {
+			current_c = desc->txd.cookie;
+			if (first) {
+				first_c = desc->txd.cookie;
+				first = false;
+			}
+
+			if (first_c < current_c)
+				residue += desc->px.bytes;
+			else {
+				if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+					residue += desc->px.bytes;
+					residue -= sar - desc->px.src_addr;
+				} else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar)) {
+					residue += desc->px.bytes;
+					residue -= dar - desc->px.dst_addr;
+				}
+			}
+		} else if (desc->status == PREP)
+			residue += desc->px.bytes;
+
+		if (desc->txd.cookie == used)
+			break;
+	}
+	spin_unlock_irqrestore(&pch->lock, flags);
+	dma_set_residue(txstate, residue);
+	return ret;
 }
 
 static void pl330_issue_pending(struct dma_chan *chan)
@@ -2631,7 +2694,7 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
 	caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
 	caps->cmd_pause = false;
 	caps->cmd_terminate = true;
-	caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+	caps->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
 	return 0;
 }
Signature · 1 line
1.7.4.4
#1 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Hi Vinod/Lars,

Quoted 108 lines · Padmavathi Venna

Fill txstate.residue with the amount of bytes remaining in the current transfer if the transfer is not complete. This will be of particular use to i2s DMA transfers, providing more accurate hw_ptr values to ASoC.

I had taken the code from Dylan Reid <[email protected]> patch from the below link and modified according to the current dmaengine framework.
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/23007

---

This patch has been tested for audio playback on exynos5420 peach-pit.

 drivers/dma/pl330.c |   67
+++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 65 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +64 -1
index b7493d2..db880ae 100644
@@ -2182,11 +2182,74 @@ static void pl330_free_chan_resources(struct
 dma_chan *chan)
 	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
 }
 
+static inline int
+pl330_src_addr_in_desc(struct dma_pl330_desc *desc, unsigned int sar)
+{
+	return ((desc->px.src_addr <= sar) &&
+		(sar <= (desc->px.src_addr + desc->px.bytes)));
+}
+
+static inline int
+pl330_dst_addr_in_desc(struct dma_pl330_desc *desc, unsigned int dar)
+{
+	return ((desc->px.dst_addr <= dar) &&
+		(dar <= (desc->px.dst_addr + desc->px.bytes)));
+}
+
 static enum dma_status
 pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 		 struct dma_tx_state *txstate)
 {
-	return dma_cookie_status(chan, cookie, txstate);
+	dma_addr_t sar, dar;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	void __iomem *regs = pch->dmac->base;
+	struct pl330_thread *thrd = pch->thread;
+	struct dma_pl330_desc *desc;
+	unsigned int residue = 0;
+	unsigned long flags;
+	bool first = true;
+	dma_cookie_t first_c, current_c;
+	dma_cookie_t used;
+	enum dma_status ret;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	used = txstate->used;
+
+	spin_lock_irqsave(&pch->lock, flags);
+	sar = readl(regs + SA(thrd->id));
+	dar = readl(regs + DA(thrd->id));
+
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY) {
+			current_c = desc->txd.cookie;
+			if (first) {
+				first_c = desc->txd.cookie;
+				first = false;
+			}
+
+			if (first_c < current_c)
+				residue += desc->px.bytes;
+			else {
+				if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+					residue += desc->px.bytes;
+					residue -= sar - desc->px.src_addr;
+				} else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar)) {
+					residue += desc->px.bytes;
+					residue -= dar - desc->px.dst_addr;
+				}
+			}
+		} else if (desc->status == PREP)
+			residue += desc->px.bytes;
+
+		if (desc->txd.cookie == used)
+			break;
+	}
+	spin_unlock_irqrestore(&pch->lock, flags);
+	dma_set_residue(txstate, residue);
+	return ret;
 }
 

static void pl330_issue_pending(struct dma_chan *chan)

drivers/dma/pl330.c +1 -1
@@ -2631,7 +2694,7 @@ static int pl330_dma_device_slave_caps(struct dma_chan
 *dchan,
 	caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
 	caps->cmd_pause = false;
 	caps->cmd_terminate = true;
-	caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+	caps->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
 	return 0;
Quoted 1 line

}

Any comment on this patch?

Thanks
Padma

Quoted 9 lines

--
1.7.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#2 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 110 lines · Padma Venkat

Hi Vinod/Lars,

Quoted 107 lines · Padmavathi Venna

Fill txstate.residue with the amount of bytes remaining in the current transfer if the transfer is not complete. This will be of particular use to i2s DMA transfers, providing more accurate hw_ptr values to ASoC.

I had taken the code from Dylan Reid <[email protected]> patch from the below link and modified according to the current dmaengine framework.
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/23007

---

This patch has been tested for audio playback on exynos5420 peach-pit.

  drivers/dma/pl330.c |   67
+++++++++++++++++++++++++++++++++++++++++++++++++-
  1 files changed, 65 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +64 -1
index b7493d2..db880ae 100644
@@ -2182,11 +2182,74 @@ static void pl330_free_chan_resources(struct
 dma_chan *chan)
  	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
  }
 
+static inline int
+pl330_src_addr_in_desc(struct dma_pl330_desc *desc, unsigned int sar)
+{
+	return ((desc->px.src_addr <= sar) &&
+		(sar <= (desc->px.src_addr + desc->px.bytes)));
+}
+
+static inline int
+pl330_dst_addr_in_desc(struct dma_pl330_desc *desc, unsigned int dar)
+{
+	return ((desc->px.dst_addr <= dar) &&
+		(dar <= (desc->px.dst_addr + desc->px.bytes)));
+}
+
  static enum dma_status
  pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
  		 struct dma_tx_state *txstate)
  {
-	return dma_cookie_status(chan, cookie, txstate);
+	dma_addr_t sar, dar;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	void __iomem *regs = pch->dmac->base;
+	struct pl330_thread *thrd = pch->thread;
+	struct dma_pl330_desc *desc;
+	unsigned int residue = 0;
+	unsigned long flags;
+	bool first = true;
+	dma_cookie_t first_c, current_c;
+	dma_cookie_t used;
+	enum dma_status ret;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	used = txstate->used;
+
+	spin_lock_irqsave(&pch->lock, flags);
+	sar = readl(regs + SA(thrd->id));
+	dar = readl(regs + DA(thrd->id));
+
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY) {
+			current_c = desc->txd.cookie;
+			if (first) {
+				first_c = desc->txd.cookie;
+				first = false;
+			}
+
+			if (first_c < current_c)
+				residue += desc->px.bytes;
+			else {
+				if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+					residue += desc->px.bytes;
+					residue -= sar - desc->px.src_addr;
+				} else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar)) {
+					residue += desc->px.bytes;
+					residue -= dar - desc->px.dst_addr;
+				}
+			}
+		} else if (desc->status == PREP)
+			residue += desc->px.bytes;
+
+		if (desc->txd.cookie == used)
+			break;
+	}
+	spin_unlock_irqrestore(&pch->lock, flags);
+	dma_set_residue(txstate, residue);
+	return ret;
  }
 

static void pl330_issue_pending(struct dma_chan *chan)

drivers/dma/pl330.c +1 -1
@@ -2631,7 +2694,7 @@ static int pl330_dma_device_slave_caps(struct dma_chan
 *dchan,
  	caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
  	caps->cmd_pause = false;
  	caps->cmd_terminate = true;
-	caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+	caps->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
Quoted 4 lines
Quoted 2 lines
drivers/dma/pl330.c +0 -0
  	return 0;
  }

Any comment on this patch?

Well it doesn't break audio, but I don't think it has the correct haviour for all cases yet.

Again, the semantics are that it should return the progress of the transfer for which the allocation function returned the cookie that is passe to this function. You have to consider that there might be multiple different descriptors submitted and in the work list, not just the one we want to know the status of. The big problem with the pl330 driver is that the current structure of the driver makes it not so easy to implement the residue reporting correctly.

- Lars

#3 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Hi Lars,

[snip]

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
drivers/dma/pl330.c +26 -0
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	used = txstate->used;
+
+	spin_lock_irqsave(&pch->lock, flags);
+	sar = readl(regs + SA(thrd->id));
+	dar = readl(regs + DA(thrd->id));
+
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY) {
+			current_c = desc->txd.cookie;
+			if (first) {
+				first_c = desc->txd.cookie;
+				first = false;
+			}
+
+			if (first_c < current_c)
+				residue += desc->px.bytes;
+			else {
+				if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+					residue += desc->px.bytes;
+					residue -= sar - desc->px.src_addr;
+				} else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar))

{

drivers/dma/pl330.c +13 -0
+					residue += desc->px.bytes;
+					residue -= dar - desc->px.dst_addr;
+				}
+			}
+		} else if (desc->status == PREP)
+			residue += desc->px.bytes;
+
+		if (desc->txd.cookie == used)
+			break;
+	}
+	spin_unlock_irqrestore(&pch->lock, flags);
+	dma_set_residue(txstate, residue);
+	return ret;
  }

[snip]

Quoted 5 lines
Quoted 2 lines

Any comment on this patch?

Well it doesn't break audio, but I don't think it has the correct haviour for all cases yet.

OK. Any way of testing other cases like scatter-gather and memcopy. I verified memcopy in dmatest but it seems not doing anything with residue bytes.

Quoted 4 lines

Again, the semantics are that it should return the progress of the transfer

for which the allocation function returned the cookie that is passe to this

May be my understanding is wrong. For clarification..In the snd_dmaengine_pcm_pointer it is subtracting the residue bytes from the total buffer bytes not from period bytes. So how it expects
the progress of the transfer of the passed cookie which just holds period bytes?

Quoted 3 lines

function. You have to consider that there might be multiple different descriptors submitted and in the work list, not just the one we want to know

Even though there are multiple descriptors in the work list, at a time only two descriptors are in busy state(as per the documentation in the driver) and all the descriptors cookie number is in incremental order. Not sure for other cases how it will be.

Quoted 6 lines

the status of. The big problem with the pl330 driver is that the current structure of the driver makes it not so easy to implement the residue reporting correctly.

- Lars

Thanks
Padma

Quoted 2 lines
#4 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 66 lines · Padma Venkat

Hi Lars,

[snip]

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
drivers/dma/pl330.c +26 -0
+
+   ret = dma_cookie_status(chan, cookie, txstate);
+   if (ret == DMA_COMPLETE || !txstate)
+           return ret;
+
+   used = txstate->used;
+
+   spin_lock_irqsave(&pch->lock, flags);
+   sar = readl(regs + SA(thrd->id));
+   dar = readl(regs + DA(thrd->id));
+
+   list_for_each_entry(desc, &pch->work_list, node) {
+           if (desc->status == BUSY) {
+                   current_c = desc->txd.cookie;
+                   if (first) {
+                           first_c = desc->txd.cookie;
+                           first = false;
+                   }
+
+                   if (first_c < current_c)
+                           residue += desc->px.bytes;
+                   else {
+                           if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+                                   residue += desc->px.bytes;
+                                   residue -= sar - desc->px.src_addr;
+                           } else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar))

{

drivers/dma/pl330.c +13 -0
+                                   residue += desc->px.bytes;
+                                   residue -= dar - desc->px.dst_addr;
+                           }
+                   }
+           } else if (desc->status == PREP)
+                   residue += desc->px.bytes;
+
+           if (desc->txd.cookie == used)
+                   break;
+   }
+   spin_unlock_irqrestore(&pch->lock, flags);
+   dma_set_residue(txstate, residue);
+   return ret;
  }

[snip]

Quoted 5 lines
Quoted 2 lines

Any comment on this patch?

Well it doesn't break audio, but I don't think it has the correct haviour for all cases yet.

OK. Any way of testing other cases like scatter-gather and memcopy. I verified memcopy in dmatest but it seems not doing anything with residue bytes.

Quoted 4 lines

Again, the semantics are that it should return the progress of the transfer

for which the allocation function returned the cookie that is passe to this

May be my understanding is wrong. For clarification..In the snd_dmaengine_pcm_pointer it is subtracting the residue bytes from the total buffer bytes not from period bytes. So how it expects
the progress of the transfer of the passed cookie which just holds period bytes?

Quoted 1 line
Quoted 8 lines
Quoted 2 lines

function. You have to consider that there might be multiple different descriptors submitted and in the work list, not just the one we want to know

Even though there are multiple descriptors in the work list, at a time only two descriptors are in busy state(as per the documentation in the driver) and all the descriptors cookie number is in incremental order. Not sure for other cases how it will be.

Yes.

Tracing the history ... I think we could have done without

04abf5daf7d dma: pl330: Differentiate between submitted and issued descriptors

The pl330 dmaengine driver currently does not differentiate
between submitted
and issued descriptors. It won't start transferring a newly submitted descriptor until issue_pending() is called, but only if it is idle. If it is active and a new descriptor is submitted before it goes idle it will happily start the newly submitted descriptor once all earlier submitted
descriptors have
been completed. This is not a 100% correct with regards to the dmaengine interface semantics. A descriptor is not supposed to be started
until the next
issue_pending() call after the descriptor has been submitted.

because the reasoning above seems incorrect considering the following documentation...

Documentation/crypto/async-tx-api.txt says
" .... Once a driver-specific threshold is met the driver
automatically issues pending operations. An application can force this event by calling async_tx_issue_pending_all(). ...."

And

include/linux/dmaengine.h says
dma_async_tx_descriptor.tx_submit(): set the prepared descriptor(s)
to be executed by the engine

so theoretically a driver, not starting transfer until issue_pending(), is "broken".
At best the patch at 04abf5daf7d makes the driver slightly more complicated and the reason behind confusion such as in this thread.

-jassi

#5 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 102 lines · Jassi Brar
Quoted 66 lines · Padma Venkat

Hi Lars,

[snip]

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
drivers/dma/pl330.c +26 -0
+
+   ret = dma_cookie_status(chan, cookie, txstate);
+   if (ret == DMA_COMPLETE || !txstate)
+           return ret;
+
+   used = txstate->used;
+
+   spin_lock_irqsave(&pch->lock, flags);
+   sar = readl(regs + SA(thrd->id));
+   dar = readl(regs + DA(thrd->id));
+
+   list_for_each_entry(desc, &pch->work_list, node) {
+           if (desc->status == BUSY) {
+                   current_c = desc->txd.cookie;
+                   if (first) {
+                           first_c = desc->txd.cookie;
+                           first = false;
+                   }
+
+                   if (first_c < current_c)
+                           residue += desc->px.bytes;
+                   else {
+                           if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+                                   residue += desc->px.bytes;
+                                   residue -= sar - desc->px.src_addr;
+                           } else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar))

{

drivers/dma/pl330.c +13 -0
+                                   residue += desc->px.bytes;
+                                   residue -= dar - desc->px.dst_addr;
+                           }
+                   }
+           } else if (desc->status == PREP)
+                   residue += desc->px.bytes;
+
+           if (desc->txd.cookie == used)
+                   break;
+   }
+   spin_unlock_irqrestore(&pch->lock, flags);
+   dma_set_residue(txstate, residue);
+   return ret;
  }

[snip]

Quoted 5 lines
Quoted 2 lines

Any comment on this patch?

Well it doesn't break audio, but I don't think it has the correct haviour for all cases yet.

OK. Any way of testing other cases like scatter-gather and memcopy. I verified memcopy in dmatest but it seems not doing anything with residue bytes.

Quoted 4 lines

Again, the semantics are that it should return the progress of the transfer

for which the allocation function returned the cookie that is passe to this

May be my understanding is wrong. For clarification..In the snd_dmaengine_pcm_pointer it is subtracting the residue bytes from the total buffer bytes not from period bytes. So how it expects
the progress of the transfer of the passed cookie which just holds period bytes?

Quoted 1 line
Quoted 8 lines
Quoted 2 lines

function. You have to consider that there might be multiple different descriptors submitted and in the work list, not just the one we want to know

Even though there are multiple descriptors in the work list, at a time only two descriptors are in busy state(as per the documentation in the driver) and all the descriptors cookie number is in incremental order. Not sure for other cases how it will be.

Yes.

Tracing the history ... I think we could have done without

04abf5daf7d dma: pl330: Differentiate between submitted and issued descriptors

The pl330 dmaengine driver currently does not differentiate
between submitted
and issued descriptors. It won't start transferring a newly submitted descriptor until issue_pending() is called, but only if it is idle. If it is active and a new descriptor is submitted before it goes idle it will happily start the newly submitted descriptor once all earlier submitted
descriptors have
been completed. This is not a 100% correct with regards to the dmaengine interface semantics. A descriptor is not supposed to be started
until the next
issue_pending() call after the descriptor has been submitted.

because the reasoning above seems incorrect considering the following documentation...

Documentation/crypto/async-tx-api.txt says
" .... Once a driver-specific threshold is met the driver
automatically issues pending operations. An application can force this event by calling async_tx_issue_pending_all(). ...."

Quoted 5 lines

And

include/linux/dmaengine.h says
dma_async_tx_descriptor.tx_submit(): set the prepared descriptor(s)
to be executed by the engine

"to be" here can lead to different conculsion. I will reword this :)

@tx_submit: accept the descriptor and assign ordered cookie and mark the descriptor pending. To be pushed on .issue_pending() call

Signature · 1 line
~Vinod
Quoted 7 lines

so theoretically a driver, not starting transfer until issue_pending(), is "broken".
At best the patch@04abf5daf7d makes the driver slightly more complicated and the reason behind confusion such as in this thread.

-jassi

#6 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

In reply to Jassi Brar
Quoted 4 lines · Jassi Brar

because the reasoning above seems incorrect considering the following documentation...

Documentation/crypto/async-tx-api.txt says

                       ^^^^^^^^^^^^

async-tx-api is not the DMA slave API.

Quoted 3 lines

" .... Once a driver-specific threshold is met the driver
automatically issues pending operations. An application can force this event by calling async_tx_issue_pending_all(). ...."

                   ^^^^^^^^^^^^^^^^^^^^^^^^^^

DMA slave users do not call this function. This documentation is not relevant for DMA slave.

Quoted 3 lines

include/linux/dmaengine.h says
dma_async_tx_descriptor.tx_submit(): set the prepared descriptor(s)
to be executed by the engine

It doesn't say when.

Quoted 2 lines

so theoretically a driver, not starting transfer until issue_pending(), is "broken".

It isn't. DMA slave engine implementations have been needing the issue_pending() call since their dawn, so it's something that they've always needed.

Quoted 2 lines

At best the patch at 04abf5daf7d makes the driver slightly more complicated and the reason behind confusion such as in this thread.

That may be, and yes, it _might_ be worth discussing whether this should be relaxed or not, but that should be done as a proposal, not trying to hide it as a bug fix. It isn't.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
#7 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 9 lines · Russell King - ARM Linux
Quoted 4 lines · Jassi Brar

because the reasoning above seems incorrect considering the following documentation...

Documentation/crypto/async-tx-api.txt says

                       ^^^^^^^^^^^^

async-tx-api is not the DMA slave API.

Quoted 8 lines
Quoted 3 lines

" .... Once a driver-specific threshold is met the driver
automatically issues pending operations. An application can force this event by calling async_tx_issue_pending_all(). ...."

                   ^^^^^^^^^^^^^^^^^^^^^^^^^^

DMA slave users do not call this function. This documentation is not relevant for DMA slave.

The APIs (device_issue_pending, tx_submit etc) are same for Slave and Async. async_tx_issue_pending_all() for Async and dma_async_issue_pending() for Slave both boil down to device_issue_pending()

Quoted 6 lines
Quoted 3 lines

include/linux/dmaengine.h says
dma_async_tx_descriptor.tx_submit(): set the prepared descriptor(s)
to be executed by the engine

It doesn't say when.

:) OK

Quoted 7 lines
Quoted 2 lines

so theoretically a driver, not starting transfer until issue_pending(), is "broken".

It isn't. DMA slave engine implementations have been needing the issue_pending() call since their dawn, so it's something that they've always needed.

Quoted 7 lines
Quoted 2 lines

At best the patch at 04abf5daf7d makes the driver slightly more complicated and the reason behind confusion such as in this thread.

That may be, and yes, it _might_ be worth discussing whether this should be relaxed or not, but that should be done as a proposal, not trying to hide it as a bug fix. It isn't.

It does, though, create an "awkward situation" when a channel is active while new requests are submitted - why would the channel want to stop after current transfer and await fresh issue_pending()? It's not that the request can be modified after submission.

And it isn't that tx_submit() is meant for 'sleepable' preparation for the transfer and we need another call to be issued from atomic context. From what I see most drivers don't need to sleep in tx_submit(). In fact, from a quick look most clients seem to suffer from the ritual i.e, there's nothing between tx_submit() and issue_pending() calls. And when there is indeed some code, it seems that can be moved just before tx_submit().

Last and apparently the least of all, we can never enforce the same behavior of the api on Async dma and have uniform behavior over the api.

So, if all tx_submit() does is put the request in controller driver's internal queue and the client can't touch the request after tx_submit(), why not merge the tx_submit() and issue_pending()?

Thanks.

#8 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 13 lines · Jassi Brar

It does, though, create an "awkward situation" when a channel is active while new requests are submitted - why would the channel want to stop after current transfer and await fresh issue_pending()? It's not that the request can be modified after submission.

And it isn't that tx_submit() is meant for 'sleepable' preparation for the transfer and we need another call to be issued from atomic context. From what I see most drivers don't need to sleep in tx_submit(). In fact, from a quick look most clients seem to suffer from the ritual i.e, there's nothing between tx_submit() and issue_pending() calls. And when there is indeed some code, it seems that can be moved just before tx_submit().

Quoted 7 lines

Last and apparently the least of all, we can never enforce the same behavior of the api on Async dma and have uniform behavior over the api.

So, if all tx_submit() does is put the request in controller driver's internal queue and the client can't touch the request after tx_submit(), why not merge the tx_submit() and issue_pending()?

You are thinking from an API point and not what can be done with this API. Today this API allows you to collate all pending txn and start while dmaengine driver can collate and submit as a batch to hardware and not waste time in getting irq and then setting next one. Sadly none of the drivers use this feature...

I actually like the split model, you can also prepare txn ahead of time and submit them when needed. If you don't like this, then please do as most implementation do today, call prepare and submit in series. Flexiblity in API is a better option IMO

Thanks

Signature · 1 line
~Vinod
#9 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 2 lines · Vinod Koul

I actually like the split model, you can also prepare txn ahead of time and submit them when needed.

Actually, you can't - that's not permitted. I have email(s) from Dan explicitly stating that it is permitted for a driver to take a spinlock in their prepare callback, and release it when the descriptor is submitted. Several DMA engine drivers (particularly those in for async_tx) do exactly that.

The reason that submit is separate from prepare is to allow DMA engine users to set a callback - if it weren't for that, there wouldn't be a submit step, prepare would have done everything.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
#10 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 10 lines · Russell King - ARM Linux
Quoted 2 lines · Vinod Koul

I actually like the split model, you can also prepare txn ahead of time and submit them when needed.

Actually, you can't - that's not permitted. I have email(s) from Dan explicitly stating that it is permitted for a driver to take a spinlock in their prepare callback, and release it when the descriptor is submitted. Several DMA engine drivers (particularly those in for async_tx) do exactly that.

Quoted 3 lines

The reason that submit is separate from prepare is to allow DMA engine users to set a callback - if it weren't for that, there wouldn't be a submit step, prepare would have done everything.

Yes thats right.

Do you mind pointing to thread Dan replied, I would like to add these bits and anything else missing to Documentation

Thanks

Signature · 1 line
~Vinod
#11 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

In reply to Vinod Koul
Quoted 14 lines · Vinod Koul
Quoted 13 lines · Jassi Brar

It does, though, create an "awkward situation" when a channel is active while new requests are submitted - why would the channel want to stop after current transfer and await fresh issue_pending()? It's not that the request can be modified after submission.

And it isn't that tx_submit() is meant for 'sleepable' preparation for the transfer and we need another call to be issued from atomic context. From what I see most drivers don't need to sleep in tx_submit(). In fact, from a quick look most clients seem to suffer from the ritual i.e, there's nothing between tx_submit() and issue_pending() calls. And when there is indeed some code, it seems that can be moved just before tx_submit().

Quoted 9 lines
Quoted 7 lines

Last and apparently the least of all, we can never enforce the same behavior of the api on Async dma and have uniform behavior over the api.

So, if all tx_submit() does is put the request in controller driver's internal queue and the client can't touch the request after tx_submit(), why not merge the tx_submit() and issue_pending()?

You are thinking from an API point and not what can be done with this API.

"awkward situation" and "ritual suffering" above, are two practical issues that we see.

Quoted 5 lines

Today this API allows you to collate all pending txn and start while dmaengine driver can collate and submit as a batch to hardware and not waste time in getting irq and then setting next one. Sadly none of the drivers use this feature...

So we at least agree that the "feature" is unused so far. And I doubt if it would ever make sense to batch transfers in slave dma (unlike offloading on async-dma) because the user has to also setup the master for each queued request, mostly if not always.

Quoted 5 lines

I actually like the split model, you can also prepare txn ahead of time and submit them when needed. If you don't like this, then please do as most implementation do today, call prepare and submit in series. Flexiblity in API is a better option IMO

As Russell pointed out, that ain't the case either. So we are yet to figure out benefits of having explicit issue_pending() after tx_submit().

-Jassi

#12 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 3 lines · Jassi Brar

As Russell pointed out, that ain't the case either. So we are yet to figure out benefits of having explicit issue_pending() after tx_submit().

callback ?

Signature · 1 line
~Vinod
#13 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Quoted 6 lines · Vinod Koul
Quoted 3 lines · Jassi Brar

As Russell pointed out, that ain't the case either. So we are yet to figure out benefits of having explicit issue_pending() after tx_submit().

callback ?

The callback is set after prep() and before tx_submit(), but here we talk after tx_submit().

#14 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

Hi Vinod, Hi Russell,

Quoted 9 lines · Jassi Brar
Quoted 6 lines · Vinod Koul
Quoted 3 lines · Jassi Brar

As Russell pointed out, that ain't the case either. So we are yet to figure out benefits of having explicit issue_pending() after tx_submit().

callback ?

The callback is set after prep() and before tx_submit(), but here we talk after tx_submit().

Perhaps the idea dates back to async-only days, when client drivers would prepare and queue descriptors in the controller driver rather than having to manage the dependency queues themselves (?).

Today ~95% clients are slave and I am yet to find one that really
can't work with submit and issue_pending tied together. Not to forget the 100% of the controller drivers have to manage 'submitted' and 'active' queues -- only to have arguably negative side-effects.

If we agree that clubbing submit and issue_pending is the right thing to do, I can start converting the ~90 client drivers. Please let me know either way.

Cheers!

#15 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

In reply to Padma Venkat
Quoted 46 lines · Padma Venkat

Hi Lars,

[snip]

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
drivers/dma/pl330.c +26 -0
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	used = txstate->used;
+
+	spin_lock_irqsave(&pch->lock, flags);
+	sar = readl(regs + SA(thrd->id));
+	dar = readl(regs + DA(thrd->id));
+
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY) {
+			current_c = desc->txd.cookie;
+			if (first) {
+				first_c = desc->txd.cookie;
+				first = false;
+			}
+
+			if (first_c < current_c)
+				residue += desc->px.bytes;
+			else {
+				if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+					residue += desc->px.bytes;
+					residue -= sar - desc->px.src_addr;
+				} else if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar))

{

drivers/dma/pl330.c +13 -0
+					residue += desc->px.bytes;
+					residue -= dar - desc->px.dst_addr;
+				}
+			}
+		} else if (desc->status == PREP)
+			residue += desc->px.bytes;
+
+		if (desc->txd.cookie == used)
+			break;
+	}
+	spin_unlock_irqrestore(&pch->lock, flags);
+	dma_set_residue(txstate, residue);
+	return ret;
   }

[snip]

Quoted 1 line
Quoted 1 line
Quoted 8 lines
Quoted 4 lines
Quoted 1 line

Any comment on this patch?

Well it doesn't break audio, but I don't think it has the correct haviour for all cases yet.

OK. Any way of testing other cases like scatter-gather and memcopy. I verified memcopy in dmatest but it seems not doing anything with residue bytes.

E.g. I think your current patch fails if more than one transfer has been submitted. In that case you'll count the bytes for all of them rather than just the one requested.

Quoted 10 lines
Quoted 5 lines

Again, the semantics are that it should return the progress of the transfer

for which the allocation function returned the cookie that is passe to this

May be my understanding is wrong. For clarification..In the snd_dmaengine_pcm_pointer it is subtracting the residue bytes from the total buffer bytes not from period bytes. So how it expects
the progress of the transfer of the passed cookie which just holds period bytes?

The issue that makes implementing this correctly for the pl330 driver complicated is that the driver allocates one cookie per segment/period, but the external API works with one cookie per transfer. All those cookies that are assigned to the segments/periods that are not the first in a transfer are not externally visible.

dmaengine_prep_slave_sg() and friends create a transfer and return descriptor for this transfer with a single cookie. If that cookie is passed to dmaengine_tx_status() the function is supposed to report the progress on that one transfer that was previously allocated and returned that cookie number. residue is the total number of bytes that are still left to to be processed for that transfer.

I've started reworking the pl330 driver to only have a single cookie per transfer, instead of one per period/segment. This makes implementing the residue reporting a lot easier. I never finished that work though, but I can try to see if I can revive it next week.

- Lars

#16 lore raw

PATCH 1/1 dmaengine: pl330: Set residue in tx_status callback

In reply to Lars-Peter Clausen
Quoted 5 lines · Lars-Peter Clausen

On 12/02/2014 06:38 AM, Padma Venkat wrote:

Well it doesn't break audio, but I don't think it has the correct haviour for all cases yet.

Quoted 7 lines

Again, the semantics are that it should return the progress of the transfer for which the allocation function returned the cookie that is passe to this function. You have to consider that there might be multiple different descriptors submitted and in the work list, not just the one we want to know the status of. The big problem with the pl330 driver is that the current structure of the driver makes it not so easy to implement the residue reporting correctly.

well you can use the completed_cookie as hint. This was last trasaction which was issues, so calculate remianing bytes for this and subsequent ones resiude would only be size of transaction

Signature · 1 line
~Vinod