[PATCH 1/2] s3c24xx: DMA: don't use autoreload feature

Vasily Khoruzhick anarsoul at gmail.com
Tue Sep 7 19:23:19 EDT 2010


Some integrated DMA-capable hardware doesn't like autoreload
feature of s3c24xx DMA-engine, that's why s3cmci driver
didn't work with DMA transfers enabled.

I rewrote DMA driver not to use autoreload feature and removed
all pre-loading features. Buffer re-load is fast enought to perform
it in IRQ handler, and anyway I don't see any reason to waste CPU
cycles on waiting for buffer load. Driver is much simplier now,
it was tested with s3cmci and s3c24xx-i2s drivers on s3c2442 and
s3c2410 SoCs and works just nice.

Signed-off-by: Vasily Khoruzhick <anarsoul at gmail.com>
---
 arch/arm/mach-s3c2410/include/mach/dma.h |   17 +-
 arch/arm/plat-s3c24xx/dma.c              |  442 +++++-------------------------
 2 files changed, 75 insertions(+), 384 deletions(-)

diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
index cf68136..1cbeff2 100644
--- a/arch/arm/mach-s3c2410/include/mach/dma.h
+++ b/arch/arm/mach-s3c2410/include/mach/dma.h
@@ -79,28 +79,15 @@ enum s3c2410_dma_state {
  *
  * There are no buffers loaded (the channel should be inactive)
  *
- * S3C2410_DMA_1LOADED
- *
- * There is one buffer loaded, however it has not been confirmed to be
- * loaded by the DMA engine. This may be because the channel is not
- * yet running, or the DMA driver decided that it was too costly to
- * sit and wait for it to happen.
- *
  * S3C2410_DMA_1RUNNING
  *
- * The buffer has been confirmed running, and not finisged
- *
- * S3C2410_DMA_1LOADED_1RUNNING
+ * The buffer has been confirmed running, and not finished
  *
- * There is a buffer waiting to be loaded by the DMA engine, and one
- * currently running.
 */
 
 enum s3c2410_dma_loadst {
 	S3C2410_DMALOAD_NONE,
-	S3C2410_DMALOAD_1LOADED,
 	S3C2410_DMALOAD_1RUNNING,
-	S3C2410_DMALOAD_1LOADED_1RUNNING,
 };
 
 
@@ -129,6 +116,7 @@ struct s3c2410_dma_buf {
 	dma_addr_t		 data;		/* start of DMA data */
 	dma_addr_t		 ptr;		/* where the DMA got to [1] */
 	void			*id;		/* client's id */
+	unsigned int		timestamp;
 };
 
 /* [1] is this updated for both recv/send modes? */
@@ -189,6 +177,7 @@ struct s3c2410_dma_chan {
 	struct s3c2410_dma_buf	*curr;		/* current dma buffer */
 	struct s3c2410_dma_buf	*next;		/* next buffer to load */
 	struct s3c2410_dma_buf	*end;		/* end of queue */
+	spinlock_t				queue_lock;
 
 	/* system device */
 	struct sys_device	dev;
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 6ad274e..5ed045b 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -133,70 +133,6 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
 #define dbg_showchan(chan) do { } while(0)
 #endif /* CONFIG_S3C2410_DMA_DEBUG */
 
-/* s3c2410_dma_stats_timeout
- *
- * Update DMA stats from timeout info
-*/
-
-static void
-s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
-{
-	if (stats == NULL)
-		return;
-
-	if (val > stats->timeout_longest)
-		stats->timeout_longest = val;
-	if (val < stats->timeout_shortest)
-		stats->timeout_shortest = val;
-
-	stats->timeout_avg += val;
-}
-
-/* s3c2410_dma_waitforload
- *
- * wait for the DMA engine to load a buffer, and update the state accordingly
-*/
-
-static int
-s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
-{
-	int timeout = chan->load_timeout;
-	int took;
-
-	if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
-		printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
-		return 0;
-	}
-
-	if (chan->stats != NULL)
-		chan->stats->loads++;
-
-	while (--timeout > 0) {
-		if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
-			took = chan->load_timeout - timeout;
-
-			s3c2410_dma_stats_timeout(chan->stats, took);
-
-			switch (chan->load_state) {
-			case S3C2410_DMALOAD_1LOADED:
-				chan->load_state = S3C2410_DMALOAD_1RUNNING;
-				break;
-
-			default:
-				printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
-			}
-
-			return 1;
-		}
-	}
-
-	if (chan->stats != NULL) {
-		chan->stats->timeout_failed++;
-	}
-
-	return 0;
-}
-
 /* s3c2410_dma_loadbuffer
  *
  * load a buffer, and update the channel state
@@ -206,66 +142,35 @@ static inline int
 s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
 		       struct s3c2410_dma_buf *buf)
 {
-	unsigned long reload;
-
 	if (buf == NULL) {
 		dmawarn("buffer is NULL\n");
 		return -EINVAL;
 	}
 
-	pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
+	pr_debug("%s: loading buff %p (0x%08lx,0x%06x)\n", __func__,
 		 buf, (unsigned long)buf->data, buf->size);
 
 	/* check the state of the channel before we do anything */
 
-	if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-		dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
-	}
-
-	if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
-		dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
-	}
+	if (chan->load_state != S3C2410_DMALOAD_NONE)
+		printk(KERN_ERR "dma%d: channel already has buffer loaded\n",
+			   chan->number);
 
-	/* it would seem sensible if we are the last buffer to not bother
-	 * with the auto-reload bit, so that the DMA engine will not try
-	 * and load another transfer after this one has finished...
-	 */
-	if (chan->load_state == S3C2410_DMALOAD_NONE) {
-		pr_debug("load_state is none, checking for noreload (next=%p)\n",
-			 buf->next);
-		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
-	} else {
-		//pr_debug("load_state is %d => autoreload\n", chan->load_state);
-		reload = S3C2410_DCON_AUTORELOAD;
-	}
-
-	if ((buf->data & 0xf0000000) != 0x30000000) {
+	if ((buf->data & 0xf0000000) != 0x30000000)
 		dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
-	}
 
 	writel(buf->data, chan->addr_reg);
 
 	dma_wrreg(chan, S3C2410_DMA_DCON,
-		  chan->dcon | reload | (buf->size/chan->xfer_unit));
+		  chan->dcon | S3C2410_DCON_NORELOAD |
+		  (buf->size/chan->xfer_unit));
 
-	chan->next = buf->next;
+	chan->curr = buf;
 
 	/* update the state of the channel */
+	chan->load_state = S3C2410_DMALOAD_1RUNNING;
 
-	switch (chan->load_state) {
-	case S3C2410_DMALOAD_NONE:
-		chan->load_state = S3C2410_DMALOAD_1LOADED;
-		break;
-
-	case S3C2410_DMALOAD_1RUNNING:
-		chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
-		break;
-
-	default:
-		dmawarn("dmaload: unknown state %d in loadbuffer\n",
-			chan->load_state);
-		break;
-	}
+	buf->timestamp = jiffies;
 
 	return 0;
 }
@@ -345,7 +250,6 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
 	dbg_showchan(chan);
 
 	/* enable the channel */
-
 	if (!chan->irq_enabled) {
 		enable_irq(chan->irq);
 		chan->irq_enabled = 1;
@@ -360,14 +264,6 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
 
 	pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
 
-#if 0
-	/* the dma buffer loads should take care of clearing the AUTO
-	 * reloading feature */
-	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
-	tmp &= ~S3C2410_DCON_NORELOAD;
-	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
-#endif
-
 	s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
 
 	dbg_showchan(chan);
@@ -377,43 +273,11 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
 	 * the first buffer is finished, the new one will be loaded onto
 	 * the channel */
 
-	if (chan->next != NULL) {
-		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				pr_debug("%s: buff not yet loaded, no more todo\n",
-					 __func__);
-			} else {
-				chan->load_state = S3C2410_DMALOAD_1RUNNING;
-				s3c2410_dma_loadbuffer(chan, chan->next);
-			}
-
-		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
-			s3c2410_dma_loadbuffer(chan, chan->next);
-		}
-	}
-
-
 	local_irq_restore(flags);
 
 	return 0;
 }
 
-/* s3c2410_dma_canload
- *
- * work out if we can queue another buffer into the DMA engine
-*/
-
-static int
-s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
-{
-	if (chan->load_state == S3C2410_DMALOAD_NONE ||
-	    chan->load_state == S3C2410_DMALOAD_1RUNNING)
-		return 1;
-
-	return 0;
-}
-
 /* s3c2410_dma_enqueue
  *
  * queue an given buffer for dma transfer.
@@ -462,47 +326,19 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
 
 	local_irq_save(flags);
 
-	if (chan->curr == NULL) {
-		/* we've got nothing loaded... */
-		pr_debug("%s: buffer %p queued onto empty channel\n",
-			 __func__, buf);
-
-		chan->curr = buf;
-		chan->end  = buf;
-		chan->next = NULL;
+	if (chan->end == NULL) {
+		pr_debug("dma%d: queued buffer onto empty channel\n",
+			chan->number);
+		chan->next = buf;
+		chan->end = buf;
 	} else {
-		pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
-			 chan->number, __func__, buf);
-
-		if (chan->end == NULL)
-			pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
-				 chan->number, __func__, chan);
-
+		pr_debug("dma%d: queued buffer onto non-empty channel\n",
+			chan->number);
 		chan->end->next = buf;
 		chan->end = buf;
 	}
 
-	/* if necessary, update the next buffer field */
-	if (chan->next == NULL)
-		chan->next = buf;
-
-	/* check to see if we can load a buffer */
-	if (chan->state == S3C2410_DMA_RUNNING) {
-		if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				printk(KERN_ERR "dma%d: loadbuffer:"
-				       "timeout loading buffer\n",
-				       chan->number);
-				dbg_showchan(chan);
-				local_irq_restore(flags);
-				return -EINVAL;
-			}
-		}
-
-		while (s3c2410_dma_canload(chan) && chan->next != NULL) {
-			s3c2410_dma_loadbuffer(chan, chan->next);
-		}
-	} else if (chan->state == S3C2410_DMA_IDLE) {
+	if (chan->state == S3C2410_DMA_IDLE) {
 		if (chan->flags & S3C2410_DMAF_AUTOSTART) {
 			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
 					 S3C2410_DMAOP_START);
@@ -529,51 +365,6 @@ s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
 	}
 }
 
-/* s3c2410_dma_lastxfer
- *
- * called when the system is out of buffers, to ensure that the channel
- * is prepared for shutdown.
-*/
-
-static inline void
-s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
-{
-#if 0
-	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
-		 chan->number, chan->load_state);
-#endif
-
-	switch (chan->load_state) {
-	case S3C2410_DMALOAD_NONE:
-		break;
-
-	case S3C2410_DMALOAD_1LOADED:
-		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				/* flag error? */
-			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
-			       chan->number, __func__);
-			return;
-		}
-		break;
-
-	case S3C2410_DMALOAD_1LOADED_1RUNNING:
-		/* I belive in this case we do not have anything to do
-		 * until the next buffer comes along, and we turn off the
-		 * reload */
-		return;
-
-	default:
-		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
-			 chan->number, chan->load_state);
-		return;
-
-	}
-
-	/* hopefully this'll shut the damned thing up after the transfer... */
-	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
-}
-
-
 #define dmadbg2(x...)
 
 static irqreturn_t
@@ -582,57 +373,25 @@ s3c2410_dma_irq(int irq, void *devpw)
 	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
 	struct s3c2410_dma_buf  *buf;
 
+	/* Check for orphaned irq */
+	if (chan->state == S3C2410_DMA_IDLE)
+		return IRQ_HANDLED;
+
 	buf = chan->curr;
 
 	dbg_showchan(chan);
 
 	/* modify the channel state */
 
-	switch (chan->load_state) {
-	case S3C2410_DMALOAD_1RUNNING:
-		/* TODO - if we are running only one buffer, we probably
-		 * want to reload here, and then worry about the buffer
-		 * callback */
-
-		chan->load_state = S3C2410_DMALOAD_NONE;
-		break;
-
-	case S3C2410_DMALOAD_1LOADED:
-		/* iirc, we should go back to NONE loaded here, we
-		 * had a buffer, and it was never verified as being
-		 * loaded.
-		 */
-
+	if (chan->load_state == S3C2410_DMALOAD_1RUNNING)
 		chan->load_state = S3C2410_DMALOAD_NONE;
-		break;
-
-	case S3C2410_DMALOAD_1LOADED_1RUNNING:
-		/* we'll worry about checking to see if another buffer is
-		 * ready after we've called back the owner. This should
-		 * ensure we do not wait around too long for the DMA
-		 * engine to start the next transfer
-		 */
-
-		chan->load_state = S3C2410_DMALOAD_1LOADED;
-		break;
-
-	case S3C2410_DMALOAD_NONE:
+	else
 		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
-		       chan->number);
-		break;
-
-	default:
-		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
-		       chan->number, chan->load_state);
-		break;
-	}
+			chan->number);
 
 	if (buf != NULL) {
-		/* update the chain to make sure that if we load any more
-		 * buffers when we call the callback function, things should
-		 * work properly */
-
-		chan->curr = buf->next;
+		chan->curr = NULL;
+		chan->next = buf->next;
 		buf->next  = NULL;
 
 		if (buf->magic != BUF_MAGIC) {
@@ -640,12 +399,14 @@ s3c2410_dma_irq(int irq, void *devpw)
 			       chan->number, __func__, buf);
 			return IRQ_HANDLED;
 		}
-
+		pr_debug("dma%d: transfer of size %d took %u ms\n",
+			chan->number,
+			buf->size,
+			jiffies_to_msecs(jiffies - buf->timestamp));
 		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
 
 		/* free resouces */
 		s3c2410_dma_freebuf(buf);
-	} else {
 	}
 
 	/* only reload if the channel is still running... our buffer done
@@ -655,53 +416,36 @@ s3c2410_dma_irq(int irq, void *devpw)
 	/* todo: check that when the channel is shut-down from inside this
 	 * function, we cope with unsetting reload, etc */
 
-	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
-		unsigned long flags;
-
-		switch (chan->load_state) {
-		case S3C2410_DMALOAD_1RUNNING:
-			/* don't need to do anything for this state */
-			break;
-
-		case S3C2410_DMALOAD_NONE:
-			/* can load buffer immediately */
-			break;
-
-		case S3C2410_DMALOAD_1LOADED:
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				/* flag error? */
-				printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
-				       chan->number, __func__);
-				return IRQ_HANDLED;
-			}
-
-			break;
-
-		case S3C2410_DMALOAD_1LOADED_1RUNNING:
-			goto no_load;
-
-		default:
-			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
-			       chan->number, chan->load_state);
-			return IRQ_HANDLED;
-		}
+	if (chan->next != NULL) {
+		if (chan->state != S3C2410_DMA_IDLE) {
+			unsigned long flags;
+			unsigned long tmp;
 
-		local_irq_save(flags);
-		s3c2410_dma_loadbuffer(chan, chan->next);
-		local_irq_restore(flags);
+			pr_debug("%s: dma%d: continuing with next buffer\n",
+				__func__, chan->number);
+			local_irq_save(flags);
+			s3c2410_dma_loadbuffer(chan, chan->next);
+			tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+			tmp &= ~S3C2410_DMASKTRIG_STOP;
+			tmp |= S3C2410_DMASKTRIG_ON;
+			dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+			local_irq_restore(flags);
+		} else
+			pr_debug("dma%d: buffdone callback stopped dma...\n",
+				chan->number);
 	} else {
-		s3c2410_dma_lastxfer(chan);
+		/* No more buffers? So no queue */
+		chan->end = NULL;
 
 		/* see if we can stop this channel.. */
-		if (chan->load_state == S3C2410_DMALOAD_NONE) {
-			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
+		if (chan->state != S3C2410_DMA_IDLE) {
+			pr_debug("dma%d: end of transfer, stopping channel (%lu)\n",
 				 chan->number, jiffies);
 			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
 					 S3C2410_DMAOP_STOP);
 		}
 	}
 
- no_load:
 	return IRQ_HANDLED;
 }
 
@@ -840,9 +584,20 @@ static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
 	s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP);
 
 	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-	tmp |= S3C2410_DMASKTRIG_STOP;
-	//tmp &= ~S3C2410_DMASKTRIG_ON;
-	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+	if (tmp & S3C2410_DMASKTRIG_ON) {
+		int retries = 1000;
+		tmp |= S3C2410_DMASKTRIG_STOP;
+		dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+
+		while (--retries) {
+			tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+			if (!(tmp & S3C2410_DMASKTRIG_ON))
+				break;
+		}
+
+		if (!retries)
+			pr_debug("dma%d: failed to stop??\n", chan->number);
+	}
 
 #if 0
 	/* should also clear interrupts, according to WinCE BSP */
@@ -860,22 +615,6 @@ static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
 	return 0;
 }
 
-static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
-{
-	unsigned long tmp;
-	unsigned int timeout = 0x10000;
-
-	while (timeout-- > 0) {
-		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-
-		if (!(tmp & S3C2410_DMASKTRIG_ON))
-			return;
-	}
-
-	pr_debug("dma%d: failed to stop?\n", chan->number);
-}
-
-
 /* s3c2410_dma_flush
  *
  * stop the channel, and remove all current and pending transfers
@@ -917,8 +656,6 @@ static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
 
 	dbg_showregs(chan);
 
-	s3c2410_dma_waitforstop(chan);
-
 #if 0
 	/* should also clear interrupts, according to WinCE BSP */
 	{
@@ -939,38 +676,8 @@ static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
 
 static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
 {
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	dbg_showchan(chan);
-
-	/* if we've only loaded one buffer onto the channel, then chec
-	 * to see if we have another, and if so, try and load it so when
-	 * the first buffer is finished, the new one will be loaded onto
-	 * the channel */
-
-	if (chan->next != NULL) {
-		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				pr_debug("%s: buff not yet loaded, no more todo\n",
-					 __func__);
-			} else {
-				chan->load_state = S3C2410_DMALOAD_1RUNNING;
-				s3c2410_dma_loadbuffer(chan, chan->next);
-			}
-
-		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
-			s3c2410_dma_loadbuffer(chan, chan->next);
-		}
-	}
-
-
-	local_irq_restore(flags);
-
+	/* Do nothing */
 	return 0;
-
 }
 
 int
@@ -1045,16 +752,12 @@ int s3c2410_dma_config(unsigned int channel,
 	case DMACH_PCM_IN:
 	case DMACH_PCM_OUT:
 	case DMACH_MIC_IN:
+	case DMACH_SDI:
 	default:
 		dcon |= S3C2410_DCON_HANDSHAKE;
 		dcon |= S3C2410_DCON_SYNC_PCLK;
 		break;
 
-	case DMACH_SDI:
-		/* note, ensure if need HANDSHAKE or not */
-		dcon |= S3C2410_DCON_SYNC_PCLK;
-		break;
-
 	case DMACH_XD0:
 	case DMACH_XD1:
 		dcon |= S3C2410_DCON_HANDSHAKE;
@@ -1231,21 +934,20 @@ static int s3c2410_dma_resume(struct sys_device *dev)
 	struct s3c2410_dma_chan *cp = to_dma_chan(dev);
 	unsigned int no = cp->number | DMACH_LOW_LEVEL;
 
-	/* restore channel's hardware configuration */
 
 	if (!cp->in_use)
 		return 0;
 
-	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
-
-	s3c2410_dma_config(no, cp->xfer_unit);
-	s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
 
 	/* re-select the dma source for this channel */
-
 	if (cp->map != NULL)
 		dma_sel.select(cp, cp->map);
 
+	/* restore channel's hardware configuration */
+	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
+	s3c2410_dma_config(no, cp->xfer_unit);
+	s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
+
 	return 0;
 }
 
-- 
1.7.2.2




More information about the linux-arm-kernel mailing list