LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 3/9] fsldma: use channel name in printk output
From: Joe Perches @ 2011-03-02 23:17 UTC (permalink / raw)
  To: Ira W. Snyder; +Cc: dan.j.williams, linuxppc-dev, linux-kernel
In-Reply-To: <1299104601-15447-4-git-send-email-iws@ovro.caltech.edu>

On Wed, 2011-03-02 at 14:23 -0800, Ira W. Snyder wrote:
> This makes debugging the driver much easier when multiple channels are
> running concurrently. In addition, you can see how much descriptor
> memory each channel has allocated via the dmapool API in sysfs.
> 
> Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
> ---
>  drivers/dma/fsldma.c |   60 +++++++++++++++++++++++++++----------------------
>  drivers/dma/fsldma.h |    1 +
>  2 files changed, 34 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index 2e1af45..6e3d3d7 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -37,7 +37,7 @@
>  
>  #include "fsldma.h"
>  
> -static const char msg_ld_oom[] = "No free memory for link descriptor\n";
> +static const char msg_ld_oom[] = "No free memory for link descriptor";
>  
>  /*
>   * Register Helpers
> @@ -207,7 +207,7 @@ static void dma_halt(struct fsldma_chan *chan)
>  	}
>  
>  	if (!dma_is_idle(chan))
> -		dev_err(chan->dev, "DMA halt timeout!\n");
> +		dev_err(chan->dev, "%s: DMA halt timeout!\n", chan->name);

I suggest instead you add:

#define chan_err(chan, fmt, arg...) 				\
	dev_err(chan->dev, "%s: " fmt, chan->name, ##arg);
#define chan_info(chan, fmt, arg...)				\
	dev_info(chan->dev, "%s: " fmt, chan->name, ##arg);
#define chan_dbg(chan, fmt, arg...)				\
	dev_dbg(chan->dev, "%s: " fmt, chan->name, ##arg);

and change the uses to be similar to:

	if (!dma_is_idle(chan))
		chan_err(chan, "DMA halt timeout!\n");

etc...

^ permalink raw reply

* [PATCH v2 8/9] fsldma: reduce locking during descriptor cleanup
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

This merges the fsl_chan_ld_cleanup() function into the dma_do_tasklet()
function to reduce locking overhead. In the best case, we will be able
to keep the DMA controller busy while we are freeing used descriptors.
In all cases, the spinlock is grabbed two times fewer than before on
each transaction.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  114 +++++++++++++++++++++----------------------------
 1 files changed, 49 insertions(+), 65 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 48e48c7..40babc1 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -879,67 +879,16 @@ static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
 }
 
 /**
- * fsl_chan_ld_cleanup - Clean up link descriptors
- * @chan : Freescale DMA channel
- *
- * This function is run after the queue of running descriptors has been
- * executed by the DMA engine. It will run any callbacks, and then free
- * the descriptors.
- *
- * HARDWARE STATE: idle
- */
-static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
-{
-	struct fsl_desc_sw *desc, *_desc;
-	const char *name = chan->name;
-	LIST_HEAD(ld_cleanup);
-	unsigned long flags;
-
-	spin_lock_irqsave(&chan->desc_lock, flags);
-
-	/* update the cookie if we have some descriptors to cleanup */
-	if (!list_empty(&chan->ld_running)) {
-		dma_cookie_t cookie;
-
-		desc = to_fsl_desc(chan->ld_running.prev);
-		cookie = desc->async_tx.cookie;
-
-		chan->completed_cookie = cookie;
-		dev_dbg(chan->dev, "%s: completed_cookie=%d\n", name, cookie);
-	}
-
-	/*
-	 * move the descriptors to a temporary list so we can drop the lock
-	 * during the entire cleanup operation
-	 */
-	list_splice_tail_init(&chan->ld_running, &ld_cleanup);
-
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
-
-	/* Run the callback for each descriptor, in order */
-	list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
-
-		/* Remove from the list of transactions */
-		list_del(&desc->node);
-
-		/* Run all cleanup for this descriptor */
-		fsldma_cleanup_descriptor(chan, desc);
-	}
-}
-
-/**
  * fsl_chan_xfer_ld_queue - transfer any pending transactions
  * @chan : Freescale DMA channel
  *
  * HARDWARE STATE: idle
+ * LOCKING: must hold chan->desc_lock
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
 	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&chan->desc_lock, flags);
 
 	/*
 	 * If the list of pending descriptors is empty, then we
@@ -947,7 +896,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 */
 	if (list_empty(&chan->ld_pending)) {
 		dev_dbg(chan->dev, "%s: no pending LDs\n", name);
-		goto out_unlock;
+		return;
 	}
 
 	/*
@@ -957,7 +906,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 */
 	if (!chan->idle) {
 		dev_dbg(chan->dev, "%s: DMA controller still busy\n", name);
-		goto out_unlock;
+		return;
 	}
 
 	/*
@@ -995,9 +944,6 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 
 	dma_start(chan);
 	chan->idle = false;
-
-out_unlock:
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
@@ -1007,7 +953,11 @@ out_unlock:
 static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
 {
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->desc_lock, flags);
 	fsl_chan_xfer_ld_queue(chan);
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
@@ -1109,21 +1059,55 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 static void dma_do_tasklet(unsigned long data)
 {
 	struct fsldma_chan *chan = (struct fsldma_chan *)data;
+	struct fsl_desc_sw *desc, *_desc;
+	const char *name = chan->name;
+	LIST_HEAD(ld_cleanup);
 	unsigned long flags;
 
-	dev_dbg(chan->dev, "%s: tasklet entry\n", chan->name);
+	dev_dbg(chan->dev, "%s: tasklet entry\n", name);
 
-	/* run all callbacks, free all used descriptors */
-	fsl_chan_ld_cleanup(chan);
-
-	/* the channel is now idle */
 	spin_lock_irqsave(&chan->desc_lock, flags);
+
+	/* update the cookie if we have some descriptors to cleanup */
+	if (!list_empty(&chan->ld_running)) {
+		dma_cookie_t cookie;
+
+		desc = to_fsl_desc(chan->ld_running.prev);
+		cookie = desc->async_tx.cookie;
+
+		chan->completed_cookie = cookie;
+		dev_dbg(chan->dev, "%s: completed_cookie=%d\n", name, cookie);
+	}
+
+	/*
+	 * move the descriptors to a temporary list so we can drop the lock
+	 * during the entire cleanup operation
+	 */
+	list_splice_tail_init(&chan->ld_running, &ld_cleanup);
+
+	/* the hardware is now idle and ready for more */
 	chan->idle = true;
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
-	/* start any pending transactions automatically */
+	/*
+	 * Start any pending transactions automatically
+	 *
+	 * In the ideal case, we keep the DMA controller busy while we go
+	 * ahead and free the descriptors below.
+	 */
 	fsl_chan_xfer_ld_queue(chan);
-	dev_dbg(chan->dev, "%s: tasklet exit\n", chan->name);
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+	/* Run the callback for each descriptor, in order */
+	list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
+
+		/* Remove from the list of transactions */
+		list_del(&desc->node);
+
+		/* Run all cleanup for this descriptor */
+		fsldma_cleanup_descriptor(chan, desc);
+	}
+
+	dev_dbg(chan->dev, "%s: tasklet exit\n", name);
 }
 
 static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 7/9] fsldma: support async_tx dependencies and automatic unmapping
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

Previous to this patch, the dma_run_dependencies() function has been
called while holding desc_lock. This function can call tx_submit() for
other descriptors, which may try to re-grab the lock. Avoid this by
moving the descriptors to be cleaned up to a temporary list, and
dropping the lock before cleanup.

At the same time, add support for automatic unmapping of src and dst
buffers, as offered by the DMAEngine API.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  132 ++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 95 insertions(+), 37 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index e9bb51e..48e48c7 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -78,6 +78,11 @@ static void set_desc_cnt(struct fsldma_chan *chan,
 	hw->count = CPU_TO_DMA(chan, count, 32);
 }
 
+static u32 get_desc_cnt(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
+{
+	return DMA_TO_CPU(chan, desc->hw.count, 32);
+}
+
 static void set_desc_src(struct fsldma_chan *chan,
 			 struct fsl_dma_ld_hw *hw, dma_addr_t src)
 {
@@ -88,6 +93,16 @@ static void set_desc_src(struct fsldma_chan *chan,
 	hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64);
 }
 
+static dma_addr_t get_desc_src(struct fsldma_chan *chan,
+			       struct fsl_desc_sw *desc)
+{
+	u64 snoop_bits;
+
+	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+		? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0;
+	return DMA_TO_CPU(chan, desc->hw.src_addr, 64) & ~snoop_bits;
+}
+
 static void set_desc_dst(struct fsldma_chan *chan,
 			 struct fsl_dma_ld_hw *hw, dma_addr_t dst)
 {
@@ -98,6 +113,16 @@ static void set_desc_dst(struct fsldma_chan *chan,
 	hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64);
 }
 
+static dma_addr_t get_desc_dst(struct fsldma_chan *chan,
+			       struct fsl_desc_sw *desc)
+{
+	u64 snoop_bits;
+
+	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+		? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0;
+	return DMA_TO_CPU(chan, desc->hw.dst_addr, 64) & ~snoop_bits;
+}
+
 static void set_desc_next(struct fsldma_chan *chan,
 			  struct fsl_dma_ld_hw *hw, dma_addr_t next)
 {
@@ -803,6 +828,57 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 }
 
 /**
+ * fsldma_cleanup_descriptor - cleanup and free a single link descriptor
+ * @chan: Freescale DMA channel
+ * @desc: descriptor to cleanup and free
+ *
+ * This function is used on a descriptor which has been executed by the DMA
+ * controller. It will run any callbacks, submit any dependencies, and then
+ * free the descriptor.
+ */
+static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
+				      struct fsl_desc_sw *desc)
+{
+	struct dma_async_tx_descriptor *txd = &desc->async_tx;
+	struct device *dev = chan->common.device->dev;
+	dma_addr_t src = get_desc_src(chan, desc);
+	dma_addr_t dst = get_desc_dst(chan, desc);
+	u32 len = get_desc_cnt(chan, desc);
+
+	/* Run the link descriptor callback function */
+	if (txd->callback) {
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p callback\n", chan->name, desc);
+#endif
+		txd->callback(txd->callback_param);
+	}
+
+	/* Run any dependencies */
+	dma_run_dependencies(txd);
+
+	/* Unmap the dst buffer, if requested */
+	if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+		if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+			dma_unmap_single(dev, dst, len, DMA_FROM_DEVICE);
+		else
+			dma_unmap_page(dev, dst, len, DMA_FROM_DEVICE);
+	}
+
+	/* Unmap the src buffer, if requested */
+	if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+		if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+			dma_unmap_single(dev, src, len, DMA_TO_DEVICE);
+		else
+			dma_unmap_page(dev, src, len, DMA_TO_DEVICE);
+	}
+
+#ifdef FSL_DMA_LD_DEBUG
+	dev_dbg(chan->dev, "%s: LD %p free\n", chan->name, desc);
+#endif
+	dma_pool_free(chan->desc_pool, desc, txd->phys);
+}
+
+/**
  * fsl_chan_ld_cleanup - Clean up link descriptors
  * @chan : Freescale DMA channel
  *
@@ -816,57 +892,39 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 {
 	struct fsl_desc_sw *desc, *_desc;
 	const char *name = chan->name;
+	LIST_HEAD(ld_cleanup);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
-	/* if the ld_running list is empty, there is nothing to do */
-	if (list_empty(&chan->ld_running)) {
-		dev_dbg(chan->dev, "%s: no descriptors to cleanup\n", name);
-		goto out_unlock;
+	/* update the cookie if we have some descriptors to cleanup */
+	if (!list_empty(&chan->ld_running)) {
+		dma_cookie_t cookie;
+
+		desc = to_fsl_desc(chan->ld_running.prev);
+		cookie = desc->async_tx.cookie;
+
+		chan->completed_cookie = cookie;
+		dev_dbg(chan->dev, "%s: completed_cookie=%d\n", name, cookie);
 	}
 
 	/*
-	 * Get the last descriptor, update the cookie to it
-	 *
-	 * This is done before callbacks run so that clients can check the
-	 * status of their DMA transfer inside the callback.
+	 * move the descriptors to a temporary list so we can drop the lock
+	 * during the entire cleanup operation
 	 */
-	desc = to_fsl_desc(chan->ld_running.prev);
-	chan->completed_cookie = desc->async_tx.cookie;
-	dev_dbg(chan->dev, "%s: completed_cookie = %d\n",
-			   name, chan->completed_cookie);
+	list_splice_tail_init(&chan->ld_running, &ld_cleanup);
+
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
 	/* Run the callback for each descriptor, in order */
-	list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
-		dma_async_tx_callback callback;
-		void *callback_param;
+	list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
 
-		/* Remove from the list of running transactions */
+		/* Remove from the list of transactions */
 		list_del(&desc->node);
 
-		/* Run the link descriptor callback function */
-		callback = desc->async_tx.callback;
-		callback_param = desc->async_tx.callback_param;
-		if (callback) {
-			spin_unlock_irqrestore(&chan->desc_lock, flags);
-#ifdef FSL_DMA_LD_DEBUG
-			dev_dbg(chan->dev, "%s: LD %p callback\n", name, desc);
-#endif
-			callback(callback_param);
-			spin_lock_irqsave(&chan->desc_lock, flags);
-		}
-
-		/* Run any dependencies, then free the descriptor */
-		dma_run_dependencies(&desc->async_tx);
-#ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "%s: LD %p free\n", name, desc);
-#endif
-		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
+		/* Run all cleanup for this descriptor */
+		fsldma_cleanup_descriptor(chan, desc);
 	}
-
-out_unlock:
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 6/9] fsldma: fix controller lockups
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

Enabling poisoning in the dmapool API quickly showed that the DMA
controller was fetching descriptors that should not have been in use.
This has caused intermittent controller lockups during testing.

I have been unable to figure out the exact set of conditions which cause
this to happen. However, I believe it is related to the driver using the
hardware registers to track whether the controller is busy or not. The
code can incorrectly decide that the hardware is idle due to lag between
register writes and the hardware actually becoming busy.

To fix this, the driver has been reworked to explicitly track the state
of the hardware, rather than try to guess what it is doing based on the
register values.

This has passed dmatest with 10 threads per channel, 100000 iterations
per thread several times without error. Previously, this would fail
within a few seconds.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  225 ++++++++++++++++++++++----------------------------
 drivers/dma/fsldma.h |    1 +
 2 files changed, 101 insertions(+), 125 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 06421c0..e9bb51e 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -63,11 +63,6 @@ static dma_addr_t get_cdar(struct fsldma_chan *chan)
 	return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
 }
 
-static dma_addr_t get_ndar(struct fsldma_chan *chan)
-{
-	return DMA_IN(chan, &chan->regs->ndar, 64);
-}
-
 static u32 get_bcr(struct fsldma_chan *chan)
 {
 	return DMA_IN(chan, &chan->regs->bcr, 32);
@@ -138,13 +133,11 @@ static void dma_init(struct fsldma_chan *chan)
 	case FSL_DMA_IP_85XX:
 		/* Set the channel to below modes:
 		 * EIE - Error interrupt enable
-		 * EOSIE - End of segments interrupt enable (basic mode)
 		 * EOLNIE - End of links interrupt enable
 		 * BWC - Bandwidth sharing among channels
 		 */
 		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
-				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
-				| FSL_DMA_MR_EOSIE, 32);
+				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE, 32);
 		break;
 	case FSL_DMA_IP_83XX:
 		/* Set the channel to below modes:
@@ -163,25 +156,32 @@ static int dma_is_idle(struct fsldma_chan *chan)
 	return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH);
 }
 
+/*
+ * Start the DMA controller
+ *
+ * Preconditions:
+ * - the CDAR register must point to the start descriptor
+ * - the MRn[CS] bit must be cleared
+ */
 static void dma_start(struct fsldma_chan *chan)
 {
 	u32 mode;
 
 	mode = DMA_IN(chan, &chan->regs->mr, 32);
 
-	if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
-		if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
-			DMA_OUT(chan, &chan->regs->bcr, 0, 32);
-			mode |= FSL_DMA_MR_EMP_EN;
-		} else {
-			mode &= ~FSL_DMA_MR_EMP_EN;
-		}
+	if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
+		DMA_OUT(chan, &chan->regs->bcr, 0, 32);
+		mode |= FSL_DMA_MR_EMP_EN;
+	} else {
+		mode &= ~FSL_DMA_MR_EMP_EN;
 	}
 
-	if (chan->feature & FSL_DMA_CHAN_START_EXT)
+	if (chan->feature & FSL_DMA_CHAN_START_EXT) {
 		mode |= FSL_DMA_MR_EMS_EN;
-	else
+	} else {
+		mode &= ~FSL_DMA_MR_EMS_EN;
 		mode |= FSL_DMA_MR_CS;
+	}
 
 	DMA_OUT(chan, &chan->regs->mr, mode, 32);
 }
@@ -757,14 +757,15 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 
 	switch (cmd) {
 	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&chan->desc_lock, flags);
+
 		/* Halt the DMA engine */
 		dma_halt(chan);
 
-		spin_lock_irqsave(&chan->desc_lock, flags);
-
 		/* Remove and free all of the descriptors in the LD queue */
 		fsldma_free_desc_list(chan, &chan->ld_pending);
 		fsldma_free_desc_list(chan, &chan->ld_running);
+		chan->idle = true;
 
 		spin_unlock_irqrestore(&chan->desc_lock, flags);
 		return 0;
@@ -802,78 +803,45 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 }
 
 /**
- * fsl_dma_update_completed_cookie - Update the completed cookie.
+ * fsl_chan_ld_cleanup - Clean up link descriptors
  * @chan : Freescale DMA channel
  *
- * CONTEXT: hardirq
+ * This function is run after the queue of running descriptors has been
+ * executed by the DMA engine. It will run any callbacks, and then free
+ * the descriptors.
+ *
+ * HARDWARE STATE: idle
  */
-static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan)
+static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 {
-	struct fsl_desc_sw *desc;
+	struct fsl_desc_sw *desc, *_desc;
+	const char *name = chan->name;
 	unsigned long flags;
-	dma_cookie_t cookie;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
+	/* if the ld_running list is empty, there is nothing to do */
 	if (list_empty(&chan->ld_running)) {
-		dev_dbg(chan->dev, "%s: no running descriptors\n", chan->name);
+		dev_dbg(chan->dev, "%s: no descriptors to cleanup\n", name);
 		goto out_unlock;
 	}
 
-	/* Get the last descriptor, update the cookie to that */
+	/*
+	 * Get the last descriptor, update the cookie to it
+	 *
+	 * This is done before callbacks run so that clients can check the
+	 * status of their DMA transfer inside the callback.
+	 */
 	desc = to_fsl_desc(chan->ld_running.prev);
-	if (dma_is_idle(chan))
-		cookie = desc->async_tx.cookie;
-	else {
-		cookie = desc->async_tx.cookie - 1;
-		if (unlikely(cookie < DMA_MIN_COOKIE))
-			cookie = DMA_MAX_COOKIE;
-	}
-
-	chan->completed_cookie = cookie;
-
-out_unlock:
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
-}
-
-/**
- * fsldma_desc_status - Check the status of a descriptor
- * @chan: Freescale DMA channel
- * @desc: DMA SW descriptor
- *
- * This function will return the status of the given descriptor
- */
-static enum dma_status fsldma_desc_status(struct fsldma_chan *chan,
-					  struct fsl_desc_sw *desc)
-{
-	return dma_async_is_complete(desc->async_tx.cookie,
-				     chan->completed_cookie,
-				     chan->common.cookie);
-}
-
-/**
- * fsl_chan_ld_cleanup - Clean up link descriptors
- * @chan : Freescale DMA channel
- *
- * This function clean up the ld_queue of DMA channel.
- */
-static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
-{
-	struct fsl_desc_sw *desc, *_desc;
-	const char *name = chan->name;
-	unsigned long flags;
-
-	spin_lock_irqsave(&chan->desc_lock, flags);
-
-	dev_dbg(chan->dev, "%s: chan completed_cookie = %d\n",
+	chan->completed_cookie = desc->async_tx.cookie;
+	dev_dbg(chan->dev, "%s: completed_cookie = %d\n",
 			   name, chan->completed_cookie);
+
+	/* Run the callback for each descriptor, in order */
 	list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
 		dma_async_tx_callback callback;
 		void *callback_param;
 
-		if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS)
-			break;
-
 		/* Remove from the list of running transactions */
 		list_del(&desc->node);
 
@@ -897,6 +865,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 
+out_unlock:
 	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
@@ -904,10 +873,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
  * fsl_chan_xfer_ld_queue - transfer any pending transactions
  * @chan : Freescale DMA channel
  *
- * This will make sure that any pending transactions will be run.
- * If the DMA controller is idle, it will be started. Otherwise,
- * the DMA controller's interrupt handler will start any pending
- * transactions when it becomes idle.
+ * HARDWARE STATE: idle
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
@@ -927,23 +893,16 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	}
 
 	/*
-	 * The DMA controller is not idle, which means the interrupt
-	 * handler will start any queued transactions when it runs
-	 * at the end of the current transaction
+	 * The DMA controller is not idle, which means that the interrupt
+	 * handler will start any queued transactions when it runs after
+	 * this transaction finishes
 	 */
-	if (!dma_is_idle(chan)) {
+	if (!chan->idle) {
 		dev_dbg(chan->dev, "%s: DMA controller still busy\n", name);
 		goto out_unlock;
 	}
 
 	/*
-	 * TODO:
-	 * make sure the dma_halt() function really un-wedges the
-	 * controller as much as possible
-	 */
-	dma_halt(chan);
-
-	/*
 	 * If there are some link descriptors which have not been
 	 * transferred, we need to start the controller
 	 */
@@ -952,15 +911,32 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * Move all elements from the queue of pending transactions
 	 * onto the list of running transactions
 	 */
+	dev_dbg(chan->dev, "%s: idle, starting controller\n", name);
 	desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node);
 	list_splice_tail_init(&chan->ld_pending, &chan->ld_running);
 
 	/*
+	 * The 85xx DMA controller doesn't clear the channel start bit
+	 * automatically at the end of a transfer. Therefore we must clear
+	 * it in software before starting the transfer.
+	 */
+	if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+		u32 mode;
+
+		mode = DMA_IN(chan, &chan->regs->mr, 32);
+		mode &= ~FSL_DMA_MR_CS;
+		DMA_OUT(chan, &chan->regs->mr, mode, 32);
+	}
+
+	/*
 	 * Program the descriptor's address into the DMA controller,
 	 * then start the DMA transaction
 	 */
 	set_cdar(chan, desc->async_tx.phys);
+	get_cdar(chan);
+
 	dma_start(chan);
+	chan->idle = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&chan->desc_lock, flags);
@@ -985,16 +961,18 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
 					struct dma_tx_state *txstate)
 {
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
-	dma_cookie_t last_used;
 	dma_cookie_t last_complete;
+	dma_cookie_t last_used;
+	unsigned long flags;
 
-	fsl_chan_ld_cleanup(chan);
+	spin_lock_irqsave(&chan->desc_lock, flags);
 
-	last_used = dchan->cookie;
 	last_complete = chan->completed_cookie;
+	last_used = dchan->cookie;
 
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
+	dma_set_tx_state(txstate, last_complete, last_used, 0);
 	return dma_async_is_complete(cookie, last_complete, last_used);
 }
 
@@ -1006,8 +984,6 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 {
 	struct fsldma_chan *chan = data;
 	const char *name = chan->name;
-	int update_cookie = 0;
-	int xfer_ld_q = 0;
 	u32 stat;
 
 	/* save and clear the status register */
@@ -1015,6 +991,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	set_sr(chan, stat);
 	dev_dbg(chan->dev, "%s: irq: stat = 0x%x\n", name, stat);
 
+	/* check that this was really our device */
 	stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
 	if (!stat)
 		return IRQ_NONE;
@@ -1029,29 +1006,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 */
 	if (stat & FSL_DMA_SR_PE) {
 		dev_dbg(chan->dev, "%s: irq: Programming Error INT\n", name);
-		if (get_bcr(chan) == 0) {
-			/* BCR register is 0, this is a DMA_INTERRUPT async_tx.
-			 * Now, update the completed cookie, and continue the
-			 * next uncompleted transfer.
-			 */
-			update_cookie = 1;
-			xfer_ld_q = 1;
-		}
 		stat &= ~FSL_DMA_SR_PE;
-	}
-
-	/*
-	 * If the link descriptor segment transfer finishes,
-	 * we will recycle the used descriptor.
-	 */
-	if (stat & FSL_DMA_SR_EOSI) {
-		dev_dbg(chan->dev, "%s: irq: End-of-segments INT\n", name);
-		dev_dbg(chan->dev, "%s: irq: clndar 0x%llx, nlndar 0x%llx\n",
-			name,
-			(unsigned long long)get_cdar(chan),
-			(unsigned long long)get_ndar(chan));
-		stat &= ~FSL_DMA_SR_EOSI;
-		update_cookie = 1;
+		if (get_bcr(chan) != 0)
+			dev_err(chan->dev, "%s: Programming Error!\n", name);
 	}
 
 	/*
@@ -1061,8 +1018,6 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	if (stat & FSL_DMA_SR_EOCDI) {
 		dev_dbg(chan->dev, "%s: irq: End-of-Chain link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOCDI;
-		update_cookie = 1;
-		xfer_ld_q = 1;
 	}
 
 	/*
@@ -1073,25 +1028,44 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	if (stat & FSL_DMA_SR_EOLNI) {
 		dev_dbg(chan->dev, "%s: irq: End-of-link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOLNI;
-		xfer_ld_q = 1;
 	}
 
-	if (update_cookie)
-		fsl_dma_update_completed_cookie(chan);
-	if (xfer_ld_q)
-		fsl_chan_xfer_ld_queue(chan);
+	/* check that the DMA controller is really idle */
+	if (!dma_is_idle(chan))
+		dev_err(chan->dev, "%s: irq: controller not idle!\n", name);
+
+	/* check that we handled all of the bits */
 	if (stat)
-		dev_dbg(chan->dev, "%s: irq: unhandled sr 0x%02x\n", name, stat);
+		dev_err(chan->dev, "%s: irq: unhandled sr 0x%02x\n", name, stat);
 
-	dev_dbg(chan->dev, "%s: irq: Exit\n", name);
+	/*
+	 * Schedule the tasklet to handle all cleanup of the current
+	 * transaction. It will start a new transaction if there is
+	 * one pending.
+	 */
 	tasklet_schedule(&chan->tasklet);
+	dev_dbg(chan->dev, "%s: irq: Exit\n", name);
 	return IRQ_HANDLED;
 }
 
 static void dma_do_tasklet(unsigned long data)
 {
 	struct fsldma_chan *chan = (struct fsldma_chan *)data;
+	unsigned long flags;
+
+	dev_dbg(chan->dev, "%s: tasklet entry\n", chan->name);
+
+	/* run all callbacks, free all used descriptors */
 	fsl_chan_ld_cleanup(chan);
+
+	/* the channel is now idle */
+	spin_lock_irqsave(&chan->desc_lock, flags);
+	chan->idle = true;
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+	/* start any pending transactions automatically */
+	fsl_chan_xfer_ld_queue(chan);
+	dev_dbg(chan->dev, "%s: tasklet exit\n", chan->name);
 }
 
 static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
@@ -1274,6 +1248,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
 	spin_lock_init(&chan->desc_lock);
 	INIT_LIST_HEAD(&chan->ld_pending);
 	INIT_LIST_HEAD(&chan->ld_running);
+	chan->idle = true;
 
 	chan->common.device = &fdev->common;
 
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 49189da..9cb5aa5 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -148,6 +148,7 @@ struct fsldma_chan {
 	int id;				/* Raw id of this channel */
 	struct tasklet_struct tasklet;
 	u32 feature;
+	bool idle;			/* DMA controller is idle */
 
 	void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable);
 	void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable);
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 5/9] fsldma: minor codingstyle and consistency fixes
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

This fixes some minor violations of the coding style. It also changes
the style of the device_prep_dma_*() function definitions so they are
identical.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   29 +++++++++++++----------------
 drivers/dma/fsldma.h |    4 ++--
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 851993c..06421c0 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -84,7 +84,7 @@ static void set_desc_cnt(struct fsldma_chan *chan,
 }
 
 static void set_desc_src(struct fsldma_chan *chan,
-				struct fsl_dma_ld_hw *hw, dma_addr_t src)
+			 struct fsl_dma_ld_hw *hw, dma_addr_t src)
 {
 	u64 snoop_bits;
 
@@ -94,7 +94,7 @@ static void set_desc_src(struct fsldma_chan *chan,
 }
 
 static void set_desc_dst(struct fsldma_chan *chan,
-				struct fsl_dma_ld_hw *hw, dma_addr_t dst)
+			 struct fsl_dma_ld_hw *hw, dma_addr_t dst)
 {
 	u64 snoop_bits;
 
@@ -104,7 +104,7 @@ static void set_desc_dst(struct fsldma_chan *chan,
 }
 
 static void set_desc_next(struct fsldma_chan *chan,
-				struct fsl_dma_ld_hw *hw, dma_addr_t next)
+			  struct fsl_dma_ld_hw *hw, dma_addr_t next)
 {
 	u64 snoop_bits;
 
@@ -113,8 +113,7 @@ static void set_desc_next(struct fsldma_chan *chan,
 	hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64);
 }
 
-static void set_ld_eol(struct fsldma_chan *chan,
-			struct fsl_desc_sw *desc)
+static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 {
 	u64 snoop_bits;
 
@@ -333,8 +332,7 @@ static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable)
 		chan->feature &= ~FSL_DMA_CHAN_START_EXT;
 }
 
-static void append_ld_queue(struct fsldma_chan *chan,
-			    struct fsl_desc_sw *desc)
+static void append_ld_queue(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 {
 	struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev);
 
@@ -375,8 +373,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
 	cookie = chan->common.cookie;
 	list_for_each_entry(child, &desc->tx_list, node) {
 		cookie++;
-		if (cookie < 0)
-			cookie = 1;
+		if (cookie < DMA_MIN_COOKIE)
+			cookie = DMA_MIN_COOKIE;
 
 		child->async_tx.cookie = cookie;
 	}
@@ -397,8 +395,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
  *
  * Return - The descriptor allocated. NULL for failed.
  */
-static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
-					struct fsldma_chan *chan)
+static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan)
 {
 	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
@@ -423,7 +420,6 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
 	return desc;
 }
 
-
 /**
  * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
  * @chan : Freescale DMA channel
@@ -534,14 +530,15 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
 	/* Insert the link descriptor to the LD ring */
 	list_add_tail(&new->node, &new->tx_list);
 
-	/* Set End-of-link to the last link descriptor of new list*/
+	/* Set End-of-link to the last link descriptor of new list */
 	set_ld_eol(chan, new);
 
 	return &new->async_tx;
 }
 
-static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
-	struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src,
+static struct dma_async_tx_descriptor *
+fsl_dma_prep_memcpy(struct dma_chan *dchan,
+	dma_addr_t dma_dst, dma_addr_t dma_src,
 	size_t len, unsigned long flags)
 {
 	struct fsldma_chan *chan;
@@ -591,7 +588,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 	new->async_tx.flags = flags; /* client is in control of this ack */
 	new->async_tx.cookie = -EBUSY;
 
-	/* Set End-of-link to the last link descriptor of new list*/
+	/* Set End-of-link to the last link descriptor of new list */
 	set_ld_eol(chan, new);
 
 	return &first->async_tx;
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 113e713..49189da 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -102,8 +102,8 @@ struct fsl_desc_sw {
 } __attribute__((aligned(32)));
 
 struct fsldma_chan_regs {
-	u32 mr;	/* 0x00 - Mode Register */
-	u32 sr;	/* 0x04 - Status Register */
+	u32 mr;		/* 0x00 - Mode Register */
+	u32 sr;		/* 0x04 - Status Register */
 	u64 cdar;	/* 0x08 - Current descriptor address register */
 	u64 sar;	/* 0x10 - Source Address Register */
 	u64 dar;	/* 0x18 - Destination Address Register */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 9/9] fsldma: make halt behave nicely on all supported controllers
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

The original dma_halt() function set the CA (channel abort) bit on both
the 83xx and 85xx controllers. This is incorrect on the 83xx, where this
bit means TEM (transfer error mask) instead. The 83xx doesn't support
channel abort, so we only do this operation on 85xx.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   19 ++++++++++++++++---
 1 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 40babc1..eb7bc24 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -216,13 +216,26 @@ static void dma_halt(struct fsldma_chan *chan)
 	u32 mode;
 	int i;
 
+	/* read the mode register */
 	mode = DMA_IN(chan, &chan->regs->mr, 32);
-	mode |= FSL_DMA_MR_CA;
-	DMA_OUT(chan, &chan->regs->mr, mode, 32);
 
-	mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA);
+	/*
+	 * The 85xx controller supports channel abort, which will stop
+	 * the current transfer. On 83xx, this bit is the transfer error
+	 * mask bit, which should not be changed.
+	 */
+	if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+		mode |= FSL_DMA_MR_CA;
+		DMA_OUT(chan, &chan->regs->mr, mode, 32);
+
+		mode &= ~FSL_DMA_MR_CA;
+	}
+
+	/* stop the DMA controller */
+	mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN);
 	DMA_OUT(chan, &chan->regs->mr, mode, 32);
 
+	/* wait for the DMA controller to become idle */
 	for (i = 0; i < 100; i++) {
 		if (dma_is_idle(chan))
 			return;
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 3/9] fsldma: use channel name in printk output
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

This makes debugging the driver much easier when multiple channels are
running concurrently. In addition, you can see how much descriptor
memory each channel has allocated via the dmapool API in sysfs.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   60 +++++++++++++++++++++++++++----------------------
 drivers/dma/fsldma.h |    1 +
 2 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 2e1af45..6e3d3d7 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -37,7 +37,7 @@
 
 #include "fsldma.h"
 
-static const char msg_ld_oom[] = "No free memory for link descriptor\n";
+static const char msg_ld_oom[] = "No free memory for link descriptor";
 
 /*
  * Register Helpers
@@ -207,7 +207,7 @@ static void dma_halt(struct fsldma_chan *chan)
 	}
 
 	if (!dma_is_idle(chan))
-		dev_err(chan->dev, "DMA halt timeout!\n");
+		dev_err(chan->dev, "%s: DMA halt timeout!\n", chan->name);
 }
 
 /**
@@ -400,12 +400,13 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
 static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
 					struct fsldma_chan *chan)
 {
+	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
 	dma_addr_t pdesc;
 
 	desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc);
 	if (!desc) {
-		dev_dbg(chan->dev, "out of memory for link desc\n");
+		dev_dbg(chan->dev, "%s: out of memory for link desc\n", name);
 		return NULL;
 	}
 
@@ -439,13 +440,12 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan)
 	 * We need the descriptor to be aligned to 32bytes
 	 * for meeting FSL DMA specification requirement.
 	 */
-	chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool",
-					  chan->dev,
+	chan->desc_pool = dma_pool_create(chan->name, chan->dev,
 					  sizeof(struct fsl_desc_sw),
 					  __alignof__(struct fsl_desc_sw), 0);
 	if (!chan->desc_pool) {
-		dev_err(chan->dev, "unable to allocate channel %d "
-				   "descriptor pool\n", chan->id);
+		dev_err(chan->dev, "%s: unable to allocate descriptor pool\n",
+				   chan->name);
 		return -ENOMEM;
 	}
 
@@ -491,7 +491,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
 	unsigned long flags;
 
-	dev_dbg(chan->dev, "Free all channel resources.\n");
+	dev_dbg(chan->dev, "%s: Free all channel resources.\n", chan->name);
 	spin_lock_irqsave(&chan->desc_lock, flags);
 	fsldma_free_desc_list(chan, &chan->ld_pending);
 	fsldma_free_desc_list(chan, &chan->ld_running);
@@ -514,7 +514,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
 
 	new = fsl_dma_alloc_descriptor(chan);
 	if (!new) {
-		dev_err(chan->dev, msg_ld_oom);
+		dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 		return NULL;
 	}
 
@@ -551,11 +551,11 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 		/* Allocate the link descriptor from DMA pool */
 		new = fsl_dma_alloc_descriptor(chan);
 		if (!new) {
-			dev_err(chan->dev, msg_ld_oom);
+			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
 #ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
 #endif
 
 		copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
@@ -639,11 +639,11 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
 		/* allocate and populate the descriptor */
 		new = fsl_dma_alloc_descriptor(chan);
 		if (!new) {
-			dev_err(chan->dev, msg_ld_oom);
+			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
 #ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
 #endif
 
 		set_desc_cnt(chan, &new->hw, len);
@@ -815,7 +815,7 @@ static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan)
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
 	if (list_empty(&chan->ld_running)) {
-		dev_dbg(chan->dev, "no running descriptors\n");
+		dev_dbg(chan->dev, "%s: no running descriptors\n", chan->name);
 		goto out_unlock;
 	}
 
@@ -859,11 +859,13 @@ static enum dma_status fsldma_desc_status(struct fsldma_chan *chan,
 static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 {
 	struct fsl_desc_sw *desc, *_desc;
+	const char *name = chan->name;
 	unsigned long flags;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
-	dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie);
+	dev_dbg(chan->dev, "%s: chan completed_cookie = %d\n",
+			   name, chan->completed_cookie);
 	list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
 		dma_async_tx_callback callback;
 		void *callback_param;
@@ -879,7 +881,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 		callback_param = desc->async_tx.callback_param;
 		if (callback) {
 			spin_unlock_irqrestore(&chan->desc_lock, flags);
-			dev_dbg(chan->dev, "LD %p callback\n", desc);
+			dev_dbg(chan->dev, "%s: LD %p callback\n", name, desc);
 			callback(callback_param);
 			spin_lock_irqsave(&chan->desc_lock, flags);
 		}
@@ -903,6 +905,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
+	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
 	unsigned long flags;
 
@@ -913,7 +916,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * don't need to do any work at all
 	 */
 	if (list_empty(&chan->ld_pending)) {
-		dev_dbg(chan->dev, "no pending LDs\n");
+		dev_dbg(chan->dev, "%s: no pending LDs\n", name);
 		goto out_unlock;
 	}
 
@@ -923,7 +926,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * at the end of the current transaction
 	 */
 	if (!dma_is_idle(chan)) {
-		dev_dbg(chan->dev, "DMA controller still busy\n");
+		dev_dbg(chan->dev, "%s: DMA controller still busy\n", name);
 		goto out_unlock;
 	}
 
@@ -996,6 +999,7 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
 static irqreturn_t fsldma_chan_irq(int irq, void *data)
 {
 	struct fsldma_chan *chan = data;
+	const char *name = chan->name;
 	int update_cookie = 0;
 	int xfer_ld_q = 0;
 	u32 stat;
@@ -1003,14 +1007,14 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	/* save and clear the status register */
 	stat = get_sr(chan);
 	set_sr(chan, stat);
-	dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat);
+	dev_dbg(chan->dev, "%s: irq: stat = 0x%x\n", name, stat);
 
 	stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
 	if (!stat)
 		return IRQ_NONE;
 
 	if (stat & FSL_DMA_SR_TE)
-		dev_err(chan->dev, "Transfer Error!\n");
+		dev_err(chan->dev, "%s: Transfer Error!\n", name);
 
 	/*
 	 * Programming Error
@@ -1018,7 +1022,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * triger a PE interrupt.
 	 */
 	if (stat & FSL_DMA_SR_PE) {
-		dev_dbg(chan->dev, "irq: Programming Error INT\n");
+		dev_dbg(chan->dev, "%s: irq: Programming Error INT\n", name);
 		if (get_bcr(chan) == 0) {
 			/* BCR register is 0, this is a DMA_INTERRUPT async_tx.
 			 * Now, update the completed cookie, and continue the
@@ -1035,8 +1039,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * we will recycle the used descriptor.
 	 */
 	if (stat & FSL_DMA_SR_EOSI) {
-		dev_dbg(chan->dev, "irq: End-of-segments INT\n");
-		dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n",
+		dev_dbg(chan->dev, "%s: irq: End-of-segments INT\n", name);
+		dev_dbg(chan->dev, "%s: irq: clndar 0x%llx, nlndar 0x%llx\n",
+			name,
 			(unsigned long long)get_cdar(chan),
 			(unsigned long long)get_ndar(chan));
 		stat &= ~FSL_DMA_SR_EOSI;
@@ -1048,7 +1053,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * and start the next transfer if it exist.
 	 */
 	if (stat & FSL_DMA_SR_EOCDI) {
-		dev_dbg(chan->dev, "irq: End-of-Chain link INT\n");
+		dev_dbg(chan->dev, "%s: irq: End-of-Chain link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOCDI;
 		update_cookie = 1;
 		xfer_ld_q = 1;
@@ -1060,7 +1065,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * prepare next transfer.
 	 */
 	if (stat & FSL_DMA_SR_EOLNI) {
-		dev_dbg(chan->dev, "irq: End-of-link INT\n");
+		dev_dbg(chan->dev, "%s: irq: End-of-link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOLNI;
 		xfer_ld_q = 1;
 	}
@@ -1070,9 +1075,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	if (xfer_ld_q)
 		fsl_chan_xfer_ld_queue(chan);
 	if (stat)
-		dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat);
+		dev_dbg(chan->dev, "%s: irq: unhandled sr 0x%02x\n", name, stat);
 
-	dev_dbg(chan->dev, "irq: Exit\n");
+	dev_dbg(chan->dev, "%s: irq: Exit\n", name);
 	tasklet_schedule(&chan->tasklet);
 	return IRQ_HANDLED;
 }
@@ -1242,6 +1247,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
 
 	fdev->chan[chan->id] = chan;
 	tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan);
+	snprintf(chan->name, sizeof(chan->name), "chan%d", chan->id);
 
 	/* Initialize the channel */
 	dma_init(chan);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index ba9f403..113e713 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -135,6 +135,7 @@ struct fsldma_device {
 #define FSL_DMA_CHAN_START_EXT	0x00002000
 
 struct fsldma_chan {
+	char name[8];			/* Channel name */
 	struct fsldma_chan_regs __iomem *regs;
 	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
 	spinlock_t desc_lock;		/* Descriptor operation lock */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 4/9] fsldma: improve link descriptor debugging
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

This adds better tracking to link descriptor allocations, callbacks, and
frees. This makes it much easier to track errors with link descriptors.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   21 +++++++++++++++------
 1 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 6e3d3d7..851993c 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -416,6 +416,10 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
 	desc->async_tx.tx_submit = fsl_dma_tx_submit;
 	desc->async_tx.phys = pdesc;
 
+#ifdef FSL_DMA_LD_DEBUG
+	dev_dbg(chan->dev, "%s: LD %p allocated\n", chan->name, desc);
+#endif
+
 	return desc;
 }
 
@@ -467,6 +471,9 @@ static void fsldma_free_desc_list(struct fsldma_chan *chan,
 
 	list_for_each_entry_safe(desc, _desc, list, node) {
 		list_del(&desc->node);
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p free\n", chan->name, desc);
+#endif
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 }
@@ -478,6 +485,9 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
 
 	list_for_each_entry_safe_reverse(desc, _desc, list, node) {
 		list_del(&desc->node);
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p free\n", chan->name, desc);
+#endif
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 }
@@ -554,9 +564,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
-#ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
-#endif
 
 		copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
 
@@ -642,9 +649,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
 			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
-#ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
-#endif
 
 		set_desc_cnt(chan, &new->hw, len);
 		set_desc_src(chan, &new->hw, src);
@@ -881,13 +885,18 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 		callback_param = desc->async_tx.callback_param;
 		if (callback) {
 			spin_unlock_irqrestore(&chan->desc_lock, flags);
+#ifdef FSL_DMA_LD_DEBUG
 			dev_dbg(chan->dev, "%s: LD %p callback\n", name, desc);
+#endif
 			callback(callback_param);
 			spin_lock_irqsave(&chan->desc_lock, flags);
 		}
 
 		/* Run any dependencies, then free the descriptor */
 		dma_run_dependencies(&desc->async_tx);
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p free\n", name, desc);
+#endif
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 2/9] fsldma: move related helper functions near each other
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

This is a purely cosmetic cleanup. It is nice to have related functions
right next to each other in the code.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  116 +++++++++++++++++++++++++++----------------------
 1 files changed, 64 insertions(+), 52 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 4de947a..2e1af45 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -39,33 +39,9 @@
 
 static const char msg_ld_oom[] = "No free memory for link descriptor\n";
 
-static void dma_init(struct fsldma_chan *chan)
-{
-	/* Reset the channel */
-	DMA_OUT(chan, &chan->regs->mr, 0, 32);
-
-	switch (chan->feature & FSL_DMA_IP_MASK) {
-	case FSL_DMA_IP_85XX:
-		/* Set the channel to below modes:
-		 * EIE - Error interrupt enable
-		 * EOSIE - End of segments interrupt enable (basic mode)
-		 * EOLNIE - End of links interrupt enable
-		 * BWC - Bandwidth sharing among channels
-		 */
-		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
-				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
-				| FSL_DMA_MR_EOSIE, 32);
-		break;
-	case FSL_DMA_IP_83XX:
-		/* Set the channel to below modes:
-		 * EOTIE - End-of-transfer interrupt enable
-		 * PRC_RM - PCI read multiple
-		 */
-		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
-				| FSL_DMA_MR_PRC_RM, 32);
-		break;
-	}
-}
+/*
+ * Register Helpers
+ */
 
 static void set_sr(struct fsldma_chan *chan, u32 val)
 {
@@ -77,6 +53,30 @@ static u32 get_sr(struct fsldma_chan *chan)
 	return DMA_IN(chan, &chan->regs->sr, 32);
 }
 
+static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
+{
+	DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
+}
+
+static dma_addr_t get_cdar(struct fsldma_chan *chan)
+{
+	return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
+}
+
+static dma_addr_t get_ndar(struct fsldma_chan *chan)
+{
+	return DMA_IN(chan, &chan->regs->ndar, 64);
+}
+
+static u32 get_bcr(struct fsldma_chan *chan)
+{
+	return DMA_IN(chan, &chan->regs->bcr, 32);
+}
+
+/*
+ * Descriptor Helpers
+ */
+
 static void set_desc_cnt(struct fsldma_chan *chan,
 				struct fsl_dma_ld_hw *hw, u32 count)
 {
@@ -113,24 +113,49 @@ static void set_desc_next(struct fsldma_chan *chan,
 	hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64);
 }
 
-static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
+static void set_ld_eol(struct fsldma_chan *chan,
+			struct fsl_desc_sw *desc)
 {
-	DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
-}
+	u64 snoop_bits;
 
-static dma_addr_t get_cdar(struct fsldma_chan *chan)
-{
-	return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
-}
+	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
+		? FSL_DMA_SNEN : 0;
 
-static dma_addr_t get_ndar(struct fsldma_chan *chan)
-{
-	return DMA_IN(chan, &chan->regs->ndar, 64);
+	desc->hw.next_ln_addr = CPU_TO_DMA(chan,
+		DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
+			| snoop_bits, 64);
 }
 
-static u32 get_bcr(struct fsldma_chan *chan)
+/*
+ * DMA Engine Hardware Control Helpers
+ */
+
+static void dma_init(struct fsldma_chan *chan)
 {
-	return DMA_IN(chan, &chan->regs->bcr, 32);
+	/* Reset the channel */
+	DMA_OUT(chan, &chan->regs->mr, 0, 32);
+
+	switch (chan->feature & FSL_DMA_IP_MASK) {
+	case FSL_DMA_IP_85XX:
+		/* Set the channel to below modes:
+		 * EIE - Error interrupt enable
+		 * EOSIE - End of segments interrupt enable (basic mode)
+		 * EOLNIE - End of links interrupt enable
+		 * BWC - Bandwidth sharing among channels
+		 */
+		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
+				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
+				| FSL_DMA_MR_EOSIE, 32);
+		break;
+	case FSL_DMA_IP_83XX:
+		/* Set the channel to below modes:
+		 * EOTIE - End-of-transfer interrupt enable
+		 * PRC_RM - PCI read multiple
+		 */
+		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
+				| FSL_DMA_MR_PRC_RM, 32);
+		break;
+	}
 }
 
 static int dma_is_idle(struct fsldma_chan *chan)
@@ -185,19 +210,6 @@ static void dma_halt(struct fsldma_chan *chan)
 		dev_err(chan->dev, "DMA halt timeout!\n");
 }
 
-static void set_ld_eol(struct fsldma_chan *chan,
-			struct fsl_desc_sw *desc)
-{
-	u64 snoop_bits;
-
-	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
-		? FSL_DMA_SNEN : 0;
-
-	desc->hw.next_ln_addr = CPU_TO_DMA(chan,
-		DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
-			| snoop_bits, 64);
-}
-
 /**
  * fsl_chan_set_src_loop_size - Set source address hold transfer size
  * @chan : Freescale DMA channel
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v2 0/9] fsldma: lockup fixes
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder

Hello everyone,

I've been chasing random infrequent controller lockups in the fsldma driver
for a long time. I finally managed to find the problem and fix it. I'm not
quite sure about the exact sequence of events which causes the race
condition, but it is related to using the hardware registers to track the
controller state. See the patch changelogs for more detail.

The problems were quickly found by turning on DMAPOOL_DEBUG inside
mm/dmapool.c. This poisons memory allocated with the dmapool API.

With dmapool poisoning turned on, the dmatest driver would start producing
failures within a few seconds. After this patchset has been applied, I have
run several iterations of the 10 threads per channel, 100000 iterations per
thread test without any problems. I have also tested it with the CARMA
drivers (posted at linuxppc-dev previously), which make use of the external
control features.

While making the previous changes, I noticed that the fsldma driver does
not respect the automatic DMA unmapping of src and dst buffers. I have
added support for this feature. This also required a fix to dmatest, which
was sending incorrect flags.

The "support async_tx dependencies" patch could be split apart from the
automatic unmapping patch if it is desirable. They both touch the same
piece of code, so I thought it was ok to combine them. Let me know.

I would really like to see this go into 2.6.39. I think we can get it
reviewed before then. :)

Much thanks goes to Felix Radensky for testing on a P2020 (85xx DMA IP core).
I wouldn't have been able to track down the problems on 85xx without his
dilligent testing.

v1 -> v2:
- reordered patches (dmatest change is first now)
- fix problems on 85xx controller
- only set correct bits for 83xx in dma_halt()

Ira W. Snyder (9):
  dmatest: fix automatic buffer unmap type
  fsldma: move related helper functions near each other
  fsldma: use channel name in printk output
  fsldma: improve link descriptor debugging
  fsldma: minor codingstyle and consistency fixes
  fsldma: fix controller lockups
  fsldma: support async_tx dependencies and automatic unmapping
  fsldma: reduce locking during descriptor cleanup
  fsldma: make halt behave nicely on all supported controllers

 drivers/dma/dmatest.c |    7 +-
 drivers/dma/fsldma.c  |  542 +++++++++++++++++++++++++++----------------------
 drivers/dma/fsldma.h  |    6 +-
 3 files changed, 308 insertions(+), 247 deletions(-)

-- 
1.7.3.4

^ permalink raw reply

* [PATCH v2 1/9] dmatest: fix automatic buffer unmap type
From: Ira W. Snyder @ 2011-03-02 22:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1299104601-15447-1-git-send-email-iws@ovro.caltech.edu>

The dmatest code relies on the DMAEngine API to automatically call
dma_unmap_single() on src buffers. The flags it passes are incorrect,
fix them.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/dmatest.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 5589358..7e1b0aa 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -285,7 +285,12 @@ static int dmatest_func(void *data)
 
 	set_user_nice(current, 10);
 
-	flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
+	/*
+	 * src buffers are freed by the DMAEngine code with dma_unmap_single()
+	 * dst buffers are freed by ourselves below
+	 */
+	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT
+	      | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE;
 
 	while (!kthread_should_stop()
 	       && !(iterations && total_tests >= iterations)) {
-- 
1.7.3.4

^ permalink raw reply related

* Re: [PATCH] Fix masking of interrupts for 52xx GPT IRQ.
From: Grant Likely @ 2011-03-02 21:30 UTC (permalink / raw)
  To: Henk Stegeman; +Cc: linuxppc-dev
In-Reply-To: <AANLkTikfKnLG1pBQuWLOcvuu7Za2cB9McyR=Z=h0nBpd@mail.gmail.com>

[fixed top-posted reply]

On Wed, Feb 9, 2011 at 3:16 AM, Henk Stegeman <henk.stegeman@gmail.com> wro=
te:
> On Mon, Feb 7, 2011 at 12:05 AM, Benjamin Herrenschmidt
> <benh@kernel.crashing.org> wrote:
>> On Sat, 2011-01-15 at 02:28 +0100, Henk Stegeman wrote:
>>> When using the GPT as interrupt controller interupts were missing.
>>> It turned out the IrqEn bit of the GPT is not a mask bit, but it also
>>> disables interrupt generation. This modification masks interrupt one
>>> level down the cascade. Note that masking one level down the cascade
>>> is only valid here because the GPT as interrupt ontroller only serves
>>> one IRQ.
>>
>> I'm not too sure here... You shouldn't implemen t both mask/unmask and
>> enable/disable on the same irq_chip and certainly not cal
>> enable_irq/disable_irq from a mask or an unmask callback...
>>
>> Now, I'm not familiar with the HW here, can you tell me more about what
>> exactly is happening, how things are layed out and what you are trying
>> to fix ?
>>
[...]
> Because the old code in the unmask/mask function did enable/disable
> and I didn't want to just drop that code, I provided it via the
> enable/disable function.
> What is wrong by implementing & registering both mask/unmask and
> enable/disable for the same irq_chip?
> If it is wrong it would be nice to let the kernel print a big fat
> warning when this is registered.

After some digging, yes Ben is right.  It doesn't make much sense to
provide an enable/disable function along with the mask/unmask.  I
think you can safely drop the old enable/disable code.  I'm going to
drop this patch from my tree and you can respin and retest.

g.

>
> Cheers,
>
> Henk
>

>>
>>> Signed-off-by: Henk Stegeman <henk.stegeman@gmail.com>
>>> ---
>>> =A0arch/powerpc/platforms/52xx/mpc52xx_gpt.c | =A0 25 +++++++++++++++++=
+++++---
>>> =A01 files changed, 22 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/p=
latforms/52xx/mpc52xx_gpt.c
>>> index 6f8ebe1..9ae2045 100644
>>> --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
>>> +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
>>> @@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv {
>>> =A0 =A0 =A0 struct irq_host *irqhost;
>>> =A0 =A0 =A0 u32 ipb_freq;
>>> =A0 =A0 =A0 u8 wdt_mode;
>>> -
>>> + =A0 =A0 int cascade_virq;
>>> =A0#if defined(CONFIG_GPIOLIB)
>>> =A0 =A0 =A0 struct of_gpio_chip of_gc;
>>> =A0#endif
>>> @@ -136,18 +136,35 @@ DEFINE_MUTEX(mpc52xx_gpt_list_mutex);
>>> =A0static void mpc52xx_gpt_irq_unmask(unsigned int virq)
>>> =A0{
>>> =A0 =A0 =A0 struct mpc52xx_gpt_priv *gpt =3D get_irq_chip_data(virq);
>>> +
>>> + =A0 =A0 enable_irq(gpt->cascade_virq);
>>> +
>>> +}
>>> +
>>> +static void mpc52xx_gpt_irq_mask(unsigned int virq)
>>> +{
>>> + =A0 =A0 struct mpc52xx_gpt_priv *gpt =3D get_irq_chip_data(virq);
>>> +
>>> + =A0 =A0 disable_irq(gpt->cascade_virq);
>>> +}
>>> +
>>> +static void mpc52xx_gpt_irq_enable(unsigned int virq)
>>> +{
>>> + =A0 =A0 struct mpc52xx_gpt_priv *gpt =3D get_irq_chip_data(virq);
>>> =A0 =A0 =A0 unsigned long flags;
>>>
>>> + =A0 =A0 dev_dbg(gpt->dev, "%s %d\n", __func__, virq);
>>> =A0 =A0 =A0 spin_lock_irqsave(&gpt->lock, flags);
>>> =A0 =A0 =A0 setbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_IRQ_EN);
>>> =A0 =A0 =A0 spin_unlock_irqrestore(&gpt->lock, flags);
>>> =A0}
>>>
>>> -static void mpc52xx_gpt_irq_mask(unsigned int virq)
>>> +static void mpc52xx_gpt_irq_disable(unsigned int virq)
>>> =A0{
>>> =A0 =A0 =A0 struct mpc52xx_gpt_priv *gpt =3D get_irq_chip_data(virq);
>>> =A0 =A0 =A0 unsigned long flags;
>>>
>>> + =A0 =A0 dev_dbg(gpt->dev, "%s %d\n", __func__, virq);
>>> =A0 =A0 =A0 spin_lock_irqsave(&gpt->lock, flags);
>>> =A0 =A0 =A0 clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_IRQ_EN);
>>> =A0 =A0 =A0 spin_unlock_irqrestore(&gpt->lock, flags);
>>> @@ -184,6 +201,8 @@ static struct irq_chip mpc52xx_gpt_irq_chip =3D {
>>> =A0 =A0 =A0 .name =3D "MPC52xx GPT",
>>> =A0 =A0 =A0 .unmask =3D mpc52xx_gpt_irq_unmask,
>>> =A0 =A0 =A0 .mask =3D mpc52xx_gpt_irq_mask,
>>> + =A0 =A0 .enable =3D mpc52xx_gpt_irq_enable,
>>> + =A0 =A0 .disable =3D mpc52xx_gpt_irq_disable,
>>> =A0 =A0 =A0 .ack =3D mpc52xx_gpt_irq_ack,
>>> =A0 =A0 =A0 .set_type =3D mpc52xx_gpt_irq_set_type,
>>> =A0};
>>> @@ -268,7 +287,7 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt,=
 struct device_node *node)
>>> =A0 =A0 =A0 if ((mode & MPC52xx_GPT_MODE_MS_MASK) =3D=3D 0)
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&gpt->regs->mode, mode | MPC52xx_G=
PT_MODE_MS_IC);
>>> =A0 =A0 =A0 spin_unlock_irqrestore(&gpt->lock, flags);
>>> -
>>> + =A0 =A0 gpt->cascade_virq =3D cascade_virq;
>>> =A0 =A0 =A0 dev_dbg(gpt->dev, "%s() complete. virq=3D%i\n", __func__, c=
ascade_virq);
>>> =A0}
>>>
>>
>>
>>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [OT - MPC5200B] strange framing, break problems with uart
From: Wolfram Sang @ 2011-03-02 21:08 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: Linux PPC Development, Henk Stegeman
In-Reply-To: <1299097003.1795.0@antares>

[-- Attachment #1: Type: text/plain, Size: 602 bytes --]

> After some discussions with Freescale's and FTDI's support, the reason seems
> to be that the FTDI chips continues to send zero up to 4 chars *after* the
> RTSn line has been deactivated by the '5200B (actually, this is the behaviour
> of many uart's).

Russell described this behaviour nicely here:

http://www.spinics.net/lists/linux-serial/msg02136.html

From that point of view, FTDI is not to blame.

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* about MISC_DEVICES not being enabled in many defconfigs
From: Uwe Kleine-König @ 2011-03-02 20:48 UTC (permalink / raw)
  To: linux-arm-kernel, Hans-Christian Egtvedt, uclinux-dist-devel,
	linux-ia64, linux-mips, linuxppc-dev, linux-sh, Borislav Petkov,
	Mike Frysinger, Andrew Morton
  Cc: kernel

Hello,

while working on an defconfig (arm/mx27) I noticed that just updating
it[1] results in removing CONFIG_EEPROM_AT24=y.  The reason is that
since commit

	v2.6.36-5965-g5f2365d (misc devices: do not enable by default)

MISC_DEVICES isn't enabled anymore by default.  So all defconfigs that
have CONFIG_SOME_SYMBOL=y (or =m) (with SOME_SYMBOL depending on
MISC_DEVICES) but not CONFIG_MISC_DEVICES=y suffer from the same
problem.

As a defconfig that was reduced before 5f2365d obviously didn't have
CONFIG_MISC_DEVICES=y many defconfigs have that problem.

I did the following to (hopefully) find all affected defconfigs:

	$ git describe
	v2.6.38-rc7
	$ git ls-files drivers/misc | grep Kconfig | xargs grep -h ^config | sed 's/config \(.*\)/CONFIG_\1=/' > miscsymbols
	$ git ls-files *defconfig | xargs grep -L CONFIG_MISC_DEVICES= | xargs grep -F -f miscsymbols
	arch/arm/configs/afeb9260_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/afeb9260_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/at572d940hfek_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/arm/configs/at572d940hfek_defconfig:CONFIG_ATMEL_SSC=m
	arch/arm/configs/at572d940hfek_defconfig:CONFIG_SENSORS_TSL2550=m
	arch/arm/configs/at572d940hfek_defconfig:CONFIG_DS1682=m
	arch/arm/configs/at91cap9adk_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/at91rm9200_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/arm/configs/at91rm9200_defconfig:CONFIG_EEPROM_LEGACY=m
	arch/arm/configs/at91sam9260ek_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/at91sam9261ek_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/at91sam9263ek_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/at91sam9g20ek_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/at91sam9rlek_defconfig:CONFIG_ATMEL_SSC=y
	arch/arm/configs/da8xx_omapl_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/davinci_all_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/ep93xx_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/arm/configs/ixp2000_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/arm/configs/ixp23xx_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/arm/configs/ixp4xx_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/arm/configs/mini2440_defconfig:CONFIG_SENSORS_TSL2550=m
	arch/arm/configs/mx27_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/mx3_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/neocore926_defconfig:CONFIG_ATMEL_PWM=y
	arch/arm/configs/neocore926_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/arm/configs/omap2plus_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/arm/configs/pcontrol_g20_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/arm/configs/pcontrol_g20_defconfig:CONFIG_EEPROM_AT24=m
	arch/arm/configs/pnx4008_defconfig:CONFIG_EEPROM_LEGACY=m
	arch/arm/configs/raumfeld_defconfig:CONFIG_ISL29003=y
	arch/arm/configs/raumfeld_defconfig:CONFIG_TI_DAC7512=y
	arch/arm/configs/realview-smp_defconfig:CONFIG_ARM_CHARLCD=y
	arch/arm/configs/realview_defconfig:CONFIG_ARM_CHARLCD=y
	arch/arm/configs/s3c2410_defconfig:CONFIG_EEPROM_AT25=m
	arch/arm/configs/s3c2410_defconfig:CONFIG_EEPROM_LEGACY=m
	arch/arm/configs/s3c2410_defconfig:CONFIG_EEPROM_93CX6=m
	arch/arm/configs/s3c6400_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/s5pc100_defconfig:CONFIG_EEPROM_AT24=y
	arch/arm/configs/versatile_defconfig:CONFIG_EEPROM_LEGACY=m
	arch/arm/configs/zeus_defconfig:CONFIG_EEPROM_AT24=m
	arch/avr32/configs/atngw100_mrmt_defconfig:CONFIG_ATMEL_PWM=y
	arch/avr32/configs/favr-32_defconfig:CONFIG_ATMEL_PWM=m
	arch/avr32/configs/favr-32_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/avr32/configs/favr-32_defconfig:CONFIG_ATMEL_SSC=m
	arch/avr32/configs/hammerhead_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/avr32/configs/merisc_defconfig:CONFIG_ATMEL_PWM=y
	arch/avr32/configs/merisc_defconfig:CONFIG_ATMEL_SSC=y
	arch/avr32/configs/mimc200_defconfig:CONFIG_ATMEL_TCLIB=y
	arch/avr32/configs/mimc200_defconfig:CONFIG_EEPROM_AT24=y
	arch/avr32/configs/mimc200_defconfig:CONFIG_EEPROM_AT25=y
	arch/blackfin/configs/BlackStamp_defconfig:CONFIG_EEPROM_AT25=y
	arch/blackfin/configs/H8606_defconfig:CONFIG_EEPROM_AT25=y
	arch/blackfin/configs/SRV1_defconfig:CONFIG_EEPROM_AT25=m
	arch/ia64/configs/generic_defconfig:CONFIG_SGI_IOC4=y
	arch/ia64/configs/generic_defconfig:CONFIG_SGI_XP=m
	arch/ia64/configs/gensparse_defconfig:CONFIG_SGI_IOC4=y
	arch/mips/configs/bigsur_defconfig:CONFIG_SGI_IOC4=m
	arch/mips/configs/bigsur_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/mips/configs/bigsur_defconfig:CONFIG_EEPROM_MAX6875=y
	arch/mips/configs/gpr_defconfig:CONFIG_TIFM_CORE=m
	arch/mips/configs/ip32_defconfig:CONFIG_SGI_IOC4=y
	arch/mips/configs/markeins_defconfig:CONFIG_SGI_IOC4=m
	arch/mips/configs/pnx8550-jbs_defconfig:CONFIG_SGI_IOC4=m
	arch/mips/configs/rm200_defconfig:CONFIG_SGI_IOC4=m
	arch/mips/configs/sb1250-swarm_defconfig:CONFIG_SGI_IOC4=m
	arch/mips/configs/wrppmc_defconfig:CONFIG_SGI_IOC4=m
	arch/mips/configs/yosemite_defconfig:CONFIG_SGI_IOC4=m
	arch/powerpc/configs/44x/warp_defconfig:CONFIG_EEPROM_AT24=y
	arch/powerpc/configs/52xx/motionpro_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/86xx/gef_ppc9a_defconfig:CONFIG_DS1682=y
	arch/powerpc/configs/86xx/gef_sbc310_defconfig:CONFIG_DS1682=y
	arch/powerpc/configs/86xx/gef_sbc610_defconfig:CONFIG_DS1682=y
	arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/e55xx_smp_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/linkstation_defconfig:CONFIG_EEPROM_LEGACY=m
	arch/powerpc/configs/mpc512x_defconfig:CONFIG_EEPROM_AT24=y
	arch/powerpc/configs/mpc5200_defconfig:CONFIG_EEPROM_AT24=y
	arch/powerpc/configs/mpc85xx_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/mpc85xx_smp_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/mpc86xx_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/pasemi_defconfig:CONFIG_EEPROM_LEGACY=y
	arch/powerpc/configs/ppc6xx_defconfig:CONFIG_ENCLOSURE_SERVICES=m
	arch/powerpc/configs/ppc6xx_defconfig:CONFIG_SENSORS_TSL2550=m
	arch/powerpc/configs/ppc6xx_defconfig:CONFIG_EEPROM_AT24=m
	arch/powerpc/configs/ppc6xx_defconfig:CONFIG_EEPROM_LEGACY=m
	arch/powerpc/configs/ppc6xx_defconfig:CONFIG_EEPROM_MAX6875=m
	arch/powerpc/configs/ppc6xx_defconfig:CONFIG_EEPROM_93CX6=m
	arch/sh/configs/se7206_defconfig:CONFIG_EEPROM_93CX6=y

(For those wondering about the commands above: A line 

	arch/$arch/configs/xyz_defconfig:CONFIG_SOME_DEVICE=y

means here, that running

	make ARCH=$arch xyz_defconfig

results in a config without SOME_DEVICE.

I don't know if that bothers you, but if it does, you should add

	CONFIG_MISC_DEVICES=y

to your defconfig.

Just to let you know ...

Best regards
Uwe

[1] make mx27_defconfig
    make savedefconfig
    mv defconfig arch/arm/configs/mx27_defconfig

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* Re: [OT - MPC5200B] strange framing, break problems with uart
From: Albrecht Dreß @ 2011-03-02 20:16 UTC (permalink / raw)
  To: Henk Stegeman; +Cc: Linux PPC Development
In-Reply-To: <AANLkTi=gqFLtM7f01GFVKdSibxz4q5J9LtHrpOcH_1ta@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2015 bytes --]

Hi Henk:

Am 01.03.11 23:28 schrieb(en) Henk Stegeman:
> Today I noticed corrupted and missing chunks of data on the 5200 with the 2.6.37 uart driver in 2.6.37.
> I don't have these problems when I use the driver from 2.6.33 (with minor changes to make it fit in 2.6.37).

Hmm, I hope it's not related to my my baud rate divisor selection patch... :-/

> While looking for a reason/solution online I came across your problem report. I hope to investigate my problem further soon, but was also wondering if you found a cause/early solution for your problem yet, just in case they could be related.

Well, my problem occurs when the '5200B is connected to a FTDI usb/serial converter (FT2232D) chip, and when both are configured to use rts/cts hw handshake.

After some discussions with Freescale's and FTDI's support, the reason seems to be that the FTDI chips continues to send zero up to 4 chars *after* the RTSn line has been deactivated by the '5200B (actually, this is the behaviour of many uart's).  However, the manual says that the '5200B should report overruns (and not breaks and/or framing errors) in this case.  Although I asked several times, the guy at Freescale did not say a word about this, but just blamed FTDI.  So, at best their manual is plain wrong...  Interestingly, if I switch rts/cts off, I *do* get overrun errors.  Strange!

The solution for me seems to write my own driver - as I know (unlike "usual" serial connections) the packet sizes I expect, I can utilise the PSC's fifo and issue an IRQ when it's almost (FIFO size minus 16 chars seems to be bullet-proof after first tests even at 3 MBaud) full.  In the ISR I /manually/ deactivate RTSn, a tasklet empties the FIFO and asserts RTSn again.  As a positive side effect, it drastically reduces the number of interrupts.  Using Bestcomm would probably be better, but I didn't get it working (still get the cpu irq's, and the task doesn't run).

Not sure if this information is helpful for you...

Cheers,
Albrecht.

[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply

* [PATCH v4 2/2] add icswx support
From: Tseng-Hui (Frank) Lin @ 2011-03-02 17:20 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: tsenglin

Icswx is a PowerPC co-processor instruction to send data to a
co-processor. On Book-S processors the LPAR_ID and process ID (PID) of
the owning process are registered in the window context of the
co-processor at initial time. When the icswx instruction is executed,
the L2 generates a cop-reg transaction on PowerBus. The transaction has
no address and the processor does not perform an MMU access to
authenticate the transaction. The coprocessor compares the LPAR_ID and
the PID included in the transaction and the LPAR_ID and PID held in the
window context to determine if the process is authorized to generate the
transaction.

The OS needs to assign a 16-bit PID for the process. This cop-PID needs
to be updated during context switch. The cop-PID needs to be destroied
when the context is destroied.

Change log from V3:
- Rebase to linux/kernel/git/next/linux-next.git 2011-02-28
- Move the SPRN_PID changes into a separate patch.
- (Unchanged) Not to make icswx a cpu_user_feature as the icswx support
  is to be used by coprocessor drivers only.

arch/powerpc/platforms/Kconfig.cputype:
- Add ICSWX_LAZY_SWITCH

arch/powerpc/include/asm/mmu_context.h:
- Call switch_cop() in switch_mm() only if prev or next uses a coprocessor.

arch/powerpc/include/asm/mmu-hash64.h:
- Add cop_lock to mm_context_t
- Rename HASH64_MAX_PID to COP_PID_MAX and move to mmu_context_hash64.c

arch/powerpc/mm/mmu_context_hash64.c:
- Add a comment block to describe the usage of the icswx support code
- Define COP_PID_NONE, COP_PID_MIN, COP_PID_MAX for id allocation
- Define mtspr_acop() to make lazy switching a config option.
- change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL.
- Remove EXPORT_SYMBOL(switch_cop) as it is only used in switch_mm().
- use_cop(): make id allocation code into new new_cop_pid().
- use_cop/drop_cop(): Use cop_lock to guard acop and cop_pid accesses
  between threads in the same process. Init sop_lock in init_new_context().
- Remove unnecessary cpu_has_feature() check from drop_cop() and switch_cop().
- Call drop_cop() instead of destroy_acop() in destroy_context().
- Remove unused destroy_acop() function.

Change log from v2:
- Make the code a CPU feature and return -NODEV if CPU doesn't have
  icswx co-processor instruction.
- Change the goto loop in use_cop() into a do-while loop.
- Change context destroy code into a new destroy_context_acop() function
  and #define it based on CONFIG_ICSWX.
- Remove mmput() from drop_cop().
- Fix some TAB/space problems.

Change log from V1:
- Change 2'nd parameter of use_cop() from struct task_struct *task
  to struct mm_struct *mm.
- Check for mm == current->active_mm before calling mtspr().
- Add a lock to guard acop related operations.
- Check for POWER7 CPU.
- Move the definition of SPRN_PID from reg_booke.h to avoid
  defining SPRN_PID in two different files.
- Rename pid to acop_pid.
- Change function name disuse_cop() to drop_cop().
- Add a comment to describe the two new fields in mm_context_t.
- Moving CONFIG_ICSWX from arch/powerpc/platforms/pseries/Kconfig
  to arch/powerpc/platforms/Kconfig.cputype.

Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com>
Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>

---
 arch/powerpc/include/asm/cputable.h    |    4 +-
 arch/powerpc/include/asm/mmu-hash64.h  |   13 +++
 arch/powerpc/include/asm/mmu_context.h |   12 ++
 arch/powerpc/include/asm/reg.h         |    1 +
 arch/powerpc/mm/mmu_context_hash64.c   |  177 ++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/Kconfig.cputype |   43 ++++++++
 6 files changed, 249 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index be3cdf9..c56e2df 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -202,6 +202,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTR_STCX_CHECKS_ADDRESS	LONG_ASM_CONST(0x0200000000000000)
 #define CPU_FTR_POPCNTB			LONG_ASM_CONST(0x0400000000000000)
 #define CPU_FTR_POPCNTD			LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_ICSWX			LONG_ASM_CONST(0x1000000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -421,7 +422,8 @@ extern const char *powerpc_base_platform;
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
-	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
+	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+	    CPU_FTR_ICSWX)
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index acac35d..b0c2549 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -409,6 +409,14 @@ static inline void subpage_prot_init_new_context(struct mm_struct *mm) { }
 
 typedef unsigned long mm_context_id_t;
 
+#ifdef CONFIG_ICSWX
+/*
+ * Use forward declearation to avoid including linux/spinlock_types.h
+ * which breaks kernel build.
+ */
+struct spinlock;
+#endif /* CONFIG_ICSWX */
+
 typedef struct {
 	mm_context_id_t id;
 	u16 user_psize;		/* page size index */
@@ -423,6 +431,11 @@ typedef struct {
 #ifdef CONFIG_PPC_SUBPAGE_PROT
 	struct subpage_prot_table spt;
 #endif /* CONFIG_PPC_SUBPAGE_PROT */
+#ifdef CONFIG_ICSWX
+	struct spinlock *cop_lockp; /* guard acop and cop_pid */
+	unsigned long acop;	/* mask of enabled coprocessor types */
+	unsigned int cop_pid;	/* pid value used with coprocessors */
+#endif /* CONFIG_ICSWX */
 } mm_context_t;
 
 
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 81fb412..fe0a09a 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -32,6 +32,12 @@ extern void __destroy_context(unsigned long context_id);
 extern void mmu_context_init(void);
 #endif
 
+#ifdef CONFIG_ICSWX
+extern void switch_cop(struct mm_struct *next);
+extern int use_cop(unsigned long acop, struct mm_struct *mm);
+extern void drop_cop(unsigned long acop, struct mm_struct *mm);
+#endif /* CONFIG_ICSWX */
+
 /*
  * switch_mm is the entry point called from the architecture independent
  * code in kernel/sched.c
@@ -55,6 +61,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	if (prev == next)
 		return;
 
+#ifdef CONFIG_ICSWX
+	/* Switch coprocessor context only if prev or next uses a coprocessor */
+	if (prev->context.acop || next->context.acop)
+		switch_cop(next);
+#endif /* CONFIG_ICSWX */
+
 	/* We must stop all altivec streams before changing the HW
 	 * context
 	 */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 125fc1a..51585eb 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -182,6 +182,7 @@
 
 #define SPRN_CTR	0x009	/* Count Register */
 #define SPRN_DSCR	0x11
+#define SPRN_ACOP	0x1F	/* Available Coprocessor Register */
 #define SPRN_CTRLF	0x088
 #define SPRN_CTRLT	0x098
 #define   CTRL_CT	0xc0000000	/* current thread */
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 2535828..43d66cc 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -18,11 +18,177 @@
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/idr.h>
+#include <linux/percpu.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_ICSWX
+/*
+ * The processor and its L2 cache cause the icswx instruction to
+ * generate a COP_REQ transaction on PowerBus. The transaction has
+ * no address, and the processor does not perform an MMU access
+ * to authenticate the transaction. The command portion of the
+ * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
+ * the coprocessor Process ID (PID), which the coprocessor compares
+ * to the authorized LPID and PID held in the coprocessor, to determine
+ * if the process is authorized to generate the transaction.
+ * The data of the COP_REQ transaction is 128-byte or less and is
+ * placed in cacheable memory on a 128-byte cache line boundary.
+ *
+ * The task to use a coprocessor should use use_cop() to allocate
+ * a coprocessor PID before executing icswx instruction. use_cop()
+ * also enables the coprocessor context switching. Drop_cop() is
+ * used to free the coprocessor PID.
+ *
+ * Example:
+ * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
+ * Each HFI have multiple windows. Each HFI window serves as a
+ * network device sending to and receiving from HFI network.
+ * HFI immediate send function uses icswx instruction. The immediate
+ * send function allows small (single cache-line) packets be sent
+ * without using the regular HFI send FIFO and doorbell, which are
+ * much slower than immediate send.
+ *
+ * For each task intending to use HFI immediate send, the HFI driver
+ * calls use_cop() to obtain a coprocessor PID for the task.
+ * The HFI driver then allocate a free HFI window and save the
+ * coprocessor PID to the HFI window to allow the task to use the
+ * HFI window.
+ *
+ * The HFI driver repeatedly creates immediate send packets and
+ * issues icswx instruction to send data through the HFI window.
+ * The HFI compares the coprocessor PID in the CPU PID register
+ * to the PID held in the HFI window to determine if the transaction
+ * is allowed.
+ *
+ * When the task to release the HFI window, the HFI driver calls
+ * drop_cop() to release the coprocessor PID.
+ */
+
+#ifdef CONFIG_ICSWX_LAZY_SWITCH
+static DEFINE_PER_CPU(unsigned long, acop_reg);
+#define mtspr_acop(val) \
+	if (__get_cpu_var(acop_reg) != val) { \
+		get_cpu_var(acop_reg) = val; \
+		mtspr(SPRN_ACOP, val); \
+		put_cpu_var(acop_reg); \
+	}
+#else
+#define mtspr_acop(val) mtspr(SPRN_ACOP, val)
+#endif /* CONFIG_ICSWX_LAZY_SWITCH */
+
+#define COP_PID_NONE 0
+#define COP_PID_MIN (COP_PID_NONE + 1)
+#define COP_PID_MAX (0xFFFF)
+
+static DEFINE_SPINLOCK(mmu_context_acop_lock);
+static DEFINE_IDA(cop_ida);
+
+void switch_cop(struct mm_struct *next)
+{
+	mtspr(SPRN_PID, next->context.cop_pid);
+	mtspr_acop(next->context.acop);
+}
+
+static int new_cop_pid(struct ida *ida, int min_id, int max_id,
+		       spinlock_t *lock)
+{
+	int index;
+	int err;
+
+again:
+	if (!ida_pre_get(ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(lock);
+	err = ida_get_new_above(ida, min_id, &index);
+	spin_unlock(lock);
+
+	if (err == -EAGAIN)
+		goto again;
+	else if (err)
+		return err;
+
+	if (index > max_id) {
+		spin_lock(lock);
+		ida_remove(ida, index);
+		spin_unlock(lock);
+		return -ENOMEM;
+	}
+
+	return index;
+}
+
+/*
+ * Start using a coprocessor.
+ * @acop: mask of coprocessor to be used.
+ * @mm: The mm the coprocessor to associate with. Most likely current mm.
+ *
+ * Return a positive PID if successful. Negative errno otherwise.
+ * The returned PID will be fed to the coprocessor to determine if an
+ * icswx transaction is authenticated.
+ */
+int use_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int cop_pid;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return -ENODEV;
+
+	if (!mm || !acop)
+		return -EINVAL;
+
+	spin_lock(mm->context.cop_lockp);
+	if (mm->context.cop_pid == COP_PID_NONE) {
+		cop_pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
+				      &mmu_context_acop_lock);
+		if (cop_pid < 0) {
+			spin_unlock(mm->context.cop_lockp);
+			return cop_pid;
+		}
+		mm->context.cop_pid = cop_pid;
+		if (mm == current->active_mm)
+			mtspr(SPRN_PID,  mm->context.cop_pid);
+	}
+	mm->context.acop |= acop;
+	if (mm == current->active_mm)
+		mtspr_acop(mm->context.acop);
+	spin_unlock(mm->context.cop_lockp);
+	return mm->context.cop_pid;
+}
+EXPORT_SYMBOL_GPL(use_cop);
+
+/*
+ * Stop using a coprocessor.
+ * @acop: mask of coprocessor to be stopped.
+ * @mm: The mm the coprocessor associated with.
+ */
+void drop_cop(unsigned long acop, struct mm_struct *mm)
+{
+	if (WARN_ON(!mm))
+		return;
+
+	spin_lock(mm->context.cop_lockp);
+	mm->context.acop &= ~acop;
+	if (mm == current->active_mm)
+		mtspr_acop(mm->context.acop);
+	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
+		spin_lock(&mmu_context_acop_lock);
+		ida_remove(&cop_ida, mm->context.cop_pid);
+		spin_unlock(&mmu_context_acop_lock);
+		mm->context.cop_pid = COP_PID_NONE;
+		if (mm == current->active_mm)
+			mtspr(SPRN_PID, mm->context.cop_pid);
+	}
+	spin_unlock(mm->context.cop_lockp);
+}
+EXPORT_SYMBOL_GPL(drop_cop);
+
+#endif /* CONFIG_ICSWX */
+
 static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDA(mmu_context_ida);
 
@@ -79,6 +245,12 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 		slice_set_user_psize(mm, mmu_virtual_psize);
 	subpage_prot_init_new_context(mm);
 	mm->context.id = index;
+#ifdef CONFIG_ICSWX
+	mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (! mm->context.cop_lockp)
+		return -ENOMEM;
+	spin_lock_init(mm->context.cop_lockp);
+#endif /* CONFIG_ICSWX */
 
 	return 0;
 }
@@ -93,6 +265,11 @@ EXPORT_SYMBOL_GPL(__destroy_context);
 
 void destroy_context(struct mm_struct *mm)
 {
+#ifdef CONFIG_ICSWX
+	drop_cop(mm->context.acop, mm);
+	kfree(mm->context.cop_lockp);
+	mm->context.cop_lockp = NULL;
+#endif /* CONFIG_ICSWX */
 	__destroy_context(mm->context.id);
 	subpage_prot_free(mm);
 	mm->context.id = NO_CONTEXT;
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 111138c..0007b66 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -226,6 +226,49 @@ config VSX
 
 	  If in doubt, say Y here.
 
+config ICSWX
+	bool "Support for PowerPC icswx coprocessor instruction"
+	depends on POWER4
+	default n
+	---help---
+
+	  Enabling this option to turn on the PowerPC Initiate Coprocessor
+	  Store Word (icswx) coprocessor instruction support for POWER7
+	  or newer processors.
+
+	  This option is only useful if you have a processor that supports
+	  icswx coprocessor instruction. It does not have any effect on
+	  processors without icswx coprocessor instruction.
+
+	  This option slightly increases kernel memory usage.
+
+	  Say N if you do not have a PowerPC processor supporting icswx
+	  instruction and a PowerPC coprocessor.
+
+config ICSWX_LAZY_SWITCH
+	bool "Lazy switching coprocessor type registers at context switching"
+	depends on ICSWX
+	default y
+	---help---
+
+	  Coprocessor type register is part of process context. It needs
+	  to be switched at context switching.
+
+	  As most machines have a very small number (most likely <= 1)
+	  of coprocessors, there is a good chance that the value of the
+	  coprocessor type register is the same between many processes.
+	  We do not need to change coprocessor type register at context
+	  switching unless the task to switch to has a different value.
+	
+	  Accessing CPU special purpose registers is far more expensive
+	  than accessing memory. This option uses a per-CPU variable
+	  to track the value of coprocessor type register. The variable
+	  is checked before updating coprocessor type register. The saving
+	  for one access is small but could turn big with the high
+	  frequency of context switching.
+	
+	  Say Y unless you have multiple coprocessors.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply related

* [PATCH v4 1/2] add icswx support
From: Tseng-Hui (Frank) Lin @ 2011-03-02 17:20 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: tsenglin

Move SPRN_PID declearations in various locations into one place.

Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>

---
 arch/powerpc/include/asm/reg.h       |   10 ++++++++++
 arch/powerpc/include/asm/reg_booke.h |    3 ---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 125fc1a..bd0d36e 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -170,6 +170,16 @@
 #define SPEFSCR_FRMC 	0x00000003	/* Embedded FP rounding mode control */
 
 /* Special Purpose Registers (SPRNs)*/
+
+#ifdef CONFIG_40x
+#define SPRN_PID	0x3B1	/* Process ID */
+#else
+#define SPRN_PID	0x030	/* Process ID */
+#ifdef CONFIG_BOOKE
+#define SPRN_PID0	SPRN_PID/* Process ID Register 0 */
+#endif
+#endif
+
 #define SPRN_CTR	0x009	/* Count Register */
 #define SPRN_DSCR	0x11
 #define SPRN_CTRLF	0x088
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index e68c69b..86ad812 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -150,8 +150,6 @@
  * or IBM 40x.
  */
 #ifdef CONFIG_BOOKE
-#define SPRN_PID	0x030	/* Process ID */
-#define SPRN_PID0	SPRN_PID/* Process ID Register 0 */
 #define SPRN_CSRR0	0x03A	/* Critical Save and Restore Register 0 */
 #define SPRN_CSRR1	0x03B	/* Critical Save and Restore Register 1 */
 #define SPRN_DEAR	0x03D	/* Data Error Address Register */
@@ -168,7 +166,6 @@
 #define SPRN_TCR	0x154	/* Timer Control Register */
 #endif /* Book E */
 #ifdef CONFIG_40x
-#define SPRN_PID	0x3B1	/* Process ID */
 #define SPRN_DBCR1	0x3BD	/* Debug Control Register 1 */		
 #define SPRN_ESR	0x3D4	/* Exception Syndrome Register */
 #define SPRN_DEAR	0x3D5	/* Data Error Address Register */

^ permalink raw reply related

* Re: [PATCH 0/8] fsldma: lockup fixes
From: Ira W. Snyder @ 2011-03-02 16:42 UTC (permalink / raw)
  To: Felix Radensky; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <4D6DDA85.8070204@embedded-sol.com>

On Wed, Mar 02, 2011 at 07:49:57AM +0200, Felix Radensky wrote:
> Hi Ira,
> 
> On 03/01/2011 09:52 PM, Ira W. Snyder wrote:
> > On Tue, Mar 01, 2011 at 08:55:15AM -0800, Ira W. Snyder wrote:
> >
> > [ big snip ]
> >
> >
> > I'd still like the bisect if you have a chance. I've re-reviewed the
> > patch series, and found the places that change register writes to the
> > controller.
> >
> > The patch below changes the register operations back to the original
> > order. It doesn't make any sense why this would be required, but it is
> > worth a quick try.
> >
> > I've added an "XXX" mark where you can comment out a single line if this
> > patch fails. It is highly unlikely to make any difference, but I'm
> > really having a hard time understanding what is wrong.
> >
> >
> This patch fixes the problem. See below
> 

Excellent! I know what is happening now. The 85xx controller doesn't
clear the "channel start" bit at the end of a transfer. Sure enough,
buried near the end of the chapter, the datasheet implies this in a
table very far away from the register definitions. The 83xx datasheet
explicitly states that it clears this bit automatically.

I'll post an updated patch series later today. Thank you so much for
being patient and trying out all of these patches.

Ira

^ permalink raw reply

* Re: [PATCH] powerpc/ptrace: remove BUG_ON when full register set not available
From: Michael Wolf @ 2011-03-02 15:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, mikey, anton
In-Reply-To: <1299035316.8833.806.camel@pasglop>

On Wed, 2011-03-02 at 14:08 +1100, Benjamin Herrenschmidt wrote:
> > --- ptracev2.orig/include/linux/regset.h	2011-02-20 12:15:57.000000000 -0600
> > +++ ptracev2/include/linux/regset.h	2011-02-28 13:33:36.685302349 -0600
> > @@ -240,6 +240,34 @@ static inline int user_regset_copyout(un
> >  	}
> >  	return 0;
> >  }
> > +/* want the count to be the registers 14-31 inclusive */
> > +#define POISON_REG_CNT (PT_R31-PT_R14+1)
> > +static inline int user_regset_copyout_poison(unsigned int *pos,
> > +					   unsigned int *count,
> > +					   void **kbuf, void __user **ubuf,
> > +					   const int start_pos,
> > +					   const int end_pos)
> > +{
> 
> I wouldn't put that in a generic location... especially something
> like POISON_REG_CNT is very specific to powerpc and our ABI.

Yeah I put it there thinking about readability but only use it in the
one place.  If we go forward with this current strategy I will remove
the #define and just comment more.

> 
> .../...
> 
> >  static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
> >  				     const void **kbuf,
> > --- ptracev2.orig/arch/powerpc/kernel/ptrace.c	2011-02-20 12:15:57.000000000 -0600
> > +++ ptracev2/arch/powerpc/kernel/ptrace.c	2011-03-01 13:49:12.686354353 -0600
> > @@ -234,11 +234,29 @@ static int gpr_get(struct task_struct *t
> >  	if (target->thread.regs == NULL)
> >  		return -EIO;
> >  
> > -	CHECK_FULL_REGS(target->thread.regs);
> 
> Wouldn't it be a simpler/cleaner approach to use a single function call
> here that checks if the reg set is full and if not, put poison values
> in the thread.regs structure itself ?
> 
> The resulting code would be more palatable...

That was actually the way I had done the first patch while debugging the
problem but Paul Mackerras didn't like that I changed the thread struct.

It is not clear to me which is better.  Reporting a poison value that 
isn't actually there or to change the data.  Hopefully a consensus can
be reached and then I can submit a new patch based on that.

> 
> Cheers,
> Ben.
> 
> > -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> > -				  target->thread.regs,
> > -				  0, offsetof(struct pt_regs, msr));
> > +	if (!FULL_REGS(target->thread.regs)) {
> > +                /* Don't have the full register set. Copy out register r0-r13 */
> > +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> > +					  target->thread.regs,
> > +					  0, sizeof(long)*PT_R14);
> > +
> > +		/* Dont want to change the actual register values so rather than read the */
> > +		/* actual register copy a poison value into the buffer instead		  */
> > +		if (!ret)
> > +			ret = user_regset_copyout_poison(&pos, &count, &kbuf, &ubuf,
> > +						  sizeof(long)*PT_R14, offsetof(struct pt_regs, nip));
> > +
> > +		/* Copy out the rest of the registers as usual */
> > +		if (!ret)
> > +			ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> > +						  target->thread.regs,
> > +						  offsetof(struct pt_regs, nip), offsetof(struct pt_regs, msr));
> > +		
> > +	} else 
> > +		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
> > +					  target->thread.regs,
> > +					  0, offsetof(struct pt_regs, msr));
> >  	if (!ret) {
> >  		unsigned long msr = get_user_msr(target);
> >  		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
> > @@ -645,11 +663,29 @@ static int gpr32_get(struct task_struct 
> >  	if (target->thread.regs == NULL)
> >  		return -EIO;
> >  
> > -	CHECK_FULL_REGS(target->thread.regs);
> > -
> >  	pos /= sizeof(reg);
> >  	count /= sizeof(reg);
> >  
> > +	if(!FULL_REGS(target->thread.regs)) {
> > +		if (kbuf) {
> > +                	/* Don't have the full register set. Copy out register r0-r13 */
> > +			for (; count > 0 && pos < PT_R14; --count)
> > +				*k++ = regs[pos++];
> > +
> > +			/* Dont want to change the actual register values so rather than read the */
> > +			/* actual register copy a poison value into the buffer instead		  */
> > +			for (; count > 0 && pos <= PT_R31; --count,pos++)
> > +				*k++ = 0xdeadbeef;
> > +
> > +		} else { 
> > +			for (; count > 0 && pos < PT_R14; --count)
> > +				if (__put_user((compat_ulong_t) regs[pos++], u++))
> > +					return -EFAULT;
> > +			for (; count > 0 && pos <= PT_R31; --count,pos++)
> > +				if (__put_user((compat_ulong_t) 0xdeadbeef, u++))
> > +					return -EFAULT;
> > +		}
> > +	}
> >  	if (kbuf)
> >  		for (; count > 0 && pos < PT_MSR; --count)
> >  			*k++ = regs[pos++];
> > 
> > 
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/linuxppc-dev
> 
> 

^ permalink raw reply

* Re: [PATCH V2 1/6] powerpc: Move udbg_early_init() after early_init_devtree()
From: Dave Kleikamp @ 2011-03-02 13:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, David Gibson
In-Reply-To: <1299037037.8833.821.camel@pasglop>

On Wed, 2011-03-02 at 14:37 +1100, Benjamin Herrenschmidt wrote:
> On Mon, 2011-02-07 at 19:29 +1100, David Gibson wrote:
> > On Wed, Feb 02, 2011 at 06:00:25PM -0600, Dave Kleikamp wrote:
> > > On Thu, 2011-02-03 at 10:06 +1100, David Gibson wrote:
> > > > On Tue, Feb 01, 2011 at 12:48:41PM -0600, Dave Kleikamp wrote:
> > > > > so that it can use information from the device tree.
> > > > 
> > > > Hrm.  On the other hand this means that the early_init_devtree() code
> > > > can't benefit from hardcoded early debugging.  Since you don't
> > > > actually appear to use devtree information in udbg_early_init() in the
> > > > latest series, I'd suggest dropping this patch.
> > > 
> > > Patch 2 depends on early_init_devtree() being run.  Until then, I don't
> > > know of a way to get at the bootargs.
> > 
> > Ah, yes.  Drat.
> 
> Doesn't matter. _Early_ debug has (or should have) the address in
> the .config file anyways, so it really shouldn't have to care about the
> arguments.
> 
> So I'll drop this patch.
> 
> There are plenty of reasons why we want to be able to use the early
> debug stuff to debug what's happening inside early_init_devtree() :-)

Fair enough.  I wasn't sure this was the right thing to do.  It's either
turn off early debug for AMP, or build separate kernels with a different
address in .config.

Shaggy

^ permalink raw reply

* [PATCH] Remove unused is_iso from fsl_udc_core.c
From: huzaifas @ 2011-03-02  6:23 UTC (permalink / raw)
  To: linux-usb; +Cc: dbrownell, linuxppc-dev, gregkh, Huzaifa Sidhpurwala

From: Huzaifa Sidhpurwala <huzaifas@redhat.com>

is_iso variable is not used anywhere, remove it

Signed-off-by: Huzaifa Sidhpurwala <huzaifas@redhat.com>
---
 drivers/usb/gadget/fsl_udc_core.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 4c55eda..912cb8e 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -766,7 +766,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 	struct fsl_req *req = container_of(_req, struct fsl_req, req);
 	struct fsl_udc *udc;
 	unsigned long flags;
-	int is_iso = 0;
 
 	/* catch various bogus parameters */
 	if (!_req || !req->req.complete || !req->req.buf
@@ -781,7 +780,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
 		if (req->req.length > ep->ep.maxpacket)
 			return -EMSGSIZE;
-		is_iso = 1;
 	}
 
 	udc = ep->udc;
-- 
1.7.3.4

^ permalink raw reply related

* Re: Per process DSCR + somefixes (try#3)
From: Alexey Kardashevskiy @ 2011-03-02  6:15 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1299044868.8833.832.camel@pasglop>

On 02/03/11 16:47, Benjamin Herrenschmidt wrote:
> BTW. I suppose it's an expected behaviour that thread created with a
> given default value will keep that value even when the default is later
> changed right ? And their descendents will use the same default as the
> original thread, not the new default, at least that's how I read your
> code :-) Maybe that should be documented somewhere...
>    

That's right. The idea was to let one set of 
processes-which-do-not-access-dscr-directly to work+fork with one value 
and other set to work+fork with another value. I have no idea who and 
how is going to use it though. Hope the HPC team tells me if something 
is wrong :-)

-- 
Alexey Kardashevskiy
IBM OzLabs, LTC Team

e-mail/sametime: aik@au1.ibm.com
notes: Alexey Kardashevskiy/Australia/IBM

^ permalink raw reply

* Re: [PATCH 0/8] fsldma: lockup fixes
From: Felix Radensky @ 2011-03-02  5:49 UTC (permalink / raw)
  To: Ira W. Snyder; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <20110301195208.GC23403@ovro.caltech.edu>

Hi Ira,

On 03/01/2011 09:52 PM, Ira W. Snyder wrote:
> On Tue, Mar 01, 2011 at 08:55:15AM -0800, Ira W. Snyder wrote:
>
> [ big snip ]
>
>
> I'd still like the bisect if you have a chance. I've re-reviewed the
> patch series, and found the places that change register writes to the
> controller.
>
> The patch below changes the register operations back to the original
> order. It doesn't make any sense why this would be required, but it is
> worth a quick try.
>
> I've added an "XXX" mark where you can comment out a single line if this
> patch fails. It is highly unlikely to make any difference, but I'm
> really having a hard time understanding what is wrong.
>
>
This patch fixes the problem. See below

__dma_request_channel: success (dma0chan0)
dmatest: Started 1 threads using dma0chan0
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372000 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3720c0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372120 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372180 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3721e0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: start=0
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: end=8
of:fsl-elo-dma ffe0c300.dma: chan0: idle, starting controller
of:fsl-elo-dma ffe0c300.dma: chan0: 85xx, running workaround
of:fsl-elo-dma ffe0c300.dma: chan0: dma_halt mode=0x08000140
of:fsl-elo-dma ffe0c300.dma: chan0: irq: stat = 0x8
of:fsl-elo-dma ffe0c300.dma: chan0: irq: End-of-link INT
of:fsl-elo-dma ffe0c300.dma: chan0: irq: Exit
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet entry
of:fsl-elo-dma ffe0c300.dma: chan0: completed_cookie=8
of:fsl-elo-dma ffe0c300.dma: chan0: no pending LDs
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372000 callback
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372000 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3720c0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372120 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372180 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3721e0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 free
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet exit
dma0chan0-copy0: verifying source buffer...
dma0chan0-copy0: verifying dest buffer...
dma0chan0-copy0: #0: No errors with src_off=0x10a8 dst_off=0x1914 
len=0x1dca
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: start=8
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: end=10
of:fsl-elo-dma ffe0c300.dma: chan0: idle, starting controller
of:fsl-elo-dma ffe0c300.dma: chan0: 85xx, running workaround
of:fsl-elo-dma ffe0c300.dma: chan0: dma_halt mode=0x08000141
of:fsl-elo-dma ffe0c300.dma: chan0: irq: stat = 0x8
of:fsl-elo-dma ffe0c300.dma: chan0: irq: End-of-link INT
of:fsl-elo-dma ffe0c300.dma: chan0: irq: Exit
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet entry
of:fsl-elo-dma ffe0c300.dma: chan0: completed_cookie=10
of:fsl-elo-dma ffe0c300.dma: chan0: no pending LDs
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 callback
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 free
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet exit
dma0chan0-copy0: verifying source buffer...
dma0chan0-copy0: verifying dest buffer...
dma0chan0-copy0: #1: No errors with src_off=0xdb8 dst_off=0xc14 len=0x526
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3721e0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372180 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372120 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3720c0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: start=10
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: end=17
of:fsl-elo-dma ffe0c300.dma: chan0: idle, starting controller
of:fsl-elo-dma ffe0c300.dma: chan0: 85xx, running workaround
of:fsl-elo-dma ffe0c300.dma: chan0: dma_halt mode=0x08000141
of:fsl-elo-dma ffe0c300.dma: chan0: irq: stat = 0x8
of:fsl-elo-dma ffe0c300.dma: chan0: irq: End-of-link INT
of:fsl-elo-dma ffe0c300.dma: chan0: irq: Exit
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet entry
of:fsl-elo-dma ffe0c300.dma: chan0: completed_cookie=17
of:fsl-elo-dma ffe0c300.dma: chan0: no pending LDs
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 callback
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3721e0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372180 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372120 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3720c0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 free
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet exit
dma0chan0-copy0: verifying source buffer...
dma0chan0-copy0: verifying dest buffer...
dma0chan0-copy0: #2: No errors with src_off=0xf48 dst_off=0x85d len=0x188f
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3720c0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372120 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372180 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3721e0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372000 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372300 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372360 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3723c0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372420 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372480 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3724e0 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372540 allocated
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: start=17
of:fsl-elo-dma ffe0c300.dma: chan0: assign cookies: end=32
of:fsl-elo-dma ffe0c300.dma: chan0: idle, starting controller
of:fsl-elo-dma ffe0c300.dma: chan0: 85xx, running workaround
of:fsl-elo-dma ffe0c300.dma: chan0: dma_halt mode=0x08000141
of:fsl-elo-dma ffe0c300.dma: chan0: irq: stat = 0x8
of:fsl-elo-dma ffe0c300.dma: chan0: irq: End-of-link INT
of:fsl-elo-dma ffe0c300.dma: chan0: irq: Exit
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet entry
of:fsl-elo-dma ffe0c300.dma: chan0: completed_cookie=32
of:fsl-elo-dma ffe0c300.dma: chan0: no pending LDs
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 callback
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372060 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3720c0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372120 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372180 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3721e0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3722a0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372240 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372000 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372300 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372360 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3723c0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372420 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372480 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef3724e0 free
of:fsl-elo-dma ffe0c300.dma: chan0: LD ef372540 free
of:fsl-elo-dma ffe0c300.dma: chan0: tasklet exit
dma0chan0-copy0: verifying source buffer...
dma0chan0-copy0: verifying dest buffer...
dma0chan0-copy0: #3: No errors with src_off=0x4ff dst_off=0x453 len=0x395d
dma0chan0-copy0: terminating after 4 tests, 0 failures (status 0)

Felix.

^ permalink raw reply

* Re: Per process DSCR + somefixes (try#3)
From: Benjamin Herrenschmidt @ 2011-03-02  5:47 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: linuxppc-dev
In-Reply-To: <4D5B62F2.3020709@au1.ibm.com>

On Wed, 2011-02-16 at 16:38 +1100, Alexey Kardashevskiy wrote:
> step1: http://patchwork.ozlabs.org/patch/71489/
> step2: http://patchwork.ozlabs.org/patch/81423/
> 
> In step2 I defined sysfs node as:
> 
> static SYSDEV_ATTR(dscr_default, 0600, show_dscr_default, 
> store_dscr_default);
> 
> and it caused problems with rhel6.
> Now it is:
> 
> static SYSDEV_CLASS_ATTR(dscr_default, 0600, show_dscr_default, 
> store_dscr_default);
> 
> It works now on both 2.6.32 and 2.6.36 but is that correct?

Ok, please resend with a proper changeset comment, something like that
would do:

<<
The DSCR (aka Data Stream Control Register) is supported on some
server PowerPC chips and allow some control over the prefetch
of data streams.

This patch allows the value to specified per thread by emulating
the corresponding mfspr and mtspr instructions. Children of such
threads inherit the value. Other threads use a default value that
can be specified in sysfs.
>>

And include your Signed-off-by: line.

BTW. I suppose it's an expected behaviour that thread created with a
given default value will keep that value even when the default is later
changed right ? And their descendents will use the same default as the
original thread, not the new default, at least that's how I read your
code :-) Maybe that should be documented somewhere...

Cheers,
Ben.

^ permalink raw reply

* RE: [PATCH][v2] driver/FSL SATA:Fix wrong Device Error Register usage
From: Kushwaha Prabhakar-B32579 @ 2011-03-02  5:22 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: meet2prabhu@gmail.com, Kalra Ashish-B00888,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1299036347.8833.819.camel@pasglop>

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQmVuamFtaW4gSGVycmVu
c2NobWlkdCBbbWFpbHRvOmJlbmhAa2VybmVsLmNyYXNoaW5nLm9yZ10NCj4gU2VudDogV2VkbmVz
ZGF5LCBNYXJjaCAwMiwgMjAxMSA4OjU2IEFNDQo+IFRvOiBLdXNod2FoYSBQcmFiaGFrYXItQjMy
NTc5DQo+IENjOiBsaW51eHBwYy1kZXZAbGlzdHMub3psYWJzLm9yZzsgbWVldDJwcmFiaHVAZ21h
aWwuY29tOyBLYWxyYSBBc2hpc2gtDQo+IEIwMDg4OA0KPiBTdWJqZWN0OiBSZTogW1BBVENIXVt2
Ml0gZHJpdmVyL0ZTTCBTQVRBOkZpeCB3cm9uZyBEZXZpY2UgRXJyb3IgUmVnaXN0ZXINCj4gdXNh
Z2UNCj4gDQo+IE9uIE1vbiwgMjAxMS0wMi0yMSBhdCAxNToyNyArMDUzMCwgUHJhYmhha2FyIEt1
c2h3YWhhIHdyb3RlOg0KPiA+IFdoZW4gYSBzaW5nbGUgZGV2aWNlIGVycm9yIGlzIGRldGVjdGVk
LCB0aGUgZGV2aWNlIHVuZGVyIHRoZSBlcnJvciBpcw0KPiA+IGluZGljYXRlZCBieSB0aGUgZXJy
b3IgYml0IHNldCBpbiB0aGUgREVSLiBUaGVyZSBpcyBhIG9uZSB0byBvbmUNCj4gPiBtYXBwaW5n
IGJldHdlZW4gcmVnaXN0ZXIgYml0IGFuZCBkZXZpY2VzIG9uIFBvcnQgbXVsdGlwbGllcihQTVAp
IGkuZS4NCj4gPiBiaXQgMCByZXByZXNlbnRzIFBNUCBkZXZpY2UgMCBhbmQgYml0IDEgcmVwcmVz
ZW50cyBQTVAgZGV2aWNlIDEgZXRjLg0KPiANCj4gSXQgbWlnaHQgaGVscCB0byBzZW5kIHRob3Nl
IHBhdGNoZXMgdG8gdGhlIGxpbnV4LWlkZSBtYWlsaW5nIGxpc3QgYW5kDQo+IGFwcHJvcHJpYXRl
IGxpYmF0YSBtYWludGFpbmVycyBpbiBhZGRpdGlvbiB0byBDQydpbmcgbGludXhwcGMtZGV2Lg0K
PiANClRoYW5rcyBCZW5qYW1pbiEhDQpJIHdpbGwgdGFrZSBjYXJlIHlvdXIgcG9pbnQgaW4gbmVh
ciBmdXR1cmUuDQoNCi0tUHJhYmhha2FyDQoNCj4gPiBDdXJyZW50IGltcGxlbWVudGF0aW9uIHRy
ZWF0cyBEZXZpY2UgZXJyb3IgcmVnaXN0ZXIgdmFsdWUgYXMgZGV2aWNlDQo+ID4gbnVtYmVyIG5v
dCBzZXQgb2YgYml0cyByZXByZXNlbnRpbmcgbXVsdGlwbGUgZGV2aWNlIG9uIFBNUC4gSXQgaXMN
Cj4gPiBjaGFuZ2VkIHRvIGNvbnNpZGVyIGJpdCBsZXZlbC4NCj4gPiBObyBuZWVkIHRvIGNoZWNr
IGZvciBlYWNoIHNldCBiaXQgYXMgYWxsIGNvbW1hbmQgaXMgZ29pbmcgdG8gYmUNCj4gYWJvcnRl
ZC4NCj4gPg0KPiA+IFNpZ25lZC1vZmYtYnk6IFByYWJoYWthciBLdXNod2FoYSA8cHJhYmhha2Fy
QGZyZWVzY2FsZS5jb20+DQo+ID4gU2lnbmVkLW9mZi1ieTogQXNoaXNoIEthbHJhIDxCMDA4ODhA
ZnJlZXNjYWxlLmNvbT4NCj4gPiAtLS0NCj4gPiAgZ2l0Oi8vZ2l0Lmtlcm5lbC5vcmcvcHViL3Nj
bS9saW51eC9rZXJuZWwvZ2l0L3RvcnZhbGRzL2xpbnV4LTIuNi5naXQNCj4gPiAoYnJhbmNoIG1h
c3RlcikNCj4gPg0KPiA+ICBDaGFuZ2VzIGZvciB2MTogSW5jb3Jwb3JhdGVkIERhdmlkIExhaWdo
dCdzIGNvbW1lbnQNCj4gPiAgCS0gU2luZ2xlIHVzYWdlIG9mIGZmcygpDQo+ID4NCj4gPiAgQ2hh
bmdlcyBmb3IgdjI6IEluY29ycG9yYXRlZCBEYXZpZCBMYWlnaHQncyBjb21tZW50DQo+ID4gIAkt
IENoYW5nZWQgdHlwZSBvZiBkZXZfbnVtIHRvIHVuc2lnbmVkDQo+ID4NCj4gPiAgZHJpdmVycy9h
dGEvc2F0YV9mc2wuYyB8ICAgIDYgKysrKy0tDQo+ID4gIDEgZmlsZXMgY2hhbmdlZCwgNCBpbnNl
cnRpb25zKCspLCAyIGRlbGV0aW9ucygtKQ0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv
YXRhL3NhdGFfZnNsLmMgYi9kcml2ZXJzL2F0YS9zYXRhX2ZzbC5jIGluZGV4DQo+ID4gYjAyMTRk
MC4uODk1NzcxYyAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL2F0YS9zYXRhX2ZzbC5jDQo+ID4g
KysrIGIvZHJpdmVycy9hdGEvc2F0YV9mc2wuYw0KPiA+IEBAIC0xMDQwLDEyICsxMDQwLDE0IEBA
IHN0YXRpYyB2b2lkIHNhdGFfZnNsX2Vycm9yX2ludHIoc3RydWN0DQo+ID4gYXRhX3BvcnQgKmFw
KQ0KPiA+DQo+ID4gIAkJLyogZmluZCBvdXQgdGhlIG9mZmVuZGluZyBsaW5rIGFuZCBxYyAqLw0K
PiA+ICAJCWlmIChhcC0+bnJfcG1wX2xpbmtzKSB7DQo+ID4gKwkJCXVuc2lnbmVkIGludCBkZXZf
bnVtOw0KPiA+ICAJCQlkZXJlZyA9IGlvcmVhZDMyKGhjcl9iYXNlICsgREUpOw0KPiA+ICAJCQlp
b3dyaXRlMzIoZGVyZWcsIGhjcl9iYXNlICsgREUpOw0KPiA+ICAJCQlpb3dyaXRlMzIoY2VyZWcs
IGhjcl9iYXNlICsgQ0UpOw0KPiA+DQo+ID4gLQkJCWlmIChkZXJlZyA8IGFwLT5ucl9wbXBfbGlu
a3MpIHsNCj4gPiAtCQkJCWxpbmsgPSAmYXAtPnBtcF9saW5rW2RlcmVnXTsNCj4gPiArCQkJZGV2
X251bSA9IGZmcyhkZXJlZyktMTsNCj4gPiArCQkJaWYgKGRldl9udW0gPCBhcC0+bnJfcG1wX2xp
bmtzKSB7DQo+ID4gKwkJCQlsaW5rID0gJmFwLT5wbXBfbGlua1tkZXZfbnVtXTsNCj4gPiAgCQkJ
CWVoaSA9ICZsaW5rLT5laF9pbmZvOw0KPiA+ICAJCQkJcWMgPSBhdGFfcWNfZnJvbV90YWcoYXAs
IGxpbmstPmFjdGl2ZV90YWcpOw0KPiA+ICAJCQkJLyoNCj4gDQo+IA0KDQo=

^ permalink raw reply


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