All of lore.kernel.org
 help / color / mirror / Atom feed
From: Russell King - ARM Linux <linux@arm.linux.org.uk>
To: Kukjin Kim <kgene.kim@samsung.com>
Cc: linux-arm-kernel@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org,
	Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Boojin Kim <boojin.kim@samsung.com>,
	Vinod Koul <vinod.koul@intel.com>,
	Linus Walleij <linus.walleij@linaro.org>,
	Jassi Brar <jassisinghbrar@gmail.com>,
	Grant Likely <grant.likely@secretlab.ca>,
	Dan Williams <dan.j.williams@intel.com>,
	Liam Girdwood <lrg@ti.com>
Subject: Re: [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
Date: Wed, 13 Jul 2011 10:14:03 +0100	[thread overview]
Message-ID: <20110713091403.GI23270@n2100.arm.linux.org.uk> (raw)
In-Reply-To: <1310546857-6304-4-git-send-email-kgene.kim@samsung.com>

On Wed, Jul 13, 2011 at 05:47:28PM +0900, Kukjin Kim wrote:
> +static void pl330_tasklet_cyclic(unsigned long data)
> +{
> +	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> +	struct dma_pl330_desc *desc, *_dt;
> +	unsigned long flags;
> +	LIST_HEAD(list);
> +
> +	spin_lock_irqsave(&pch->lock, flags);
> +
> +	/* Pick up ripe tomatoes */
> +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> +		if ((desc->status == DONE) && desc->cyclic) {
> +			dma_async_tx_callback callback;
> +
> +			list_move_tail(&desc->node, &pch->work_list);
> +			pch->completed = desc->txd.cookie;
> +
> +			desc->status = PREP;
> +
> +			/* Try to submit a req imm.
> +			next to the last completed cookie */
> +			fill_queue(pch);
> +
> +			/* Make sure the PL330 Channel thread is active */
> +			pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
> +
> +			callback = desc->txd.callback;
> +			if (callback)
> +				callback(desc->txd.callback_param);

How does this work when callbacks are allowed to queue new requests?
Aren't you going to deadlock on the spinlock?

I don't see 'list' being used in this function either.

> +
> +		}
> +
> +	spin_unlock_irqrestore(&pch->lock, flags);
> +}
> +
> +static void pl330_cyclic_free(struct dma_pl330_chan *pch)
> +{
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	struct dma_pl330_desc *desc, *_dt;
> +	unsigned long flags;
> +	LIST_HEAD(list);
> +
> +	spin_lock_irqsave(&pdmac->pool_lock, flags);
> +
> +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> +	if (desc->cyclic)
> +		list_move_tail(&desc->node, &list);
> +
> +	list_splice_tail_init(&list, &pdmac->desc_pool);

As you're not using 'list' after this point, would 'list_splice_tail'
do here?

> +
> +	spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> +	pch->cyclic_task = NULL;
> +}
> +
>  static void pl330_tasklet(unsigned long data)
>  {
>  	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> @@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
>  
>  	spin_unlock_irqrestore(&pch->lock, flags);
>  
> +	if (pch->cyclic_task)
> +		tasklet_schedule(pch->cyclic_task);
> +	else
>  	tasklet_schedule(&pch->task);

This 'tasklet_schedule' wants to be indented.

>  }
>  
> @@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>  static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
>  {
>  	struct dma_pl330_chan *pch = to_pchan(chan);
> -	struct dma_pl330_desc *desc;
> +	struct dma_pl330_desc *desc, *_dt;
>  	unsigned long flags;
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	struct dma_slave_config *slave_config;
> +	struct dma_pl330_peri *peri;
> +	int i;
> +	LIST_HEAD(list);
>  
> -	/* Only supports DMA_TERMINATE_ALL */
> -	if (cmd != DMA_TERMINATE_ALL)
> -		return -ENXIO;
> -
> -	spin_lock_irqsave(&pch->lock, flags);
> -
> -	/* FLUSH the PL330 Channel thread */
> -	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> +	switch (cmd) {
> +	case DMA_TERMINATE_ALL:
> +		spin_lock_irqsave(&pch->lock, flags);
>  
> -	/* Mark all desc done */
> -	list_for_each_entry(desc, &pch->work_list, node)
> -		desc->status = DONE;
> +		/* FLUSH the PL330 Channel thread */
> +		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
>  
> -	spin_unlock_irqrestore(&pch->lock, flags);
> +		/* Mark all desc done */
> +		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
> +			desc->status = DONE;
> +			pch->completed = desc->txd.cookie;
> +			list_move_tail(&desc->node, &list);
> +		}
>  
> -	pl330_tasklet((unsigned long) pch);
> +		list_splice_tail_init(&list, &pdmac->desc_pool);

Again, would list_splice_tail() do here?

> +		spin_unlock_irqrestore(&pch->lock, flags);
> +		break;
> +	case DMA_SLAVE_CONFIG:
> +		slave_config = (struct dma_slave_config *)arg;
> +		peri = pch->chan.private;
> +
> +		if (slave_config->direction == DMA_TO_DEVICE) {
> +			if (slave_config->dst_addr)
> +				peri->fifo_addr = slave_config->dst_addr;
> +			if (slave_config->dst_addr_width) {
> +				i = 0;
> +				while (slave_config->dst_addr_width != (1 << i))
> +					i++;
> +				peri->burst_sz = i;
> +			}
> +		} else if (slave_config->direction == DMA_FROM_DEVICE) {
> +			if (slave_config->src_addr)
> +				peri->fifo_addr = slave_config->src_addr;
> +			if (slave_config->src_addr_width) {
> +				i = 0;
> +				while (slave_config->src_addr_width != (1 << i))
> +					i++;
> +				peri->burst_sz = i;
> +			}
> +		}

It would make more sense to store the M2P and P2M address/width/burst size
separately, so you don't have to make DMA_SLAVE_CONFIG calls before every
transfer.

WARNING: multiple messages have this Message-ID (diff)
From: linux@arm.linux.org.uk (Russell King - ARM Linux)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
Date: Wed, 13 Jul 2011 10:14:03 +0100	[thread overview]
Message-ID: <20110713091403.GI23270@n2100.arm.linux.org.uk> (raw)
In-Reply-To: <1310546857-6304-4-git-send-email-kgene.kim@samsung.com>

On Wed, Jul 13, 2011 at 05:47:28PM +0900, Kukjin Kim wrote:
> +static void pl330_tasklet_cyclic(unsigned long data)
> +{
> +	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> +	struct dma_pl330_desc *desc, *_dt;
> +	unsigned long flags;
> +	LIST_HEAD(list);
> +
> +	spin_lock_irqsave(&pch->lock, flags);
> +
> +	/* Pick up ripe tomatoes */
> +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> +		if ((desc->status == DONE) && desc->cyclic) {
> +			dma_async_tx_callback callback;
> +
> +			list_move_tail(&desc->node, &pch->work_list);
> +			pch->completed = desc->txd.cookie;
> +
> +			desc->status = PREP;
> +
> +			/* Try to submit a req imm.
> +			next to the last completed cookie */
> +			fill_queue(pch);
> +
> +			/* Make sure the PL330 Channel thread is active */
> +			pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
> +
> +			callback = desc->txd.callback;
> +			if (callback)
> +				callback(desc->txd.callback_param);

How does this work when callbacks are allowed to queue new requests?
Aren't you going to deadlock on the spinlock?

I don't see 'list' being used in this function either.

> +
> +		}
> +
> +	spin_unlock_irqrestore(&pch->lock, flags);
> +}
> +
> +static void pl330_cyclic_free(struct dma_pl330_chan *pch)
> +{
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	struct dma_pl330_desc *desc, *_dt;
> +	unsigned long flags;
> +	LIST_HEAD(list);
> +
> +	spin_lock_irqsave(&pdmac->pool_lock, flags);
> +
> +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> +	if (desc->cyclic)
> +		list_move_tail(&desc->node, &list);
> +
> +	list_splice_tail_init(&list, &pdmac->desc_pool);

As you're not using 'list' after this point, would 'list_splice_tail'
do here?

> +
> +	spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> +	pch->cyclic_task = NULL;
> +}
> +
>  static void pl330_tasklet(unsigned long data)
>  {
>  	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> @@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
>  
>  	spin_unlock_irqrestore(&pch->lock, flags);
>  
> +	if (pch->cyclic_task)
> +		tasklet_schedule(pch->cyclic_task);
> +	else
>  	tasklet_schedule(&pch->task);

This 'tasklet_schedule' wants to be indented.

>  }
>  
> @@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>  static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
>  {
>  	struct dma_pl330_chan *pch = to_pchan(chan);
> -	struct dma_pl330_desc *desc;
> +	struct dma_pl330_desc *desc, *_dt;
>  	unsigned long flags;
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	struct dma_slave_config *slave_config;
> +	struct dma_pl330_peri *peri;
> +	int i;
> +	LIST_HEAD(list);
>  
> -	/* Only supports DMA_TERMINATE_ALL */
> -	if (cmd != DMA_TERMINATE_ALL)
> -		return -ENXIO;
> -
> -	spin_lock_irqsave(&pch->lock, flags);
> -
> -	/* FLUSH the PL330 Channel thread */
> -	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> +	switch (cmd) {
> +	case DMA_TERMINATE_ALL:
> +		spin_lock_irqsave(&pch->lock, flags);
>  
> -	/* Mark all desc done */
> -	list_for_each_entry(desc, &pch->work_list, node)
> -		desc->status = DONE;
> +		/* FLUSH the PL330 Channel thread */
> +		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
>  
> -	spin_unlock_irqrestore(&pch->lock, flags);
> +		/* Mark all desc done */
> +		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
> +			desc->status = DONE;
> +			pch->completed = desc->txd.cookie;
> +			list_move_tail(&desc->node, &list);
> +		}
>  
> -	pl330_tasklet((unsigned long) pch);
> +		list_splice_tail_init(&list, &pdmac->desc_pool);

Again, would list_splice_tail() do here?

> +		spin_unlock_irqrestore(&pch->lock, flags);
> +		break;
> +	case DMA_SLAVE_CONFIG:
> +		slave_config = (struct dma_slave_config *)arg;
> +		peri = pch->chan.private;
> +
> +		if (slave_config->direction == DMA_TO_DEVICE) {
> +			if (slave_config->dst_addr)
> +				peri->fifo_addr = slave_config->dst_addr;
> +			if (slave_config->dst_addr_width) {
> +				i = 0;
> +				while (slave_config->dst_addr_width != (1 << i))
> +					i++;
> +				peri->burst_sz = i;
> +			}
> +		} else if (slave_config->direction == DMA_FROM_DEVICE) {
> +			if (slave_config->src_addr)
> +				peri->fifo_addr = slave_config->src_addr;
> +			if (slave_config->src_addr_width) {
> +				i = 0;
> +				while (slave_config->src_addr_width != (1 << i))
> +					i++;
> +				peri->burst_sz = i;
> +			}
> +		}

It would make more sense to store the M2P and P2M address/width/burst size
separately, so you don't have to make DMA_SLAVE_CONFIG calls before every
transfer.

  reply	other threads:[~2011-07-13  9:14 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
2011-07-13  8:47 ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  9:07   ` Russell King - ARM Linux
2011-07-13  9:07     ` Russell King - ARM Linux
2011-07-13  8:47 ` [PATCH V2 02/12] DMA: PL330: Update PL330 DMA API driver Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 03/12] DMA: PL330: Add DMA capabilities Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  9:14   ` Russell King - ARM Linux [this message]
2011-07-13  9:14     ` Russell King - ARM Linux
2011-07-13 11:04     ` boojin
2011-07-13 11:04       ` boojin
2011-07-15  4:45   ` Chanho Park
2011-07-15  4:45     ` Chanho Park
2011-07-16  1:11     ` Boojin Kim
2011-07-16  1:11       ` Boojin Kim
2011-07-13  8:47 ` [PATCH V2 04/12] ARM: SAMSUNG: Update to use PL330-DMA driver Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-15  2:53   ` Grant Likely
2011-07-15  2:53     ` Grant Likely
2011-07-16  0:39     ` Boojin Kim
2011-07-16  0:39       ` Boojin Kim
2011-07-16  0:50       ` Grant Likely
2011-07-16  0:50         ` Grant Likely
2011-07-13  8:47 ` [PATCH V2 06/12] ARM: EXYNOS4: Use generic DMA PL330 driver Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 07/12] ARM: S5PV210: " Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 08/12] ARM: S5PC100: " Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 09/12] ARM: S5P64X0: " Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 10/12] ARM: SAMSUNG: Remove S3C-PL330-DMA driver Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 11/12] spi/s3c64xx: Add support DMA engine API Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 12/12] ASoC: Samsung: Update DMA interface Kukjin Kim
2011-07-13  8:47   ` Kukjin Kim
2011-07-13 23:57   ` Mark Brown
2011-07-13 23:57     ` Mark Brown
2011-07-16  0:01     ` Kukjin Kim
2011-07-16  0:01       ` Kukjin Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110713091403.GI23270@n2100.arm.linux.org.uk \
    --to=linux@arm.linux.org.uk \
    --cc=boojin.kim@samsung.com \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=dan.j.williams@intel.com \
    --cc=grant.likely@secretlab.ca \
    --cc=jassisinghbrar@gmail.com \
    --cc=kgene.kim@samsung.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=lrg@ti.com \
    --cc=vinod.koul@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.