public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] dma: pl330: Change pl330_tx_status()
@ 2013-12-09 11:19 Lukasz Czerwinski
  2013-12-09 12:00 ` Lars-Peter Clausen
  0 siblings, 1 reply; 3+ messages in thread
From: Lukasz Czerwinski @ 2013-12-09 11:19 UTC (permalink / raw)
  To: djbw, linux-kernel; +Cc: s.nawrocki, m.szyprowski

This patch adds possibility to read status of unfinished transfers
before termination.

Signed-off-by: Lukasz Czerwinski <l.czerwinski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---

I tested patch with Exynos4 board. This is only proof of concept.
Any comments are welcome.

Thanks
Lukasz

 drivers/dma/pl330.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 24f8ae3..c88c36e 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -566,6 +566,7 @@ struct dma_pl330_chan {
 	/* For D-to-M and M-to-D channels */
 	int burst_sz; /* the peripheral fifo width */
 	int burst_len; /* the number of burst */
+	int transfered;
 	dma_addr_t fifo_addr;
 
 	/* for cyclic capability */
@@ -602,6 +603,9 @@ struct dma_pl330_desc {
 
 	enum desc_status status;
 
+	int bytes_requested;
+	int direction;
+
 	/* The channel which currently holds this desc */
 	struct dma_pl330_chan *pchan;
 };
@@ -2366,6 +2370,29 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 	return 1;
 }
 
+int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
+		struct dma_pl330_desc *desc)
+{
+	u32 val, addr;
+	struct pl330_thread *thrd = pch->pl330_chid;
+	void __iomem *regs = thrd->dmac->pinfo->base;
+
+	val = addr = 0;
+	switch (desc->direction) {
+	case DMA_MEM_TO_DEV:
+		val = readl(regs + SA(thrd->id));
+		addr = desc->px.src_addr;
+		break;
+	case DMA_DEV_TO_MEM:
+		val = readl(regs + DA(thrd->id));
+		addr = desc->px.dst_addr;
+		break;
+	default:
+		break;
+	}
+	return val - addr;
+}
+
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
@@ -2446,7 +2473,33 @@ 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);
+	enum dma_status ret;
+	unsigned long flags;
+	struct dma_pl330_desc *desc;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	unsigned int bytes_transferred;
+	unsigned int residual;
+
+	/* Check in pending list */
+	spin_lock_irqsave(&pch->lock, flags);
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->txd.cookie == cookie) {
+			bytes_transferred =
+				pl330_get_current_xferred_count(pch, desc);
+			residual =  desc->bytes_requested -
+				bytes_transferred % desc->bytes_requested;
+			dma_set_residue(txstate, residual);
+			ret = desc->status;
+			spin_unlock_irqrestore(&pch->lock, flags);
+			return ret;
+		}
+	}
+	spin_unlock_irqrestore(&pch->lock, flags);
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	dma_set_residue(txstate,  pch->transfered);
+
+	return ret;
 }
 
 static void pl330_issue_pending(struct dma_chan *chan)
@@ -2717,9 +2770,12 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
 			break;
 		}
 
+		desc->direction = direction;
 		desc->rqcfg.brst_size = pch->burst_sz;
 		desc->rqcfg.brst_len = 1;
+		desc->bytes_requested = period_len;
 		fill_px(&desc->px, dst, src, period_len);
+		pch->transfered = 0;
 
 		if (!first)
 			first = desc;
@@ -2853,8 +2909,11 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 				sg_dma_address(sg), addr, sg_dma_len(sg));
 		}
 
+		desc->direction = direction;
 		desc->rqcfg.brst_size = pch->burst_sz;
 		desc->rqcfg.brst_len = 1;
+		desc->bytes_requested = sg_dma_len(sg);
+		pch->transfered = 0;
 	}
 
 	/* Return the last desc in the chain */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH] dma: pl330: Change pl330_tx_status()
  2013-12-09 11:19 [RFC PATCH] dma: pl330: Change pl330_tx_status() Lukasz Czerwinski
@ 2013-12-09 12:00 ` Lars-Peter Clausen
  2013-12-13 15:33   ` Lukasz Czerwinski
  0 siblings, 1 reply; 3+ messages in thread
From: Lars-Peter Clausen @ 2013-12-09 12:00 UTC (permalink / raw)
  To: Lukasz Czerwinski; +Cc: djbw, linux-kernel, s.nawrocki, m.szyprowski

On 12/09/2013 12:19 PM, Lukasz Czerwinski wrote:
> This patch adds possibility to read status of unfinished transfers
> before termination.
> 
> Signed-off-by: Lukasz Czerwinski <l.czerwinski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> 
> I tested patch with Exynos4 board. This is only proof of concept.
> Any comments are welcome.

The patch does not look as if it is going to work correctly. And I think
that this can't be implemented correctly with the current structure of the
driver (at least not without jumping through a couple of hoops). I do have a
couple of WIP patches that restructure the driver and then implement residue
reporting on top of it.

> 
> Thanks
> Lukasz
> 
>  drivers/dma/pl330.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 60 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 24f8ae3..c88c36e 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -566,6 +566,7 @@ struct dma_pl330_chan {
>  	/* For D-to-M and M-to-D channels */
>  	int burst_sz; /* the peripheral fifo width */
>  	int burst_len; /* the number of burst */
> +	int transfered;

This is always set to 0.

>  	dma_addr_t fifo_addr;
>  
>  	/* for cyclic capability */
> @@ -602,6 +603,9 @@ struct dma_pl330_desc {
>  
>  	enum desc_status status;
>  
> +	int bytes_requested;
> +	int direction;
> +
>  	/* The channel which currently holds this desc */
>  	struct dma_pl330_chan *pchan;
>  };
> @@ -2366,6 +2370,29 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>  	return 1;
>  }
>  
> +int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
> +		struct dma_pl330_desc *desc)
> +{
> +	u32 val, addr;
> +	struct pl330_thread *thrd = pch->pl330_chid;
> +	void __iomem *regs = thrd->dmac->pinfo->base;
> +
> +	val = addr = 0;
> +	switch (desc->direction) {
> +	case DMA_MEM_TO_DEV:
> +		val = readl(regs + SA(thrd->id));
> +		addr = desc->px.src_addr;
> +		break;
> +	case DMA_DEV_TO_MEM:
> +		val = readl(regs + DA(thrd->id));
> +		addr = desc->px.dst_addr;
> +		break;
> +	default:
> +		break;
> +	}
> +	return val - addr;
> +}
> +
>  static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
>  {
>  	struct dma_pl330_chan *pch = to_pchan(chan);
> @@ -2446,7 +2473,33 @@ 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);
> +	enum dma_status ret;
> +	unsigned long flags;
> +	struct dma_pl330_desc *desc;
> +	struct dma_pl330_chan *pch = to_pchan(chan);
> +	unsigned int bytes_transferred;
> +	unsigned int residual;
> +
> +	/* Check in pending list */
> +	spin_lock_irqsave(&pch->lock, flags);
> +	list_for_each_entry(desc, &pch->work_list, node) {
> +		if (desc->txd.cookie == cookie) {
> +			bytes_transferred =
> +				pl330_get_current_xferred_count(pch, desc);

pl330_get_current_xferred_count() will only return the correct result if it
is called for the currently active transfer.

And then there is also the issue that the driver creates multiple internal
descriptors for each segment in the transfer. Each of these descriptors gets
different cookie. pl330_tx_submit() returns the cookie to the descriptor to
the first segment in the transfer. This means if you pass that cookie to
pl330_tx_status() you'll only get the residue for the first segment and not
for the whole transfer, as it is supposed to be.

> +			residual =  desc->bytes_requested -
> +				bytes_transferred % desc->bytes_requested;

If bytes_transferred % desc->bytes_requested != bytes_transferred there is a
bug somewhere.

> +			dma_set_residue(txstate, residual);
> +			ret = desc->status;
> +			spin_unlock_irqrestore(&pch->lock, flags);
> +			return ret;
> +		}
> +	}
> +	spin_unlock_irqrestore(&pch->lock, flags);
> +
> +	ret = dma_cookie_status(chan, cookie, txstate);
> +	dma_set_residue(txstate,  pch->transfered);
> +
> +	return ret;
>  }
>  
[...]


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH] dma: pl330: Change pl330_tx_status()
  2013-12-09 12:00 ` Lars-Peter Clausen
@ 2013-12-13 15:33   ` Lukasz Czerwinski
  0 siblings, 0 replies; 3+ messages in thread
From: Lukasz Czerwinski @ 2013-12-13 15:33 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: djbw@fb.com, linux-kernel@vger.kernel.org, Sylwester Nawrocki,
	Marek Szyprowski

On 12/09/2013 01:00 PM, Lars-Peter Clausen wrote:
> On 12/09/2013 12:19 PM, Lukasz Czerwinski wrote:
>> This patch adds possibility to read status of unfinished transfers
>> before termination.
>>
>> Signed-off-by: Lukasz Czerwinski <l.czerwinski@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>
>> I tested patch with Exynos4 board. This is only proof of concept.
>> Any comments are welcome.
>
> The patch does not look as if it is going to work correctly. And I think
> that this can't be implemented correctly with the current structure of the
> driver (at least not without jumping through a couple of hoops). I do have a
> couple of WIP patches that restructure the driver and then implement residue
> reporting on top of it.
>
>>

Thanks for your comments.

I will be waiting for your patch series then I will implement residue 
reporting in proper way.

br
Lukasz

>> Thanks
>> Lukasz
>>
>>   drivers/dma/pl330.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 60 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
>> index 24f8ae3..c88c36e 100644
>> --- a/drivers/dma/pl330.c
>> +++ b/drivers/dma/pl330.c
>> @@ -566,6 +566,7 @@ struct dma_pl330_chan {
>>   	/* For D-to-M and M-to-D channels */
>>   	int burst_sz; /* the peripheral fifo width */
>>   	int burst_len; /* the number of burst */
>> +	int transfered;
>
> This is always set to 0.
>
>>   	dma_addr_t fifo_addr;
>>
>>   	/* for cyclic capability */
>> @@ -602,6 +603,9 @@ struct dma_pl330_desc {
>>
>>   	enum desc_status status;
>>
>> +	int bytes_requested;
>> +	int direction;
>> +
>>   	/* The channel which currently holds this desc */
>>   	struct dma_pl330_chan *pchan;
>>   };
>> @@ -2366,6 +2370,29 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>>   	return 1;
>>   }
>>
>> +int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>> +		struct dma_pl330_desc *desc)
>> +{
>> +	u32 val, addr;
>> +	struct pl330_thread *thrd = pch->pl330_chid;
>> +	void __iomem *regs = thrd->dmac->pinfo->base;
>> +
>> +	val = addr = 0;
>> +	switch (desc->direction) {
>> +	case DMA_MEM_TO_DEV:
>> +		val = readl(regs + SA(thrd->id));
>> +		addr = desc->px.src_addr;
>> +		break;
>> +	case DMA_DEV_TO_MEM:
>> +		val = readl(regs + DA(thrd->id));
>> +		addr = desc->px.dst_addr;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	return val - addr;
>> +}
>> +
>>   static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
>>   {
>>   	struct dma_pl330_chan *pch = to_pchan(chan);
>> @@ -2446,7 +2473,33 @@ 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);
>> +	enum dma_status ret;
>> +	unsigned long flags;
>> +	struct dma_pl330_desc *desc;
>> +	struct dma_pl330_chan *pch = to_pchan(chan);
>> +	unsigned int bytes_transferred;
>> +	unsigned int residual;
>> +
>> +	/* Check in pending list */
>> +	spin_lock_irqsave(&pch->lock, flags);
>> +	list_for_each_entry(desc, &pch->work_list, node) {
>> +		if (desc->txd.cookie == cookie) {
>> +			bytes_transferred =
>> +				pl330_get_current_xferred_count(pch, desc);
>
> pl330_get_current_xferred_count() will only return the correct result if it
> is called for the currently active transfer.
>
> And then there is also the issue that the driver creates multiple internal
> descriptors for each segment in the transfer. Each of these descriptors gets
> different cookie. pl330_tx_submit() returns the cookie to the descriptor to
> the first segment in the transfer. This means if you pass that cookie to
> pl330_tx_status() you'll only get the residue for the first segment and not
> for the whole transfer, as it is supposed to be.
>
>> +			residual =  desc->bytes_requested -
>> +				bytes_transferred % desc->bytes_requested;
>
> If bytes_transferred % desc->bytes_requested != bytes_transferred there is a
> bug somewhere.
>
>> +			dma_set_residue(txstate, residual);
>> +			ret = desc->status;
>> +			spin_unlock_irqrestore(&pch->lock, flags);
>> +			return ret;
>> +		}
>> +	}
>> +	spin_unlock_irqrestore(&pch->lock, flags);
>> +
>> +	ret = dma_cookie_status(chan, cookie, txstate);
>> +	dma_set_residue(txstate,  pch->transfered);
>> +
>> +	return ret;
>>   }
>>
> [...]
> .
>

  * English - detected
  * Polish

  * Polish

  <javascript:void(0);>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-12-13 15:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-09 11:19 [RFC PATCH] dma: pl330: Change pl330_tx_status() Lukasz Czerwinski
2013-12-09 12:00 ` Lars-Peter Clausen
2013-12-13 15:33   ` Lukasz Czerwinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox