All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Ujfalusi <peter.ujfalusi@ti.com>
To: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
	Vinod Koul <vinod.koul@intel.com>,
	Russell King <rmk+kernel@arm.linux.org.uk>,
	peter@hurleysoftware.com
Cc: Dan Williams <dan.j.williams@intel.com>,
	dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org,
	nsekhar@ti.com, linux-omap@vger.kernel.org,
	linux-serial@vger.kernel.org, john.ogness@linutronix.de
Subject: Re: [PATCH v3 3/3] dma: omap-dma: add support for pause of non-cyclic transfers
Date: Tue, 11 Aug 2015 15:02:44 +0300	[thread overview]
Message-ID: <55C9E464.2060404@ti.com> (raw)
In-Reply-To: <1438977619-15488-4-git-send-email-bigeasy@linutronix.de>

On 08/07/2015 11:00 PM, Sebastian Andrzej Siewior wrote:
> -static void omap_dma_stop(struct omap_chan *c)
> +static void omap_dma_drain_chan(struct omap_chan *c)
> +{
> +	int i;
> +	uint32_t val;
> +
> +	/* Wait for sDMA FIFO to drain */
> +	for (i = 0; ; i++) {
> +		val = omap_dma_chan_read(c, CCR);
> +		if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)))
> +			break;
> +
> +		if (i > 100)
> +			break;
> +
> +		udelay(5);
> +	}
> +
> +	if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))
> +		dev_err(c->vc.chan.device->dev,
> +			"DMA drain did not complete on lch %d\n",
> +			c->dma_ch);
> +}
> +
> +static int omap_dma_stop(struct omap_chan *c)
>  {
>  	struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
>  	uint32_t val;
> @@ -312,7 +335,6 @@ static void omap_dma_stop(struct omap_chan *c)
>  	val = omap_dma_chan_read(c, CCR);
>  	if (od->plat->errata & DMA_ERRATA_i541 && val & CCR_TRIGGER_SRC) {
>  		uint32_t sysconfig;
> -		unsigned i;
>  
>  		sysconfig = omap_dma_glbl_read(od, OCP_SYSCONFIG);
>  		val = sysconfig & ~DMA_SYSCONFIG_MIDLEMODE_MASK;
> @@ -323,27 +345,18 @@ static void omap_dma_stop(struct omap_chan *c)
>  		val &= ~CCR_ENABLE;
>  		omap_dma_chan_write(c, CCR, val);
>  
> -		/* Wait for sDMA FIFO to drain */
> -		for (i = 0; ; i++) {
> -			val = omap_dma_chan_read(c, CCR);
> -			if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)))
> -				break;
> -
> -			if (i > 100)
> -				break;
> -
> -			udelay(5);
> -		}
> -
> -		if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))
> -			dev_err(c->vc.chan.device->dev,
> -				"DMA drain did not complete on lch %d\n",
> -			        c->dma_ch);
> +		omap_dma_drain_chan(c);
>  
>  		omap_dma_glbl_write(od, OCP_SYSCONFIG, sysconfig);
>  	} else {
> +
> +		if (!(val & CCR_ENABLE))
> +			return -EINVAL;
> +
>  		val &= ~CCR_ENABLE;
>  		omap_dma_chan_write(c, CCR, val);
> +
> +		omap_dma_drain_chan(c);

Note that the FIFO drain only applies to source synchronized transfers... When
the BUFFERING is _not_ disabled - in most of the cases this is true.

> +	/*
> +	 * We do not allow DMA_MEM_TO_DEV transfers to be paused.
> +	 * From the AM572x TRM, 16.1.4.18 Disabling a Channel During Transfer:
> +	 * "When a channel is disabled during a transfer, the channel undergoes
> +	 * an abort, unless it is hardware-source-synchronized …".
> +	 * A source-synchronised channel is one where the fetching of data is
> +	 * under control of the device. In other words, a device-to-memory
> +	 * transfer. So, a destination-synchronised channel (which would be a
> +	 * memory-to-device transfer) undergoes an abort if the the CCR_ENABLE
> +	 * bit is cleared.
> +	 * From 16.1.4.20.4.6.2 Abort: "If an abort trigger occurs, the channel
> +	 * aborts immediately after completion of current read/write
> +	 * transactions and then the FIFO is cleaned up." The term "cleaned up"
> +	 * is not defined. TI recommends to check that RD_ACTIVE and WR_ACTIVE
> +	 * are both clear _before_ disabling the channel, otherwise data loss
> +	 * will occur.
> +	 * The problem is that if the channel is active, then device activity
> +	 * can result in DMA activity starting between reading those as both
> +	 * clear and the write to DMA_CCR to clear the enable bit hitting the
> +	 * hardware. If the DMA hardware can't drain the data in its FIFO to the
> +	 * destination, then data loss "might" occur (say if we write to an UART
> +	 * and the UART is not accepting any further data).

I don't know if you have checked it, but probably the TX DMA could be also
used when the PRZEFETCH is disabled for the channel? Just a guess

> +	 */
> +	else if (c->desc->dir == DMA_DEV_TO_MEM)
> +		can_pause = true;
> +
> +	if (can_pause && !c->paused) {
> +		ret = omap_dma_stop(c);
> +		if (!ret)
> +			c->paused = true;
>  	}
> +out:
> +	spin_unlock_irqrestore(&od->irq_lock, flags);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int omap_dma_resume(struct dma_chan *chan)
>  {
>  	struct omap_chan *c = to_omap_dma_chan(chan);
> +	struct omap_dmadev *od = to_omap_dma_dev(chan->device);
> +	unsigned long flags;
> +	int ret = -EINVAL;
>  
> -	/* Pause/Resume only allowed with cyclic mode */
> -	if (!c->cyclic)
> -		return -EINVAL;
> +	spin_lock_irqsave(&od->irq_lock, flags);
>  
> -	if (c->paused) {
> +	if (c->paused && c->desc) {
>  		mb();
>  
>  		/* Restore channel link register */
> @@ -1082,9 +1134,11 @@ static int omap_dma_resume(struct dma_chan *chan)
>  
>  		omap_dma_start(c, c->desc);
>  		c->paused = false;
> +		ret = 0;
>  	}
> +	spin_unlock_irqrestore(&od->irq_lock, flags);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int omap_dma_chan_init(struct omap_dmadev *od)
> 


-- 
Péter

WARNING: multiple messages have this Message-ID (diff)
From: Peter Ujfalusi <peter.ujfalusi@ti.com>
To: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
	Vinod Koul <vinod.koul@intel.com>,
	Russell King <rmk+kernel@arm.linux.org.uk>,
	<peter@hurleysoftware.com>
Cc: Dan Williams <dan.j.williams@intel.com>,
	<dmaengine@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<nsekhar@ti.com>, <linux-omap@vger.kernel.org>,
	<linux-serial@vger.kernel.org>, <john.ogness@linutronix.de>
Subject: Re: [PATCH v3 3/3] dma: omap-dma: add support for pause of non-cyclic transfers
Date: Tue, 11 Aug 2015 15:02:44 +0300	[thread overview]
Message-ID: <55C9E464.2060404@ti.com> (raw)
In-Reply-To: <1438977619-15488-4-git-send-email-bigeasy@linutronix.de>

On 08/07/2015 11:00 PM, Sebastian Andrzej Siewior wrote:
> -static void omap_dma_stop(struct omap_chan *c)
> +static void omap_dma_drain_chan(struct omap_chan *c)
> +{
> +	int i;
> +	uint32_t val;
> +
> +	/* Wait for sDMA FIFO to drain */
> +	for (i = 0; ; i++) {
> +		val = omap_dma_chan_read(c, CCR);
> +		if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)))
> +			break;
> +
> +		if (i > 100)
> +			break;
> +
> +		udelay(5);
> +	}
> +
> +	if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))
> +		dev_err(c->vc.chan.device->dev,
> +			"DMA drain did not complete on lch %d\n",
> +			c->dma_ch);
> +}
> +
> +static int omap_dma_stop(struct omap_chan *c)
>  {
>  	struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
>  	uint32_t val;
> @@ -312,7 +335,6 @@ static void omap_dma_stop(struct omap_chan *c)
>  	val = omap_dma_chan_read(c, CCR);
>  	if (od->plat->errata & DMA_ERRATA_i541 && val & CCR_TRIGGER_SRC) {
>  		uint32_t sysconfig;
> -		unsigned i;
>  
>  		sysconfig = omap_dma_glbl_read(od, OCP_SYSCONFIG);
>  		val = sysconfig & ~DMA_SYSCONFIG_MIDLEMODE_MASK;
> @@ -323,27 +345,18 @@ static void omap_dma_stop(struct omap_chan *c)
>  		val &= ~CCR_ENABLE;
>  		omap_dma_chan_write(c, CCR, val);
>  
> -		/* Wait for sDMA FIFO to drain */
> -		for (i = 0; ; i++) {
> -			val = omap_dma_chan_read(c, CCR);
> -			if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)))
> -				break;
> -
> -			if (i > 100)
> -				break;
> -
> -			udelay(5);
> -		}
> -
> -		if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))
> -			dev_err(c->vc.chan.device->dev,
> -				"DMA drain did not complete on lch %d\n",
> -			        c->dma_ch);
> +		omap_dma_drain_chan(c);
>  
>  		omap_dma_glbl_write(od, OCP_SYSCONFIG, sysconfig);
>  	} else {
> +
> +		if (!(val & CCR_ENABLE))
> +			return -EINVAL;
> +
>  		val &= ~CCR_ENABLE;
>  		omap_dma_chan_write(c, CCR, val);
> +
> +		omap_dma_drain_chan(c);

Note that the FIFO drain only applies to source synchronized transfers... When
the BUFFERING is _not_ disabled - in most of the cases this is true.

> +	/*
> +	 * We do not allow DMA_MEM_TO_DEV transfers to be paused.
> +	 * From the AM572x TRM, 16.1.4.18 Disabling a Channel During Transfer:
> +	 * "When a channel is disabled during a transfer, the channel undergoes
> +	 * an abort, unless it is hardware-source-synchronized …".
> +	 * A source-synchronised channel is one where the fetching of data is
> +	 * under control of the device. In other words, a device-to-memory
> +	 * transfer. So, a destination-synchronised channel (which would be a
> +	 * memory-to-device transfer) undergoes an abort if the the CCR_ENABLE
> +	 * bit is cleared.
> +	 * From 16.1.4.20.4.6.2 Abort: "If an abort trigger occurs, the channel
> +	 * aborts immediately after completion of current read/write
> +	 * transactions and then the FIFO is cleaned up." The term "cleaned up"
> +	 * is not defined. TI recommends to check that RD_ACTIVE and WR_ACTIVE
> +	 * are both clear _before_ disabling the channel, otherwise data loss
> +	 * will occur.
> +	 * The problem is that if the channel is active, then device activity
> +	 * can result in DMA activity starting between reading those as both
> +	 * clear and the write to DMA_CCR to clear the enable bit hitting the
> +	 * hardware. If the DMA hardware can't drain the data in its FIFO to the
> +	 * destination, then data loss "might" occur (say if we write to an UART
> +	 * and the UART is not accepting any further data).

I don't know if you have checked it, but probably the TX DMA could be also
used when the PRZEFETCH is disabled for the channel? Just a guess

> +	 */
> +	else if (c->desc->dir == DMA_DEV_TO_MEM)
> +		can_pause = true;
> +
> +	if (can_pause && !c->paused) {
> +		ret = omap_dma_stop(c);
> +		if (!ret)
> +			c->paused = true;
>  	}
> +out:
> +	spin_unlock_irqrestore(&od->irq_lock, flags);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int omap_dma_resume(struct dma_chan *chan)
>  {
>  	struct omap_chan *c = to_omap_dma_chan(chan);
> +	struct omap_dmadev *od = to_omap_dma_dev(chan->device);
> +	unsigned long flags;
> +	int ret = -EINVAL;
>  
> -	/* Pause/Resume only allowed with cyclic mode */
> -	if (!c->cyclic)
> -		return -EINVAL;
> +	spin_lock_irqsave(&od->irq_lock, flags);
>  
> -	if (c->paused) {
> +	if (c->paused && c->desc) {
>  		mb();
>  
>  		/* Restore channel link register */
> @@ -1082,9 +1134,11 @@ static int omap_dma_resume(struct dma_chan *chan)
>  
>  		omap_dma_start(c, c->desc);
>  		c->paused = false;
> +		ret = 0;
>  	}
> +	spin_unlock_irqrestore(&od->irq_lock, flags);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int omap_dma_chan_init(struct omap_dmadev *od)
> 


-- 
Péter

  reply	other threads:[~2015-08-11 12:02 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-07 20:00 omap-dma + 8250_omap: fix the dmaengine_pause() Sebastian Andrzej Siewior
2015-08-07 20:00 ` [PATCH 1/3] tty: serial: 8250_omap: do not use RX DMA if pause is not supported Sebastian Andrzej Siewior
2015-08-08  0:28   ` Peter Hurley
2015-08-08  9:03     ` Russell King - ARM Linux
2015-08-11  9:57       ` Vinod Koul
2015-08-08  9:32     ` Sebastian Andrzej Siewior
2015-08-08  9:57       ` Russell King - ARM Linux
2015-08-08 15:40       ` Greg KH
2015-08-10 11:54   ` Peter Ujfalusi
2015-08-10 11:54     ` Peter Ujfalusi
2015-08-10 12:19     ` Sebastian Andrzej Siewior
2015-08-10 13:00     ` Peter Hurley
2015-08-10 17:15       ` Russell King - ARM Linux
2015-08-07 20:00 ` [PATCH 2/3] dma: add __must_check annotation for dmaengine_pause() Sebastian Andrzej Siewior
2015-08-08  0:40   ` Peter Hurley
2015-08-11  9:58   ` Vinod Koul
2015-08-11 10:06     ` Russell King - ARM Linux
2015-08-11 12:34       ` Sebastian Andrzej Siewior
2015-08-21  8:32         ` Vinod Koul
2015-08-07 20:00 ` [PATCH v3 3/3] dma: omap-dma: add support for pause of non-cyclic transfers Sebastian Andrzej Siewior
2015-08-07 20:00   ` Sebastian Andrzej Siewior
2015-08-11 12:02   ` Peter Ujfalusi [this message]
2015-08-11 12:02     ` Peter Ujfalusi
2015-08-11 12:30     ` Russell King - ARM Linux
2015-08-11 12:43       ` Peter Ujfalusi
2015-08-11 12:43         ` Peter Ujfalusi

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=55C9E464.2060404@ti.com \
    --to=peter.ujfalusi@ti.com \
    --cc=bigeasy@linutronix.de \
    --cc=dan.j.williams@intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=john.ogness@linutronix.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=nsekhar@ti.com \
    --cc=peter@hurleysoftware.com \
    --cc=rmk+kernel@arm.linux.org.uk \
    --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.