LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: hongbo.zhang @ 2013-07-29 10:49 UTC (permalink / raw)
  To: vinod.koul, djbw, leoli, scottwood, linuxppc-dev
  Cc: Hongbo Zhang, devicetree, linux-kernel
In-Reply-To: <1375094944-3343-1-git-send-email-hongbo.zhang@freescale.com>

From: Hongbo Zhang <hongbo.zhang@freescale.com>

Freescale QorIQ T4 and B4 introduce new 8-channel DMA engines, this patch adds
the device tree nodes for them.

Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
---
 .../devicetree/bindings/powerpc/fsl/dma.txt        |   66 ++++++++++++++++
 arch/powerpc/boot/dts/fsl/b4si-post.dtsi           |    4 +-
 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi          |   81 ++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi          |   81 ++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/t4240si-post.dtsi        |    4 +-
 5 files changed, 232 insertions(+), 4 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi

diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
index 6e9384b..2e66c3d 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
@@ -126,6 +126,72 @@ Example:
 		};
 	};
 
+** Freescale Elo3 DMA Controller
+   This is EloPlus controller with 8 channels, used in Freescale Txxx and Bxxx
+   series chips, such as t1040, t4240, b4860.
+
+Required properties:
+
+- compatible        : must include "fsl,elo3-dma"
+- reg               : <registers mapping for DMA general status reg>
+- ranges            : describes the mapping between the address space of the
+                      DMA channels and the address space of the DMA controller
+
+- DMA channel nodes:
+        - compatible        : must include "fsl,eloplus-dma-channel"
+        - reg               : <registers mapping for channel>
+        - interrupts        : <interrupt mapping for DMA channel IRQ>
+        - interrupt-parent  : optional, if needed for interrupt mapping
+
+Example:
+dma@100300 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "fsl,elo3-dma";
+	reg = <0x100300 0x4 0x100600 0x4>;
+	ranges = <0x0 0x100100 0x500>;
+	dma-channel@0 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x0 0x80>;
+		interrupts = <28 2 0 0>;
+	};
+	dma-channel@80 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x80 0x80>;
+		interrupts = <29 2 0 0>;
+	};
+	dma-channel@100 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x100 0x80>;
+		interrupts = <30 2 0 0>;
+	};
+	dma-channel@180 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x180 0x80>;
+		interrupts = <31 2 0 0>;
+	};
+	dma-channel@300 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x300 0x80>;
+		interrupts = <76 2 0 0>;
+	};
+	dma-channel@380 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x380 0x80>;
+		interrupts = <77 2 0 0>;
+	};
+	dma-channel@400 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x400 0x80>;
+		interrupts = <78 2 0 0>;
+	};
+	dma-channel@480 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x480 0x80>;
+		interrupts = <79 2 0 0>;
+	};
+};
+
 Note on DMA channel compatible properties: The compatible property must say
 "fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
 driver (fsldma).  Any DMA channel used by fsldma cannot be used by another
diff --git a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
index 7399154..ea53ea1 100644
--- a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
@@ -223,13 +223,13 @@
 		reg = <0xe2000 0x1000>;
 	};
 
-/include/ "qoriq-dma-0.dtsi"
+/include/ "elo3-dma-0.dtsi"
 	dma@100300 {
 		fsl,iommu-parent = <&pamu0>;
 		fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
 	};
 
-/include/ "qoriq-dma-1.dtsi"
+/include/ "elo3-dma-1.dtsi"
 	dma@101300 {
 		fsl,iommu-parent = <&pamu0>;
 		fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
diff --git a/arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi b/arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
new file mode 100644
index 0000000..69a3277
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
@@ -0,0 +1,81 @@
+/*
+ * QorIQ DMA device tree stub [ controller @ offset 0x100000 ]
+ *
+ * Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+dma0: dma@100300 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "fsl,elo3-dma";
+	reg = <0x100300 0x4 0x100600 0x4>;
+	ranges = <0x0 0x100100 0x500>;
+	dma-channel@0 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x0 0x80>;
+		interrupts = <28 2 0 0>;
+	};
+	dma-channel@80 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x80 0x80>;
+		interrupts = <29 2 0 0>;
+	};
+	dma-channel@100 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x100 0x80>;
+		interrupts = <30 2 0 0>;
+	};
+	dma-channel@180 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x180 0x80>;
+		interrupts = <31 2 0 0>;
+	};
+	dma-channel@300 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x300 0x80>;
+		interrupts = <76 2 0 0>;
+	};
+	dma-channel@380 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x380 0x80>;
+		interrupts = <77 2 0 0>;
+	};
+	dma-channel@400 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x400 0x80>;
+		interrupts = <78 2 0 0>;
+	};
+	dma-channel@480 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x480 0x80>;
+		interrupts = <79 2 0 0>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi b/arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi
new file mode 100644
index 0000000..d410948
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi
@@ -0,0 +1,81 @@
+/*
+ * QorIQ DMA device tree stub [ controller @ offset 0x101000 ]
+ *
+ * Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+dma1: dma@101300 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "fsl,elo3-dma";
+	reg = <0x101300 0x4 0x101600 0x4>;
+	ranges = <0x0 0x101100 0x500>;
+	dma-channel@0 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x0 0x80>;
+		interrupts = <32 2 0 0>;
+	};
+	dma-channel@80 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x80 0x80>;
+		interrupts = <33 2 0 0>;
+	};
+	dma-channel@100 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x100 0x80>;
+		interrupts = <34 2 0 0>;
+	};
+	dma-channel@180 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x180 0x80>;
+		interrupts = <35 2 0 0>;
+	};
+	dma-channel@300 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x300 0x80>;
+		interrupts = <80 2 0 0>;
+	};
+	dma-channel@380 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x380 0x80>;
+		interrupts = <81 2 0 0>;
+	};
+	dma-channel@400 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x400 0x80>;
+		interrupts = <82 2 0 0>;
+	};
+	dma-channel@480 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x480 0x80>;
+		interrupts = <83 2 0 0>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
index bd611a9..ec95c60 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
@@ -387,8 +387,8 @@
 		reg	   = <0xea000 0x4000>;
 	};
 
-/include/ "qoriq-dma-0.dtsi"
-/include/ "qoriq-dma-1.dtsi"
+/include/ "elo3-dma-0.dtsi"
+/include/ "elo3-dma-1.dtsi"
 
 /include/ "qoriq-espi-0.dtsi"
 	spi@110000 {
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v7 1/3] DMA: Freescale: revise device tree binding document
From: hongbo.zhang @ 2013-07-29 10:49 UTC (permalink / raw)
  To: vinod.koul, djbw, leoli, scottwood, linuxppc-dev
  Cc: Hongbo Zhang, devicetree, linux-kernel
In-Reply-To: <1375094944-3343-1-git-send-email-hongbo.zhang@freescale.com>

From: Hongbo Zhang <hongbo.zhang@freescale.com>

This patch updates the discription of each type of DMA controller and its
channels, it is preparation for adding another new DMA controller binding, it
also fixes some defects of indent for text alignment at the same time.

Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
---
 .../devicetree/bindings/powerpc/fsl/dma.txt        |   48 ++++++++------------
 1 file changed, 20 insertions(+), 28 deletions(-)

diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
index 2a4b4bc..6e9384b 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
@@ -1,33 +1,29 @@
-* Freescale 83xx DMA Controller
+* Freescale DMA Controllers
 
-Freescale PowerPC 83xx have on chip general purpose DMA controllers.
+** Freescale Elo DMA Controller
+   This is a little-endian DMA controller, used in Freescale mpc83xx series
+   chips such as mpc8315, mpc8349, mpc8379 etc.
 
 Required properties:
 
-- compatible        : compatible list, contains 2 entries, first is
-		 "fsl,CHIP-dma", where CHIP is the processor
-		 (mpc8349, mpc8360, etc.) and the second is
-		 "fsl,elo-dma"
+- compatible        : must include "fsl,elo-dma"
 - reg               : <registers mapping for DMA general status reg>
-- ranges		: Should be defined as specified in 1) to describe the
-		  DMA controller channels.
+- ranges            : describes the mapping between the address space of the
+                      DMA channels and the address space of the DMA controller
 - cell-index        : controller index.  0 for controller @ 0x8100
 - interrupts        : <interrupt mapping for DMA IRQ>
 - interrupt-parent  : optional, if needed for interrupt mapping
 
-
 - DMA channel nodes:
-        - compatible        : compatible list, contains 2 entries, first is
-			 "fsl,CHIP-dma-channel", where CHIP is the processor
-			 (mpc8349, mpc8350, etc.) and the second is
-			 "fsl,elo-dma-channel". However, see note below.
+        - compatible        : must include "fsl,elo-dma-channel"
+                              However, see note below.
         - reg               : <registers mapping for channel>
         - cell-index        : dma channel index starts at 0.
 
 Optional properties:
         - interrupts        : <interrupt mapping for DMA channel IRQ>
-			  (on 83xx this is expected to be identical to
-			   the interrupts property of the parent node)
+                              (on 83xx this is expected to be identical to
+                              the interrupts property of the parent node)
         - interrupt-parent  : optional, if needed for interrupt mapping
 
 Example:
@@ -70,27 +66,23 @@ Example:
 		};
 	};
 
-* Freescale 85xx/86xx DMA Controller
-
-Freescale PowerPC 85xx/86xx have on chip general purpose DMA controllers.
+** Freescale EloPlus DMA Controller
+   This is DMA controller with extended addresses and chaining, mainly used in
+   Freescale mpc85xx/86xx, Pxxx and BSC series chips, such as mpc8540, mpc8641
+   p4080, bsc9131 etc.
 
 Required properties:
 
-- compatible        : compatible list, contains 2 entries, first is
-		 "fsl,CHIP-dma", where CHIP is the processor
-		 (mpc8540, mpc8540, etc.) and the second is
-		 "fsl,eloplus-dma"
+- compatible        : must include "fsl,eloplus-dma"
 - reg               : <registers mapping for DMA general status reg>
 - cell-index        : controller index.  0 for controller @ 0x21000,
                                          1 for controller @ 0xc000
-- ranges		: Should be defined as specified in 1) to describe the
-		  DMA controller channels.
+- ranges            : describes the mapping between the address space of the
+                      DMA channels and the address space of the DMA controller
 
 - DMA channel nodes:
-        - compatible        : compatible list, contains 2 entries, first is
-			 "fsl,CHIP-dma-channel", where CHIP is the processor
-			 (mpc8540, mpc8560, etc.) and the second is
-			 "fsl,eloplus-dma-channel". However, see note below.
+        - compatible        : must include "fsl,eloplus-dma-channel"
+                              However, see note below.
         - cell-index        : dma channel index starts at 0.
         - reg               : <registers mapping for channel>
         - interrupts        : <interrupt mapping for DMA channel IRQ>
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v7 3/3] DMA: Freescale: update driver to support 8-channel DMA engine
From: hongbo.zhang @ 2013-07-29 10:49 UTC (permalink / raw)
  To: vinod.koul, djbw, leoli, scottwood, linuxppc-dev
  Cc: Hongbo Zhang, devicetree, linux-kernel
In-Reply-To: <1375094944-3343-1-git-send-email-hongbo.zhang@freescale.com>

From: Hongbo Zhang <hongbo.zhang@freescale.com>

This patch adds support to 8-channel DMA engine, thus the driver works for both
the new 8-channel and the legacy 4-channel DMA engines.

Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
---
 drivers/dma/Kconfig  |    9 +++++----
 drivers/dma/fsldma.c |    9 ++++++---
 drivers/dma/fsldma.h |    2 +-
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6825957..3979c65 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -89,14 +89,15 @@ config AT_HDMAC
 	  Support the Atmel AHB DMA controller.
 
 config FSL_DMA
-	tristate "Freescale Elo and Elo Plus DMA support"
+	tristate "Freescale Elo series DMA support"
 	depends on FSL_SOC
 	select DMA_ENGINE
 	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	---help---
-	  Enable support for the Freescale Elo and Elo Plus DMA controllers.
-	  The Elo is the DMA controller on some 82xx and 83xx parts, and the
-	  Elo Plus is the DMA controller on 85xx and 86xx parts.
+	  Enable support for the Freescale Elo series DMA controllers.
+	  The Elo is the DMA controller on some mpc82xx and mpc83xx parts, the
+	  EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is on
+	  some Txxx and Bxxx parts.
 
 config MPC512X_DMA
 	tristate "Freescale MPC512x built-in DMA engine support"
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 49e8fbd..16a9a48 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1261,7 +1261,9 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
 	WARN_ON(fdev->feature != chan->feature);
 
 	chan->dev = fdev->dev;
-	chan->id = ((res.start - 0x100) & 0xfff) >> 7;
+	chan->id = (res.start & 0xfff) < 0x300 ?
+		   ((res.start - 0x100) & 0xfff) >> 7 :
+		   ((res.start - 0x200) & 0xfff) >> 7;
 	if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
 		dev_err(fdev->dev, "too many channels for device\n");
 		err = -EINVAL;
@@ -1434,6 +1436,7 @@ static int fsldma_of_remove(struct platform_device *op)
 }
 
 static const struct of_device_id fsldma_of_ids[] = {
+	{ .compatible = "fsl,elo3-dma", },
 	{ .compatible = "fsl,eloplus-dma", },
 	{ .compatible = "fsl,elo-dma", },
 	{}
@@ -1455,7 +1458,7 @@ static struct platform_driver fsldma_of_driver = {
 
 static __init int fsldma_init(void)
 {
-	pr_info("Freescale Elo / Elo Plus DMA driver\n");
+	pr_info("Freescale Elo series DMA driver\n");
 	return platform_driver_register(&fsldma_of_driver);
 }
 
@@ -1467,5 +1470,5 @@ static void __exit fsldma_exit(void)
 subsys_initcall(fsldma_init);
 module_exit(fsldma_exit);
 
-MODULE_DESCRIPTION("Freescale Elo / Elo Plus DMA driver");
+MODULE_DESCRIPTION("Freescale Elo series DMA driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index f5c3879..1ffc244 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -112,7 +112,7 @@ struct fsldma_chan_regs {
 };
 
 struct fsldma_chan;
-#define FSL_DMA_MAX_CHANS_PER_DEVICE 4
+#define FSL_DMA_MAX_CHANS_PER_DEVICE 8
 
 struct fsldma_device {
 	void __iomem *regs;	/* DGSR register base */
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH v7 0/3] DMA: Freescale: Add support for 8-channel DMA engine
From: Vinod Koul @ 2013-07-29 10:59 UTC (permalink / raw)
  To: hongbo.zhang; +Cc: devicetree, linux-kernel, djbw, scottwood, linuxppc-dev
In-Reply-To: <1375094944-3343-1-git-send-email-hongbo.zhang@freescale.com>

On Mon, Jul 29, 2013 at 06:49:01PM +0800, hongbo.zhang@freescale.com wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
> 
> Hi Vinod, Dan, Scott and Leo, please have a look at these V7 patches.
The dma relates changes look okay to me.

I need someone to review and ACK the DT bindings.

~Vinod
> 
> Freescale QorIQ T4 and B4 introduce new 8-channel DMA engines, this patch set
> adds support this DMA engine.
> 
> V6->V7 changes:
> - only remove unnecessary "CHIP-dma" explanations in [1/3]
> 
> V5->V6 changes:
> - minor updates of descriptions in binding document and Kconfig
> - remove [4/4], that should be another patch in future
> 
> V4->V5 changes:
> - update description in the dt binding document, to make it more resonable
> - add new patch [4/4] to eliminate a compiling warning which already exists
>   for a long time
> 
> V3->V4 changes:
> - introduce new patch [1/3] to revise the legacy dma binding document
> - and then add new paragraph to describe new dt node binding in [2/3]
> - rebase to latest kernel v3.11-rc1
> 
> V2->V3 changes:
> - edit Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> - edit text string in Kconfig and the driver files, using "elo series" to
>   mention all the current "elo*"
> 
> V1->V2 changes:
> - removed the codes handling the register dgsr1, since it isn't used currently
> - renamed the DMA DT compatible to "fsl,elo3-dma"
> - renamed the new dts files to "elo3-dma-<n>.dtsi"
> 
> Hongbo Zhang (3):
>   DMA: Freescale: revise device tree binding document
>   DMA: Freescale: Add new 8-channel DMA engine device tree nodes
>   DMA: Freescale: update driver to support 8-channel DMA engine
> 
>  .../devicetree/bindings/powerpc/fsl/dma.txt        |  114 +++++++++++++++-----
>  arch/powerpc/boot/dts/fsl/b4si-post.dtsi           |    4 +-
>  arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi          |   81 ++++++++++++++
>  arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi          |   81 ++++++++++++++
>  arch/powerpc/boot/dts/fsl/t4240si-post.dtsi        |    4 +-
>  drivers/dma/Kconfig                                |    9 +-
>  drivers/dma/fsldma.c                               |    9 +-
>  drivers/dma/fsldma.h                               |    2 +-
>  8 files changed, 264 insertions(+), 40 deletions(-)
>  create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
>  create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi
> 
> -- 
> 1.7.9.5
> 
> 
> 

-- 

^ permalink raw reply

* Re: [PATCH 2/3] include: Convert ethernet mac address declarations to use ETH_ALEN
From: Rafael J. Wysocki @ 2013-07-29 11:59 UTC (permalink / raw)
  To: Joe Perches
  Cc: Steve Glendinning, Samuel Ortiz, linux-media, netdev, linux-usb,
	linux-kernel, linux-acpi, Vitaly Bordug, Len Brown, linuxppc-dev,
	David S. Miller, Mauro Carvalho Chehab
In-Reply-To: <a769aba61c43967257854413f16d2b935cc54972.1375075325.git.joe@perches.com>

On Sunday, July 28, 2013 10:29:04 PM Joe Perches wrote:
> It's convenient to have ethernet mac addresses use
> ETH_ALEN to be able to grep for them a bit easier and
> also to ensure that the addresses are __aligned(2).
> 
> Add #include <linux/if_ether.h> as necessary.
> 
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
>  include/acpi/actbl2.h           |  4 ++-
>  include/linux/dm9000.h          |  4 ++-
>  include/linux/fs_enet_pd.h      |  3 ++-
>  include/linux/ieee80211.h       | 59 +++++++++++++++++++++--------------------
>  include/linux/mlx4/device.h     | 11 ++++----
>  include/linux/mlx4/qp.h         |  5 ++--
>  include/linux/mv643xx_eth.h     |  3 ++-
>  include/linux/sh_eth.h          |  3 ++-
>  include/linux/smsc911x.h        |  3 ++-
>  include/linux/uwb/spec.h        |  5 ++--
>  include/media/tveeprom.h        |  4 ++-
>  include/net/irda/irlan_common.h |  3 ++-
>  12 files changed, 61 insertions(+), 46 deletions(-)
> 
> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> index ffaac0e..3f0f11c 100644
> --- a/include/acpi/actbl2.h
> +++ b/include/acpi/actbl2.h
> @@ -44,6 +44,8 @@
>  #ifndef __ACTBL2_H__
>  #define __ACTBL2_H__
>  
> +#include <linux/if_ether.h>
> +
>  /*******************************************************************************
>   *
>   * Additional ACPI Tables (2)
> @@ -605,7 +607,7 @@ struct acpi_ibft_nic {
>  	u8 secondary_dns[16];
>  	u8 dhcp[16];
>  	u16 vlan;
> -	u8 mac_address[6];
> +	u8 mac_address[ETH_ALEN];
>  	u16 pci_address;
>  	u16 name_length;
>  	u16 name_offset;

Please don't touch this file.

It comes from a code base outside of the kernel and should be kept in sync with
the upstream.

Thanks,
Rafael


> diff --git a/include/linux/dm9000.h b/include/linux/dm9000.h
> index 96e8769..841925f 100644
> --- a/include/linux/dm9000.h
> +++ b/include/linux/dm9000.h
> @@ -14,6 +14,8 @@
>  #ifndef __DM9000_PLATFORM_DATA
>  #define __DM9000_PLATFORM_DATA __FILE__
>  
> +#include <linux/if_ether.h>
> +
>  /* IO control flags */
>  
>  #define DM9000_PLATF_8BITONLY	(0x0001)
> @@ -27,7 +29,7 @@
>  
>  struct dm9000_plat_data {
>  	unsigned int	flags;
> -	unsigned char	dev_addr[6];
> +	unsigned char	dev_addr[ETH_ALEN];
>  
>  	/* allow replacement IO routines */
>  
> diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
> index 51b7934..343d82a 100644
> --- a/include/linux/fs_enet_pd.h
> +++ b/include/linux/fs_enet_pd.h
> @@ -18,6 +18,7 @@
>  
>  #include <linux/string.h>
>  #include <linux/of_mdio.h>
> +#include <linux/if_ether.h>
>  #include <asm/types.h>
>  
>  #define FS_ENET_NAME	"fs_enet"
> @@ -135,7 +136,7 @@ struct fs_platform_info {
>  	const struct fs_mii_bus_info *bus_info;
>  
>  	int rx_ring, tx_ring;	/* number of buffers on rx     */
> -	__u8 macaddr[6];	/* mac address                 */
> +	__u8 macaddr[ETH_ALEN];	/* mac address                 */
>  	int rx_copybreak;	/* limit we copy small frames  */
>  	int use_napi;		/* use NAPI                    */
>  	int napi_weight;	/* NAPI weight                 */
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index b0dc87a..4e101af 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -16,6 +16,7 @@
>  #define LINUX_IEEE80211_H
>  
>  #include <linux/types.h>
> +#include <linux/if_ether.h>
>  #include <asm/byteorder.h>
>  
>  /*
> @@ -209,28 +210,28 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
>  struct ieee80211_hdr {
>  	__le16 frame_control;
>  	__le16 duration_id;
> -	u8 addr1[6];
> -	u8 addr2[6];
> -	u8 addr3[6];
> +	u8 addr1[ETH_ALEN];
> +	u8 addr2[ETH_ALEN];
> +	u8 addr3[ETH_ALEN];
>  	__le16 seq_ctrl;
> -	u8 addr4[6];
> +	u8 addr4[ETH_ALEN];
>  } __packed __aligned(2);
>  
>  struct ieee80211_hdr_3addr {
>  	__le16 frame_control;
>  	__le16 duration_id;
> -	u8 addr1[6];
> -	u8 addr2[6];
> -	u8 addr3[6];
> +	u8 addr1[ETH_ALEN];
> +	u8 addr2[ETH_ALEN];
> +	u8 addr3[ETH_ALEN];
>  	__le16 seq_ctrl;
>  } __packed __aligned(2);
>  
>  struct ieee80211_qos_hdr {
>  	__le16 frame_control;
>  	__le16 duration_id;
> -	u8 addr1[6];
> -	u8 addr2[6];
> -	u8 addr3[6];
> +	u8 addr1[ETH_ALEN];
> +	u8 addr2[ETH_ALEN];
> +	u8 addr3[ETH_ALEN];
>  	__le16 seq_ctrl;
>  	__le16 qos_ctrl;
>  } __packed __aligned(2);
> @@ -608,8 +609,8 @@ struct ieee80211s_hdr {
>  	u8 flags;
>  	u8 ttl;
>  	__le32 seqnum;
> -	u8 eaddr1[6];
> -	u8 eaddr2[6];
> +	u8 eaddr1[ETH_ALEN];
> +	u8 eaddr2[ETH_ALEN];
>  } __packed __aligned(2);
>  
>  /* Mesh flags */
> @@ -758,7 +759,7 @@ struct ieee80211_rann_ie {
>  	u8 rann_flags;
>  	u8 rann_hopcount;
>  	u8 rann_ttl;
> -	u8 rann_addr[6];
> +	u8 rann_addr[ETH_ALEN];
>  	__le32 rann_seq;
>  	__le32 rann_interval;
>  	__le32 rann_metric;
> @@ -802,9 +803,9 @@ enum ieee80211_vht_opmode_bits {
>  struct ieee80211_mgmt {
>  	__le16 frame_control;
>  	__le16 duration;
> -	u8 da[6];
> -	u8 sa[6];
> -	u8 bssid[6];
> +	u8 da[ETH_ALEN];
> +	u8 sa[ETH_ALEN];
> +	u8 bssid[ETH_ALEN];
>  	__le16 seq_ctrl;
>  	union {
>  		struct {
> @@ -833,7 +834,7 @@ struct ieee80211_mgmt {
>  		struct {
>  			__le16 capab_info;
>  			__le16 listen_interval;
> -			u8 current_ap[6];
> +			u8 current_ap[ETH_ALEN];
>  			/* followed by SSID and Supported rates */
>  			u8 variable[0];
>  		} __packed reassoc_req;
> @@ -966,21 +967,21 @@ struct ieee80211_vendor_ie {
>  struct ieee80211_rts {
>  	__le16 frame_control;
>  	__le16 duration;
> -	u8 ra[6];
> -	u8 ta[6];
> +	u8 ra[ETH_ALEN];
> +	u8 ta[ETH_ALEN];
>  } __packed __aligned(2);
>  
>  struct ieee80211_cts {
>  	__le16 frame_control;
>  	__le16 duration;
> -	u8 ra[6];
> +	u8 ra[ETH_ALEN];
>  } __packed __aligned(2);
>  
>  struct ieee80211_pspoll {
>  	__le16 frame_control;
>  	__le16 aid;
> -	u8 bssid[6];
> -	u8 ta[6];
> +	u8 bssid[ETH_ALEN];
> +	u8 ta[ETH_ALEN];
>  } __packed __aligned(2);
>  
>  /* TDLS */
> @@ -989,14 +990,14 @@ struct ieee80211_pspoll {
>  struct ieee80211_tdls_lnkie {
>  	u8 ie_type; /* Link Identifier IE */
>  	u8 ie_len;
> -	u8 bssid[6];
> -	u8 init_sta[6];
> -	u8 resp_sta[6];
> +	u8 bssid[ETH_ALEN];
> +	u8 init_sta[ETH_ALEN];
> +	u8 resp_sta[ETH_ALEN];
>  } __packed;
>  
>  struct ieee80211_tdls_data {
> -	u8 da[6];
> -	u8 sa[6];
> +	u8 da[ETH_ALEN];
> +	u8 sa[ETH_ALEN];
>  	__be16 ether_type;
>  	u8 payload_type;
>  	u8 category;
> @@ -1090,8 +1091,8 @@ struct ieee80211_p2p_noa_attr {
>  struct ieee80211_bar {
>  	__le16 frame_control;
>  	__le16 duration;
> -	__u8 ra[6];
> -	__u8 ta[6];
> +	__u8 ra[ETH_ALEN];
> +	__u8 ta[ETH_ALEN];
>  	__le16 control;
>  	__le16 start_seq_num;
>  } __packed;
> diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
> index 52c23a8..e37ac2b 100644
> --- a/include/linux/mlx4/device.h
> +++ b/include/linux/mlx4/device.h
> @@ -33,6 +33,7 @@
>  #ifndef MLX4_DEVICE_H
>  #define MLX4_DEVICE_H
>  
> +#include <linux/if_ether.h>
>  #include <linux/pci.h>
>  #include <linux/completion.h>
>  #include <linux/radix-tree.h>
> @@ -619,7 +620,7 @@ struct mlx4_eth_av {
>  	u8		dgid[16];
>  	u32		reserved4[2];
>  	__be16		vlan;
> -	u8		mac[6];
> +	u8		mac[ETH_ALEN];
>  };
>  
>  union mlx4_ext_av {
> @@ -913,10 +914,10 @@ enum mlx4_net_trans_promisc_mode {
>  };
>  
>  struct mlx4_spec_eth {
> -	u8	dst_mac[6];
> -	u8	dst_mac_msk[6];
> -	u8	src_mac[6];
> -	u8	src_mac_msk[6];
> +	u8	dst_mac[ETH_ALEN];
> +	u8	dst_mac_msk[ETH_ALEN];
> +	u8	src_mac[ETH_ALEN];
> +	u8	src_mac_msk[ETH_ALEN];
>  	u8	ether_type_enable;
>  	__be16	ether_type;
>  	__be16	vlan_id_msk;
> diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
> index 262deac..6d35147 100644
> --- a/include/linux/mlx4/qp.h
> +++ b/include/linux/mlx4/qp.h
> @@ -34,6 +34,7 @@
>  #define MLX4_QP_H
>  
>  #include <linux/types.h>
> +#include <linux/if_ether.h>
>  
>  #include <linux/mlx4/device.h>
>  
> @@ -143,7 +144,7 @@ struct mlx4_qp_path {
>  	u8			feup;
>  	u8			fvl_rx;
>  	u8			reserved4[2];
> -	u8			dmac[6];
> +	u8			dmac[ETH_ALEN];
>  };
>  
>  enum { /* fl */
> @@ -318,7 +319,7 @@ struct mlx4_wqe_datagram_seg {
>  	__be32			dqpn;
>  	__be32			qkey;
>  	__be16			vlan;
> -	u8			mac[6];
> +	u8			mac[ETH_ALEN];
>  };
>  
>  struct mlx4_wqe_lso_seg {
> diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h
> index 6e8215b..61a0da3 100644
> --- a/include/linux/mv643xx_eth.h
> +++ b/include/linux/mv643xx_eth.h
> @@ -6,6 +6,7 @@
>  #define __LINUX_MV643XX_ETH_H
>  
>  #include <linux/mbus.h>
> +#include <linux/if_ether.h>
>  
>  #define MV643XX_ETH_SHARED_NAME		"mv643xx_eth"
>  #define MV643XX_ETH_NAME		"mv643xx_eth_port"
> @@ -48,7 +49,7 @@ struct mv643xx_eth_platform_data {
>  	 * Use this MAC address if it is valid, overriding the
>  	 * address that is already in the hardware.
>  	 */
> -	u8			mac_addr[6];
> +	u8			mac_addr[ETH_ALEN];
>  
>  	/*
>  	 * If speed is 0, autonegotiation is enabled.
> diff --git a/include/linux/sh_eth.h b/include/linux/sh_eth.h
> index fc30571..6205eeb 100644
> --- a/include/linux/sh_eth.h
> +++ b/include/linux/sh_eth.h
> @@ -2,6 +2,7 @@
>  #define __ASM_SH_ETH_H__
>  
>  #include <linux/phy.h>
> +#include <linux/if_ether.h>
>  
>  enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN};
>  enum {
> @@ -18,7 +19,7 @@ struct sh_eth_plat_data {
>  	phy_interface_t phy_interface;
>  	void (*set_mdio_gate)(void *addr);
>  
> -	unsigned char mac_addr[6];
> +	unsigned char mac_addr[ETH_ALEN];
>  	unsigned no_ether_link:1;
>  	unsigned ether_link_active_low:1;
>  	unsigned needs_init:1;
> diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h
> index 4dde70e..eec3efd 100644
> --- a/include/linux/smsc911x.h
> +++ b/include/linux/smsc911x.h
> @@ -22,6 +22,7 @@
>  #define __LINUX_SMSC911X_H__
>  
>  #include <linux/phy.h>
> +#include <linux/if_ether.h>
>  
>  /* platform_device configuration data, should be assigned to
>   * the platform_device's dev.platform_data */
> @@ -31,7 +32,7 @@ struct smsc911x_platform_config {
>  	unsigned int flags;
>  	unsigned int shift;
>  	phy_interface_t phy_interface;
> -	unsigned char mac[6];
> +	unsigned char mac[ETH_ALEN];
>  };
>  
>  /* Constants for platform_device irq polarity configuration */
> diff --git a/include/linux/uwb/spec.h b/include/linux/uwb/spec.h
> index b52e44f..0df24bf 100644
> --- a/include/linux/uwb/spec.h
> +++ b/include/linux/uwb/spec.h
> @@ -32,6 +32,7 @@
>  
>  #include <linux/types.h>
>  #include <linux/bitmap.h>
> +#include <linux/if_ether.h>
>  
>  #define i1480_FW 0x00000303
>  /* #define i1480_FW 0x00000302 */
> @@ -130,7 +131,7 @@ enum { UWB_DRP_BACKOFF_WIN_MAX = 16 };
>   * it is also used to define headers sent down and up the wire/radio).
>   */
>  struct uwb_mac_addr {
> -	u8 data[6];
> +	u8 data[ETH_ALEN];
>  } __attribute__((packed));
>  
>  
> @@ -568,7 +569,7 @@ struct uwb_rc_evt_confirm {
>  /* Device Address Management event. [WHCI] section 3.1.3.2. */
>  struct uwb_rc_evt_dev_addr_mgmt {
>  	struct uwb_rceb rceb;
> -	u8 baAddr[6];
> +	u8 baAddr[ETH_ALEN];
>  	u8 bResultCode;
>  } __attribute__((packed));
>  
> diff --git a/include/media/tveeprom.h b/include/media/tveeprom.h
> index 4a1191a..f7119ee 100644
> --- a/include/media/tveeprom.h
> +++ b/include/media/tveeprom.h
> @@ -12,6 +12,8 @@ enum tveeprom_audio_processor {
>  	TVEEPROM_AUDPROC_OTHER,
>  };
>  
> +#include <linux/if_ether.h>
> +
>  struct tveeprom {
>  	u32 has_radio;
>  	/* If has_ir == 0, then it is unknown what the IR capabilities are,
> @@ -40,7 +42,7 @@ struct tveeprom {
>  	u32 revision;
>  	u32 serial_number;
>  	char rev_str[5];
> -	u8 MAC_address[6];
> +	u8 MAC_address[ETH_ALEN];
>  };
>  
>  void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
> diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
> index 0af8b8d..550c2d6 100644
> --- a/include/net/irda/irlan_common.h
> +++ b/include/net/irda/irlan_common.h
> @@ -32,6 +32,7 @@
>  #include <linux/types.h>
>  #include <linux/skbuff.h>
>  #include <linux/netdevice.h>
> +#include <linux/if_ether.h>
>  
>  #include <net/irda/irttp.h>
>  
> @@ -161,7 +162,7 @@ struct irlan_provider_cb {
>  	int access_type;     /* Access type */
>  	__u16 send_arb_val;
>  
> -	__u8 mac_address[6]; /* Generated MAC address for peer device */
> +	__u8 mac_address[ETH_ALEN]; /* Generated MAC address for peer device */
>  };
>  
>  /*
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* RE: [PATCH 3/3 v18] iommu/fsl: Freescale PAMU driver and iommu implementation.
From: Sethi Varun-B16395 @ 2013-07-29 12:14 UTC (permalink / raw)
  To: Sethi Varun-B16395, joro@8bytes.org,
	iommu@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org,
	linux-kernel@vger.kernel.org, benh@kernel.crashing.org,
	galak@kernel.crashing.org, alex.williamson@redhat.com,
	Yoder Stuart-B08248, Wood Scott-B07421
  Cc: Timur Tabi
In-Reply-To: <1373863857-27239-3-git-send-email-Varun.Sethi@freescale.com>

Hi Joerg,
Do you have any further comments on this patch set?

Regards
Varun

> -----Original Message-----
> From: Sethi Varun-B16395
> Sent: Monday, July 15, 2013 10:21 AM
> To: joro@8bytes.org; iommu@lists.linux-foundation.org; linuxppc-
> dev@lists.ozlabs.org; linux-kernel@vger.kernel.org;
> benh@kernel.crashing.org; galak@kernel.crashing.org;
> alex.williamson@redhat.com; Yoder Stuart-B08248; Wood Scott-B07421
> Cc: Sethi Varun-B16395; Timur Tabi
> Subject: [PATCH 3/3 v18] iommu/fsl: Freescale PAMU driver and iommu
> implementation.
>=20
> Following is a brief description of the PAMU hardware:
> PAMU determines what action to take and whether to authorize the action
> on
> the basis of the memory address, a Logical IO Device Number (LIODN), and
> PAACT table (logically) indexed by LIODN and address. Hardware devices
> which
> need to access memory must provide an LIODN in addition to the memory
> address.
>=20
> Peripheral Access Authorization and Control Tables (PAACTs) are the
> primary
> data structures used by PAMU. A PAACT is a table of peripheral access
> authorization and control entries (PAACE).Each PAACE defines the range of
> I/O bus address space that is accessible by the LIOD and the associated
> access
> capabilities.
>=20
> There are two types of PAACTs: primary PAACT (PPAACT) and secondary PAACT
> (SPAACT).A given physical I/O device may be able to act as one or more
> independent logical I/O devices (LIODs). Each such logical I/O device is
> assigned an identifier called logical I/O device number (LIODN). A LIODN
> is
> allocated a contiguous portion of the I/O bus address space called the
> DSA window
> for performing DSA operations. The DSA window may optionally be divided
> into
> multiple sub-windows, each of which may be used to map to a region in
> system
> storage space. The first sub-window is referred to as the primary sub-
> window
> and the remaining are called secondary sub-windows.
>=20
> This patch provides the PAMU driver (fsl_pamu.c) and the corresponding
> IOMMU
> API implementation (fsl_pamu_domain.c). The PAMU hardware driver
> (fsl_pamu.c)
> has been derived from the work done by Ashish Kalra and Timur Tabi.
>=20
> [For iommu group support]
> Acked-by: Alex Williamson <alex.williamson@redhat.com>
>=20
> Signed-off-by: Timur Tabi <timur@tabi.org>
> Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
>=20
> ---
> changes in v19:
> - rebased to 3.11-rc1
> changes in v18:
> - Merged the two loops for searching shared iommu_group
> in to a single loop.
> - Renamed function used for searching shared iommu groups.
> changes in v17
> - Fixed iommu group check for peer/parent bus devices.
> - Check for ACS till root node while allocating device
> groups.
> - Fix the reference to pdev instead of dma_dev.
> changes in v16
> - rebased to kernel 3.10-rc6
> changes in v15:
> - Updated path for fsl_pamu_stash.h.
> changes in v14:
> - Use updated PAMU specific attributes.
> changes in v13:
> - Use the new header drivers/iommu/pci.h
> - fix geometry configured check.
> changes in v12:
> - Use is_power_of_2 for checking alignement.
> - Check for multifucntion PCI device ACS flags for determining device
> groups.
> - Fix get_stash_id function.
> - Don't crash in case of access violations, disable the LIODN.
> - Don't use list_empty while traversing list using list for each entry.
> - Move stash structure and ids to PAMU header files.
> - Fix geometry size calculation.
> changes in v11:
> - changed iova to dma_addr_t in iova_to_phys API.
> changes in v10:
> - Support for new guts compatibe string for T4 & B4 devices.
> - Modified comment about port ID and mentioned the errata number.
> - Fixed the issue where data pointer was not freed in case of a an error.
> - Pass data pointer while freeing irq.
> - Whle initializing the SPAACE entry clear the valid bit.
> changes in v9:
> - Merged and createad a single function to delete
> a device from domain list.
> - Refactored the add_device API code.
> - Renamed the paace and spaace init fucntions.
> - Renamed functions for mapping windows and subwindows.
> - Changed the MAX LIODN value to MAX value u-boot can
> program.
> - Hard coded maximum number of subwindows.
> changes in v8:
> - implemented the new API for window based IOMMUs.
> changes in v7:
> - Set max_subwidows in the geometry attribute.
> - Add checking for maximum supported LIODN value.
> - Use upper_32_bits and lower_32_bits macros while
>   intializing PAMU data structures.
> changes in v6:
> - Simplified complex conditional statements.
> - Fixed indentation issues.
> - Added comments for IOMMU API implementation.
> changes in v5:
> - Addressed comments from Timur.
> changes in v4:
> - Addressed comments from Timur and Scott.
> changes in v3:
> - Addressed comments by Kumar Gala
> - dynamic fspi allocation
> - fixed alignment check in map and unmap
>  arch/powerpc/sysdev/fsl_pci.h   |    5 +
>  drivers/iommu/Kconfig           |   10 +
>  drivers/iommu/Makefile          |    1 +
>  drivers/iommu/fsl_pamu.c        | 1309
> +++++++++++++++++++++++++++++++++++++++
>  drivers/iommu/fsl_pamu.h        |  410 ++++++++++++
>  drivers/iommu/fsl_pamu_domain.c | 1172
> +++++++++++++++++++++++++++++++++++
>  drivers/iommu/fsl_pamu_domain.h |   85 +++
>  7 files changed, 2992 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/iommu/fsl_pamu.c
>  create mode 100644 drivers/iommu/fsl_pamu.h
>  create mode 100644 drivers/iommu/fsl_pamu_domain.c
>  create mode 100644 drivers/iommu/fsl_pamu_domain.h
>=20
> diff --git a/arch/powerpc/sysdev/fsl_pci.h
> b/arch/powerpc/sysdev/fsl_pci.h
> index 72b5625..1e01291 100644
> --- a/arch/powerpc/sysdev/fsl_pci.h
> +++ b/arch/powerpc/sysdev/fsl_pci.h
> @@ -16,6 +16,11 @@
>=20
>  struct platform_device;
>=20
> +
> +/* FSL PCI controller BRR1 register */
> +#define PCI_FSL_BRR1      0xbf8
> +#define PCI_FSL_BRR1_VER 0xffff
> +
>  #define PCIE_LTSSM	0x0404		/* PCIE Link Training and
> Status */
>  #define PCIE_LTSSM_L0	0x16		/* L0 state */
>  #define PCIE_IP_REV_2_2		0x02080202 /* PCIE IP block version
> Rev2.2 */
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 820d85c..fe302e3 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -17,6 +17,16 @@ config OF_IOMMU
>         def_bool y
>         depends on OF
>=20
> +config FSL_PAMU
> +	bool "Freescale IOMMU support"
> +	depends on PPC_E500MC
> +	select IOMMU_API
> +	select GENERIC_ALLOCATOR
> +	help
> +	  Freescale PAMU support. PAMU is the IOMMU present on Freescale
> QorIQ platforms.
> +	  PAMU can authorize memory access, remap the memory address, and
> remap I/O
> +	  transaction types.
> +
>  # MSM IOMMU support
>  config MSM_IOMMU
>  	bool "MSM IOMMU Support"
> diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
> index bbe7041..14c1f47 100644
> --- a/drivers/iommu/Makefile
> +++ b/drivers/iommu/Makefile
> @@ -16,3 +16,4 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) +=3D tegra-smmu.o
>  obj-$(CONFIG_EXYNOS_IOMMU) +=3D exynos-iommu.o
>  obj-$(CONFIG_SHMOBILE_IOMMU) +=3D shmobile-iommu.o
>  obj-$(CONFIG_SHMOBILE_IPMMU) +=3D shmobile-ipmmu.o
> +obj-$(CONFIG_FSL_PAMU) +=3D fsl_pamu.o fsl_pamu_domain.o
> diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
> new file mode 100644
> index 0000000..a831fee
> --- /dev/null
> +++ b/drivers/iommu/fsl_pamu.c
> @@ -0,0 +1,1309 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License, version 2, as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
> USA.
> + *
> + * Copyright (C) 2013 Freescale Semiconductor, Inc.
> + *
> + */
> +
> +#define pr_fmt(fmt)    "fsl-pamu: %s: " fmt, __func__
> +
> +#include <linux/init.h>
> +#include <linux/iommu.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/of_platform.h>
> +#include <linux/bootmem.h>
> +#include <linux/genalloc.h>
> +#include <asm/io.h>
> +#include <asm/bitops.h>
> +#include <asm/fsl_guts.h>
> +
> +#include "fsl_pamu.h"
> +
> +/* define indexes for each operation mapping scenario */
> +#define OMI_QMAN        0x00
> +#define OMI_FMAN        0x01
> +#define OMI_QMAN_PRIV   0x02
> +#define OMI_CAAM        0x03
> +
> +#define make64(high, low) (((u64)(high) << 32) | (low))
> +
> +struct pamu_isr_data {
> +	void __iomem *pamu_reg_base;	/* Base address of PAMU regs*/
> +	unsigned int count;		/* The number of PAMUs */
> +};
> +
> +static struct paace *ppaact;
> +static struct paace *spaact;
> +static struct ome *omt;
> +
> +/*
> + * Table for matching compatible strings, for device tree
> + * guts node, for QorIQ SOCs.
> + * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4
> + * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0"
> + * string would be used.
> +*/
> +static const struct of_device_id guts_device_ids[] =3D {
> +	{ .compatible =3D "fsl,qoriq-device-config-1.0", },
> +	{ .compatible =3D "fsl,qoriq-device-config-2.0", },
> +	{}
> +};
> +
> +
> +/*
> + * Table for matching compatible strings, for device tree
> + * L3 cache controller node.
> + * "fsl,t4240-l3-cache-controller" corresponds to T4,
> + * "fsl,b4860-l3-cache-controller" corresponds to B4 &
> + * "fsl,p4080-l3-cache-controller" corresponds to other,
> + * SOCs.
> +*/
> +static const struct of_device_id l3_device_ids[] =3D {
> +	{ .compatible =3D "fsl,t4240-l3-cache-controller", },
> +	{ .compatible =3D "fsl,b4860-l3-cache-controller", },
> +	{ .compatible =3D "fsl,p4080-l3-cache-controller", },
> +	{}
> +};
> +
> +/* maximum subwindows permitted per liodn */
> +static u32 max_subwindow_count;
> +
> +/* Pool for fspi allocation */
> +struct gen_pool *spaace_pool;
> +
> +/**
> + * pamu_get_max_subwin_cnt() - Return the maximum supported
> + * subwindow count per liodn.
> + *
> + */
> +u32 pamu_get_max_subwin_cnt()
> +{
> +	return max_subwindow_count;
> +}
> +
> +/**
> + * pamu_get_ppaace() - Return the primary PACCE
> + * @liodn: liodn PAACT index for desired PAACE
> + *
> + * Returns the ppace pointer upon success else return
> + * null.
> + */
> +static struct paace *pamu_get_ppaace(int liodn)
> +{
> +	if (!ppaact || liodn >=3D PAACE_NUMBER_ENTRIES) {
> +		pr_debug("PPAACT doesn't exist\n");
> +		return NULL;
> +	}
> +
> +	return &ppaact[liodn];
> +}
> +
> +/**
> + * pamu_enable_liodn() - Set valid bit of PACCE
> + * @liodn: liodn PAACT index for desired PAACE
> + *
> + * Returns 0 upon success else error code < 0 returned
> + */
> +int pamu_enable_liodn(int liodn)
> +{
> +	struct paace *ppaace;
> +
> +	ppaace =3D pamu_get_ppaace(liodn);
> +	if (!ppaace) {
> +		pr_debug("Invalid primary paace entry\n");
> +		return -ENOENT;
> +	}
> +
> +	if (!get_bf(ppaace->addr_bitfields, PPAACE_AF_WSE)) {
> +		pr_debug("liodn %d not configured\n", liodn);
> +		return -EINVAL;
> +	}
> +
> +	/* Ensure that all other stores to the ppaace complete first */
> +	mb();
> +
> +	set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_VALID);
> +	mb();
> +
> +	return 0;
> +}
> +
> +/**
> + * pamu_disable_liodn() - Clears valid bit of PACCE
> + * @liodn: liodn PAACT index for desired PAACE
> + *
> + * Returns 0 upon success else error code < 0 returned
> + */
> +int pamu_disable_liodn(int liodn)
> +{
> +	struct paace *ppaace;
> +
> +	ppaace =3D pamu_get_ppaace(liodn);
> +	if (!ppaace) {
> +		pr_debug("Invalid primary paace entry\n");
> +		return -ENOENT;
> +	}
> +
> +	set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID);
> +	mb();
> +
> +	return 0;
> +}
> +
> +/* Derive the window size encoding for a particular PAACE entry */
> +static unsigned int map_addrspace_size_to_wse(phys_addr_t
> addrspace_size)
> +{
> +	/* Bug if not a power of 2 */
> +	BUG_ON(!is_power_of_2(addrspace_size));
> +
> +	/* window size is 2^(WSE+1) bytes */
> +	return __ffs(addrspace_size) - 1;
> +}
> +
> +/* Derive the PAACE window count encoding for the subwindow count */
> +static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt)
> +{
> +       /* window count is 2^(WCE+1) bytes */
> +       return __ffs(subwindow_cnt) - 1;
> +}
> +
> +/*
> + * Set the PAACE type as primary and set the coherency required domain
> + * attribute
> + */
> +static void pamu_init_ppaace(struct paace *ppaace)
> +{
> +	set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY);
> +
> +	set_bf(ppaace->domain_attr.to_host.coherency_required,
> PAACE_DA_HOST_CR,
> +	       PAACE_M_COHERENCE_REQ);
> +}
> +
> +/*
> + * Set the PAACE type as secondary and set the coherency required domain
> + * attribute.
> + */
> +static void pamu_init_spaace(struct paace *spaace)
> +{
> +	set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY);
> +	set_bf(spaace->domain_attr.to_host.coherency_required,
> PAACE_DA_HOST_CR,
> +	       PAACE_M_COHERENCE_REQ);
> +}
> +
> +/*
> + * Return the spaace (corresponding to the secondary window index)
> + * for a particular ppaace.
> + */
> +static struct paace *pamu_get_spaace(struct paace *paace, u32 wnum)
> +{
> +	u32 subwin_cnt;
> +	struct paace *spaace =3D NULL;
> +
> +	subwin_cnt =3D 1UL << (get_bf(paace->impl_attr, PAACE_IA_WCE) + 1);
> +
> +	if (wnum < subwin_cnt)
> +		spaace =3D &spaact[paace->fspi + wnum];
> +	else
> +		pr_debug("secondary paace out of bounds\n");
> +
> +	return spaace;
> +}
> +
> +/**
> + * pamu_get_fspi_and_allocate() - Allocates fspi index and reserves
> subwindows
> + *                                required for primary PAACE in the
> secondary
> + *                                PAACE table.
> + * @subwin_cnt: Number of subwindows to be reserved.
> + *
> + * A PPAACE entry may have a number of associated subwindows. A
> subwindow
> + * corresponds to a SPAACE entry in the SPAACT table. Each PAACE entry
> stores
> + * the index (fspi) of the first SPAACE entry in the SPAACT table. This
> + * function returns the index of the first SPAACE entry. The remaining
> + * SPAACE entries are reserved contiguously from that index.
> + *
> + * Returns a valid fspi index in the range of 0 - SPAACE_NUMBER_ENTRIES
> on success.
> + * If no SPAACE entry is available or the allocator can not reserve the
> required
> + * number of contiguous entries function returns ULONG_MAX indicating a
> failure.
> + *
> +*/
> +static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt)
> +{
> +	unsigned long spaace_addr;
> +
> +	spaace_addr =3D gen_pool_alloc(spaace_pool, subwin_cnt *
> sizeof(struct paace));
> +	if (!spaace_addr)
> +		return ULONG_MAX;
> +
> +	return (spaace_addr - (unsigned long)spaact) / (sizeof(struct
> paace));
> +}
> +
> +/* Release the subwindows reserved for a particular LIODN */
> +void pamu_free_subwins(int liodn)
> +{
> +	struct paace *ppaace;
> +	u32 subwin_cnt, size;
> +
> +	ppaace =3D pamu_get_ppaace(liodn);
> +	if (!ppaace) {
> +		pr_debug("Invalid liodn entry\n");
> +		return;
> +	}
> +
> +	if (get_bf(ppaace->addr_bitfields, PPAACE_AF_MW)) {
> +		subwin_cnt =3D 1UL << (get_bf(ppaace->impl_attr, PAACE_IA_WCE)
> + 1);
> +		size =3D (subwin_cnt - 1) * sizeof(struct paace);
> +		gen_pool_free(spaace_pool, (unsigned long)&spaact[ppaace-
> >fspi], size);
> +		set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
> +	}
> +}
> +
> +/*
> + * Function used for updating stash destination for the coressponding
> + * LIODN.
> + */
> +int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value)
> +{
> +	struct paace *paace;
> +
> +	paace =3D pamu_get_ppaace(liodn);
> +	if (!paace) {
> +		pr_debug("Invalid liodn entry\n");
> +		return -ENOENT;
> +	}
> +	if (subwin) {
> +		paace =3D pamu_get_spaace(paace, subwin - 1);
> +		if (!paace) {
> +			return -ENOENT;
> +		}
> +	}
> +	set_bf(paace->impl_attr, PAACE_IA_CID, value);
> +
> +	mb();
> +
> +	return 0;
> +}
> +
> +/* Disable a subwindow corresponding to the LIODN */
> +int pamu_disable_spaace(int liodn, u32 subwin)
> +{
> +	struct paace *paace;
> +
> +	paace =3D pamu_get_ppaace(liodn);
> +	if (!paace) {
> +		pr_debug("Invalid liodn entry\n");
> +		return -ENOENT;
> +	}
> +	if (subwin) {
> +		paace =3D pamu_get_spaace(paace, subwin - 1);
> +		if (!paace) {
> +			return -ENOENT;
> +		}
> +		set_bf(paace->addr_bitfields, PAACE_AF_V,
> +			 PAACE_V_INVALID);
> +	} else {
> +		set_bf(paace->addr_bitfields, PAACE_AF_AP,
> +			 PAACE_AP_PERMS_DENIED);
> +	}
> +
> +	mb();
> +
> +	return 0;
> +}
> +
> +
> +/**
> + * pamu_config_paace() - Sets up PPAACE entry for specified liodn
> + *
> + * @liodn: Logical IO device number
> + * @win_addr: starting address of DSA window
> + * @win-size: size of DSA window
> + * @omi: Operation mapping index -- if ~omi =3D=3D 0 then omi not define=
d
> + * @rpn: real (true physical) page number
> + * @stashid: cache stash id for associated cpu -- if ~stashid =3D=3D 0 t=
hen
> + *	     stashid not defined
> + * @snoopid: snoop id for hardware coherency -- if ~snoopid =3D=3D 0 the=
n
> + *	     snoopid not defined
> + * @subwin_cnt: number of sub-windows
> + * @prot: window permissions
> + *
> + * Returns 0 upon success else error code < 0 returned
> + */
> +int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t
> win_size,
> +		       u32 omi, unsigned long rpn, u32 snoopid, u32 stashid,
> +		       u32 subwin_cnt, int prot)
> +{
> +	struct paace *ppaace;
> +	unsigned long fspi;
> +
> +	if (!is_power_of_2(win_size) || win_size < PAMU_PAGE_SIZE) {
> +		pr_debug("window size too small or not a power of two
> %llx\n", win_size);
> +		return -EINVAL;
> +	}
> +
> +	if (win_addr & (win_size - 1)) {
> +		pr_debug("window address is not aligned with window size\n");
> +		return -EINVAL;
> +	}
> +
> +	ppaace =3D pamu_get_ppaace(liodn);
> +	if (!ppaace) {
> +		return -ENOENT;
> +	}
> +
> +	/* window size is 2^(WSE+1) bytes */
> +	set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE,
> +		map_addrspace_size_to_wse(win_size));
> +
> +	pamu_init_ppaace(ppaace);
> +
> +	ppaace->wbah =3D win_addr >> (PAMU_PAGE_SHIFT + 20);
> +	set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL,
> +	       (win_addr >> PAMU_PAGE_SHIFT));
> +
> +	/* set up operation mapping if it's configured */
> +	if (omi < OME_NUMBER_ENTRIES) {
> +		set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
> +		ppaace->op_encode.index_ot.omi =3D omi;
> +	} else if (~omi !=3D 0) {
> +		pr_debug("bad operation mapping index: %d\n", omi);
> +		return -EINVAL;
> +	}
> +
> +	/* configure stash id */
> +	if (~stashid !=3D 0)
> +		set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid);
> +
> +	/* configure snoop id */
> +	if (~snoopid !=3D 0)
> +		ppaace->domain_attr.to_host.snpid =3D snoopid;
> +
> +	if (subwin_cnt) {
> +		/* The first entry is in the primary PAACE instead */
> +		fspi =3D pamu_get_fspi_and_allocate(subwin_cnt - 1);
> +		if (fspi =3D=3D ULONG_MAX) {
> +			pr_debug("spaace indexes exhausted\n");
> +			return -EINVAL;
> +		}
> +
> +		/* window count is 2^(WCE+1) bytes */
> +		set_bf(ppaace->impl_attr, PAACE_IA_WCE,
> +		       map_subwindow_cnt_to_wce(subwin_cnt));
> +		set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0x1);
> +		ppaace->fspi =3D fspi;
> +	} else {
> +		set_bf(ppaace->impl_attr, PAACE_IA_ATM,
> PAACE_ATM_WINDOW_XLATE);
> +		ppaace->twbah =3D rpn >> 20;
> +		set_bf(ppaace->win_bitfields, PAACE_WIN_TWBAL, rpn);
> +		set_bf(ppaace->addr_bitfields, PAACE_AF_AP, prot);
> +		set_bf(ppaace->impl_attr, PAACE_IA_WCE, 0);
> +		set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
> +	}
> +	mb();
> +
> +	return 0;
> +}
> +
> +/**
> + * pamu_config_spaace() - Sets up SPAACE entry for specified subwindow
> + *
> + * @liodn:  Logical IO device number
> + * @subwin_cnt:  number of sub-windows associated with dma-window
> + * @subwin: subwindow index
> + * @subwin_size: size of subwindow
> + * @omi: Operation mapping index
> + * @rpn: real (true physical) page number
> + * @snoopid: snoop id for hardware coherency -- if ~snoopid =3D=3D 0 the=
n
> + *			  snoopid not defined
> + * @stashid: cache stash id for associated cpu
> + * @enable: enable/disable subwindow after reconfiguration
> + * @prot: sub window permissions
> + *
> + * Returns 0 upon success else error code < 0 returned
> + */
> +int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin,
> +		       phys_addr_t subwin_size, u32 omi, unsigned long rpn,
> +		       u32 snoopid, u32 stashid, int enable, int prot)
> +{
> +	struct paace *paace;
> +
> +
> +	/* setup sub-windows */
> +	if (!subwin_cnt) {
> +		pr_debug("Invalid subwindow count\n");
> +		return -EINVAL;
> +	}
> +
> +	paace =3D pamu_get_ppaace(liodn);
> +	if (subwin > 0 && subwin < subwin_cnt && paace) {
> +		paace =3D pamu_get_spaace(paace, subwin - 1);
> +
> +		if (paace && !(paace->addr_bitfields & PAACE_V_VALID)) {
> +			pamu_init_spaace(paace);
> +			set_bf(paace->addr_bitfields, SPAACE_AF_LIODN, liodn);
> +		}
> +	}
> +
> +	if (!paace) {
> +		pr_debug("Invalid liodn entry\n");
> +		return -ENOENT;
> +	}
> +
> +	if (!is_power_of_2(subwin_size) || subwin_size < PAMU_PAGE_SIZE) {
> +		pr_debug("subwindow size out of range, or not a power of
> 2\n");
> +		return -EINVAL;
> +	}
> +
> +	if (rpn =3D=3D ULONG_MAX) {
> +		pr_debug("real page number out of range\n");
> +		return -EINVAL;
> +	}
> +
> +	/* window size is 2^(WSE+1) bytes */
> +	set_bf(paace->win_bitfields, PAACE_WIN_SWSE,
> +	       map_addrspace_size_to_wse(subwin_size));
> +
> +	set_bf(paace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE);
> +	paace->twbah =3D rpn >> 20;
> +	set_bf(paace->win_bitfields, PAACE_WIN_TWBAL, rpn);
> +	set_bf(paace->addr_bitfields, PAACE_AF_AP, prot);
> +
> +	/* configure snoop id */
> +	if (~snoopid !=3D 0)
> +		paace->domain_attr.to_host.snpid =3D snoopid;
> +
> +	/* set up operation mapping if it's configured */
> +	if (omi < OME_NUMBER_ENTRIES) {
> +		set_bf(paace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
> +		paace->op_encode.index_ot.omi =3D omi;
> +	} else if (~omi !=3D 0) {
> +		pr_debug("bad operation mapping index: %d\n", omi);
> +		return -EINVAL;
> +	}
> +
> +	if (~stashid !=3D 0)
> +		set_bf(paace->impl_attr, PAACE_IA_CID, stashid);
> +
> +	smp_wmb();
> +
> +	if (enable)
> +		set_bf(paace->addr_bitfields, PAACE_AF_V, PAACE_V_VALID);
> +
> +	mb();
> +
> +	return 0;
> +}
> +
> +/**
> +* get_ome_index() - Returns the index in the operation mapping table
> +*                   for device.
> +* @*omi_index: pointer for storing the index value
> +*
> +*/
> +void get_ome_index(u32 *omi_index, struct device *dev)
> +{
> +	if (of_device_is_compatible(dev->of_node, "fsl,qman-portal"))
> +		*omi_index =3D OMI_QMAN;
> +	if (of_device_is_compatible(dev->of_node, "fsl,qman"))
> +		*omi_index =3D OMI_QMAN_PRIV;
> +}
> +
> +/**
> + * get_stash_id - Returns stash destination id corresponding to a
> + *                cache type and vcpu.
> + * @stash_dest_hint: L1, L2 or L3
> + * @vcpu: vpcu target for a particular cache type.
> + *
> + * Returs stash on success or ~(u32)0 on failure.
> + *
> + */
> +u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
> +{
> +	const u32 *prop;
> +	struct device_node *node;
> +	u32 cache_level;
> +	int len, found =3D 0;
> +	int i;
> +
> +	/* Fastpath, exit early if L3/CPC cache is target for stashing */
> +	if (stash_dest_hint =3D=3D PAMU_ATTR_CACHE_L3) {
> +		node =3D of_find_matching_node(NULL, l3_device_ids);
> +		if (node) {
> +			prop =3D of_get_property(node, "cache-stash-id", 0);
> +			if (!prop) {
> +				pr_debug("missing cache-stash-id at %s\n", node-
> >full_name);
> +				of_node_put(node);
> +				return ~(u32)0;
> +			}
> +			of_node_put(node);
> +			return be32_to_cpup(prop);
> +		}
> +		return ~(u32)0;
> +	}
> +
> +	for_each_node_by_type(node, "cpu") {
> +		prop =3D of_get_property(node, "reg", &len);
> +		for (i =3D 0; i < len / sizeof(u32); i++) {
> +			if (be32_to_cpup(&prop[i]) =3D=3D vcpu) {
> +				found =3D 1;
> +				goto found_cpu_node;
> +			}
> +		}
> +	}
> +found_cpu_node:
> +
> +	/* find the hwnode that represents the cache */
> +	for (cache_level =3D PAMU_ATTR_CACHE_L1; (cache_level <
> PAMU_ATTR_CACHE_L3) && found; cache_level++) {
> +		if (stash_dest_hint =3D=3D cache_level) {
> +			prop =3D of_get_property(node, "cache-stash-id", 0);
> +			if (!prop) {
> +				pr_debug("missing cache-stash-id at %s\n", node-
> >full_name);
> +				of_node_put(node);
> +				return ~(u32)0;
> +			}
> +			of_node_put(node);
> +			return be32_to_cpup(prop);
> +		}
> +
> +		prop =3D of_get_property(node, "next-level-cache", 0);
> +		if (!prop) {
> +			pr_debug("can't find next-level-cache at %s\n",
> +				node->full_name);
> +			of_node_put(node);
> +			return ~(u32)0;  /* can't traverse any further */
> +		}
> +		of_node_put(node);
> +
> +		/* advance to next node in cache hierarchy */
> +		node =3D of_find_node_by_phandle(*prop);
> +		if (!node) {
> +			pr_debug("Invalid node for cache hierarchy %s\n",
> +				node->full_name);
> +			return ~(u32)0;
> +		}
> +	}
> +
> +	pr_debug("stash dest not found for %d on vcpu %d\n",
> +	          stash_dest_hint, vcpu);
> +	return ~(u32)0;
> +}
> +
> +/* Identify if the PAACT table entry belongs to QMAN, BMAN or QMAN
> Portal */
> +#define QMAN_PAACE 1
> +#define QMAN_PORTAL_PAACE 2
> +#define BMAN_PAACE 3
> +
> +/**
> + * Setup operation mapping and stash destinations for QMAN and QMAN
> portal.
> + * Memory accesses to QMAN and BMAN private memory need not be coherent,
> so
> + * clear the PAACE entry coherency attribute for them.
> + */
> +static void setup_qbman_paace(struct paace *ppaace, int  paace_type)
> +{
> +	switch (paace_type) {
> +	case QMAN_PAACE:
> +		set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
> +		ppaace->op_encode.index_ot.omi =3D OMI_QMAN_PRIV;
> +		/* setup QMAN Private data stashing for the L3 cache */
> +		set_bf(ppaace->impl_attr, PAACE_IA_CID,
> get_stash_id(PAMU_ATTR_CACHE_L3, 0));
> +		set_bf(ppaace->domain_attr.to_host.coherency_required,
> PAACE_DA_HOST_CR,
> +		       0);
> +		break;
> +	case QMAN_PORTAL_PAACE:
> +		set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
> +		ppaace->op_encode.index_ot.omi =3D OMI_QMAN;
> +		/*Set DQRR and Frame stashing for the L3 cache */
> +		set_bf(ppaace->impl_attr, PAACE_IA_CID,
> get_stash_id(PAMU_ATTR_CACHE_L3, 0));
> +		break;
> +	case BMAN_PAACE:
> +		set_bf(ppaace->domain_attr.to_host.coherency_required,
> PAACE_DA_HOST_CR,
> +		       0);
> +		break;
> +	}
> +}
> +
> +/**
> + * Setup the operation mapping table for various devices. This is a
> static
> + * table where each table index corresponds to a particular device. PAMU
> uses
> + * this table to translate device transaction to appropriate corenet
> + * transaction.
> + */
> +static void __init setup_omt(struct ome *omt)
> +{
> +	struct ome *ome;
> +
> +	/* Configure OMI_QMAN */
> +	ome =3D &omt[OMI_QMAN];
> +
> +	ome->moe[IOE_READ_IDX] =3D EOE_VALID | EOE_READ;
> +	ome->moe[IOE_EREAD0_IDX] =3D EOE_VALID | EOE_RSA;
> +	ome->moe[IOE_WRITE_IDX] =3D EOE_VALID | EOE_WRITE;
> +	ome->moe[IOE_EWRITE0_IDX] =3D EOE_VALID | EOE_WWSAO;
> +
> +	ome->moe[IOE_DIRECT0_IDX] =3D EOE_VALID | EOE_LDEC;
> +	ome->moe[IOE_DIRECT1_IDX] =3D EOE_VALID | EOE_LDECPE;
> +
> +	/* Configure OMI_FMAN */
> +	ome =3D &omt[OMI_FMAN];
> +	ome->moe[IOE_READ_IDX]  =3D EOE_VALID | EOE_READI;
> +	ome->moe[IOE_WRITE_IDX] =3D EOE_VALID | EOE_WRITE;
> +
> +	/* Configure OMI_QMAN private */
> +	ome =3D &omt[OMI_QMAN_PRIV];
> +	ome->moe[IOE_READ_IDX]  =3D EOE_VALID | EOE_READ;
> +	ome->moe[IOE_WRITE_IDX] =3D EOE_VALID | EOE_WRITE;
> +	ome->moe[IOE_EREAD0_IDX] =3D EOE_VALID | EOE_RSA;
> +	ome->moe[IOE_EWRITE0_IDX] =3D EOE_VALID | EOE_WWSA;
> +
> +	/* Configure OMI_CAAM */
> +	ome =3D &omt[OMI_CAAM];
> +	ome->moe[IOE_READ_IDX]  =3D EOE_VALID | EOE_READI;
> +	ome->moe[IOE_WRITE_IDX] =3D EOE_VALID | EOE_WRITE;
> +}
> +
> +/*
> + * Get the maximum number of PAACT table entries
> + * and subwindows supported by PAMU
> + */
> +static void get_pamu_cap_values(unsigned long pamu_reg_base)
> +{
> +	u32 pc_val;
> +
> +	pc_val =3D in_be32((u32 *)(pamu_reg_base + PAMU_PC3));
> +	/* Maximum number of subwindows per liodn */
> +	max_subwindow_count =3D 1 << (1 + PAMU_PC3_MWCE(pc_val));
> +}
> +
> +/* Setup PAMU registers pointing to PAACT, SPAACT and OMT */
> +int setup_one_pamu(unsigned long pamu_reg_base, unsigned long
> pamu_reg_size,
> +	           phys_addr_t ppaact_phys, phys_addr_t spaact_phys,
> +		   phys_addr_t omt_phys)
> +{
> +	u32 *pc;
> +	struct pamu_mmap_regs *pamu_regs;
> +
> +	pc =3D (u32 *) (pamu_reg_base + PAMU_PC);
> +	pamu_regs =3D (struct pamu_mmap_regs *)
> +		(pamu_reg_base + PAMU_MMAP_REGS_BASE);
> +
> +	/* set up pointers to corenet control blocks */
> +
> +	out_be32(&pamu_regs->ppbah, upper_32_bits(ppaact_phys));
> +	out_be32(&pamu_regs->ppbal, lower_32_bits(ppaact_phys));
> +	ppaact_phys =3D ppaact_phys + PAACT_SIZE;
> +	out_be32(&pamu_regs->pplah, upper_32_bits(ppaact_phys));
> +	out_be32(&pamu_regs->pplal, lower_32_bits(ppaact_phys));
> +
> +	out_be32(&pamu_regs->spbah, upper_32_bits(spaact_phys));
> +	out_be32(&pamu_regs->spbal, lower_32_bits(spaact_phys));
> +	spaact_phys =3D spaact_phys + SPAACT_SIZE;
> +	out_be32(&pamu_regs->splah, upper_32_bits(spaact_phys));
> +	out_be32(&pamu_regs->splal, lower_32_bits(spaact_phys));
> +
> +	out_be32(&pamu_regs->obah, upper_32_bits(omt_phys));
> +	out_be32(&pamu_regs->obal, lower_32_bits(omt_phys));
> +	omt_phys =3D omt_phys + OMT_SIZE;
> +	out_be32(&pamu_regs->olah, upper_32_bits(omt_phys));
> +	out_be32(&pamu_regs->olal, lower_32_bits(omt_phys));
> +
> +	/*
> +	 * set PAMU enable bit,
> +	 * allow ppaact & omt to be cached
> +	 * & enable PAMU access violation interrupts.
> +	 */
> +
> +	out_be32((u32 *)(pamu_reg_base + PAMU_PICS),
> +			PAMU_ACCESS_VIOLATION_ENABLE);
> +	out_be32(pc, PAMU_PC_PE | PAMU_PC_OCE | PAMU_PC_SPCC |
> PAMU_PC_PPCC);
> +	return 0;
> +}
> +
> +/* Enable all device LIODNS */
> +static void __init setup_liodns(void)
> +{
> +	int i, len;
> +	struct paace *ppaace;
> +	struct device_node *node =3D NULL;
> +	const u32 *prop;
> +
> +	for_each_node_with_property(node, "fsl,liodn") {
> +		prop =3D of_get_property(node, "fsl,liodn", &len);
> +		for (i =3D 0; i < len / sizeof(u32); i++) {
> +			int liodn;
> +
> +			liodn =3D be32_to_cpup(&prop[i]);
> +			if (liodn >=3D PAACE_NUMBER_ENTRIES) {
> +				pr_debug("Invalid LIODN value %d\n", liodn);
> +				continue;
> +			}
> +			ppaace =3D pamu_get_ppaace(liodn);
> +			pamu_init_ppaace(ppaace);
> +			/* window size is 2^(WSE+1) bytes */
> +			set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
> +			ppaace->wbah =3D 0;
> +			set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
> +			set_bf(ppaace->impl_attr, PAACE_IA_ATM,
> +				PAACE_ATM_NO_XLATE);
> +			set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
> +				PAACE_AP_PERMS_ALL);
> +			if (of_device_is_compatible(node, "fsl,qman-portal"))
> +				setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE);
> +			if (of_device_is_compatible(node, "fsl,qman"))
> +				setup_qbman_paace(ppaace, QMAN_PAACE);
> +			if (of_device_is_compatible(node, "fsl,bman"))
> +				setup_qbman_paace(ppaace, BMAN_PAACE);
> +			mb();
> +			pamu_enable_liodn(liodn);
> +		}
> +	}
> +}
> +
> +irqreturn_t pamu_av_isr(int irq, void *arg)
> +{
> +	struct pamu_isr_data *data =3D arg;
> +	phys_addr_t phys;
> +	unsigned int i, j, ret;
> +
> +	pr_emerg("fsl-pamu: access violation interrupt\n");
> +
> +	for (i =3D 0; i < data->count; i++) {
> +		void __iomem *p =3D data->pamu_reg_base + i * PAMU_OFFSET;
> +		u32 pics =3D in_be32(p + PAMU_PICS);
> +
> +		if (pics & PAMU_ACCESS_VIOLATION_STAT) {
> +			u32 avs1 =3D in_be32(p + PAMU_AVS1);
> +			struct paace *paace;
> +
> +			pr_emerg("POES1=3D%08x\n", in_be32(p + PAMU_POES1));
> +			pr_emerg("POES2=3D%08x\n", in_be32(p + PAMU_POES2));
> +			pr_emerg("AVS1=3D%08x\n", avs1);
> +			pr_emerg("AVS2=3D%08x\n", in_be32(p + PAMU_AVS2));
> +			pr_emerg("AVA=3D%016llx\n", make64(in_be32(p +
> PAMU_AVAH),
> +				in_be32(p + PAMU_AVAL)));
> +			pr_emerg("UDAD=3D%08x\n", in_be32(p + PAMU_UDAD));
> +			pr_emerg("POEA=3D%016llx\n", make64(in_be32(p +
> PAMU_POEAH),
> +				in_be32(p + PAMU_POEAL)));
> +
> +			phys =3D make64(in_be32(p + PAMU_POEAH),
> +				in_be32(p + PAMU_POEAL));
> +
> +			/* Assume that POEA points to a PAACE */
> +			if (phys) {
> +				u32 *paace =3D phys_to_virt(phys);
> +
> +				/* Only the first four words are relevant */
> +				for (j =3D 0; j < 4; j++)
> +					pr_emerg("PAACE[%u]=3D%08x\n", j,
> in_be32(paace + j));
> +			}
> +
> +			/* clear access violation condition */
> +			out_be32((p + PAMU_AVS1), avs1 & PAMU_AV_MASK);
> +			paace =3D pamu_get_ppaace(avs1 >> PAMU_AVS1_LIODN_SHIFT);
> +			BUG_ON(!paace);
> +			/* check if we got a violation for a disabled LIODN */
> +			if (!get_bf(paace->addr_bitfields, PAACE_AF_V)) {
> +				/*
> +				 * As per hardware erratum A-003638, access
> +				 * violation can be reported for a disabled
> +				 * LIODN. If we hit that condition, disable
> +				 * access violation reporting.
> +				 */
> +				pics &=3D ~PAMU_ACCESS_VIOLATION_ENABLE;
> +			} else {
> +				/* Disable the LIODN */
> +				ret =3D pamu_disable_liodn(avs1 >>
> PAMU_AVS1_LIODN_SHIFT);
> +				BUG_ON(ret);
> +				pr_emerg("Disabling liodn %x\n", avs1 >>
> PAMU_AVS1_LIODN_SHIFT);
> +			}
> +			out_be32((p + PAMU_PICS), pics);
> +		}
> +	}
> +
> +
> +	return IRQ_HANDLED;
> +}
> +
> +#define LAWAR_EN		0x80000000
> +#define LAWAR_TARGET_MASK	0x0FF00000
> +#define LAWAR_TARGET_SHIFT	20
> +#define LAWAR_SIZE_MASK		0x0000003F
> +#define LAWAR_CSDID_MASK	0x000FF000
> +#define LAWAR_CSDID_SHIFT	12
> +
> +#define LAW_SIZE_4K		0xb
> +
> +struct ccsr_law {
> +	u32	lawbarh;	/* LAWn base address high */
> +	u32	lawbarl;	/* LAWn base address low */
> +	u32	lawar;		/* LAWn attributes */
> +	u32	reserved;
> +};
> +
> +/*
> + * Create a coherence subdomain for a given memory block.
> + */
> +static int __init create_csd(phys_addr_t phys, size_t size, u32
> csd_port_id)
> +{
> +	struct device_node *np;
> +	const __be32 *iprop;
> +	void __iomem *lac =3D NULL;	/* Local Access Control registers */
> +	struct ccsr_law __iomem *law;
> +	void __iomem *ccm =3D NULL;
> +	u32 __iomem *csdids;
> +	unsigned int i, num_laws, num_csds;
> +	u32 law_target =3D 0;
> +	u32 csd_id =3D 0;
> +	int ret =3D 0;
> +
> +	np =3D of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
> +	if (!np)
> +		return -ENODEV;
> +
> +	iprop =3D of_get_property(np, "fsl,num-laws", NULL);
> +	if (!iprop) {
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	num_laws =3D be32_to_cpup(iprop);
> +	if (!num_laws) {
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	lac =3D of_iomap(np, 0);
> +	if (!lac) {
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	/* LAW registers are at offset 0xC00 */
> +	law =3D lac + 0xC00;
> +
> +	of_node_put(np);
> +
> +	np =3D of_find_compatible_node(NULL, NULL, "fsl,corenet-cf");
> +	if (!np) {
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	iprop =3D of_get_property(np, "fsl,ccf-num-csdids", NULL);
> +	if (!iprop) {
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	num_csds =3D be32_to_cpup(iprop);
> +	if (!num_csds) {
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	ccm =3D of_iomap(np, 0);
> +	if (!ccm) {
> +		ret =3D -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* The undocumented CSDID registers are at offset 0x600 */
> +	csdids =3D ccm + 0x600;
> +
> +	of_node_put(np);
> +	np =3D NULL;
> +
> +	/* Find an unused coherence subdomain ID */
> +	for (csd_id =3D 0; csd_id < num_csds; csd_id++) {
> +		if (!csdids[csd_id])
> +			break;
> +	}
> +
> +	/* Store the Port ID in the (undocumented) proper CIDMRxx register
> */
> +	csdids[csd_id] =3D csd_port_id;
> +
> +	/* Find the DDR LAW that maps to our buffer. */
> +	for (i =3D 0; i < num_laws; i++) {
> +		if (law[i].lawar & LAWAR_EN) {
> +			phys_addr_t law_start, law_end;
> +
> +			law_start =3D make64(law[i].lawbarh, law[i].lawbarl);
> +			law_end =3D law_start +
> +				(2ULL << (law[i].lawar & LAWAR_SIZE_MASK));
> +
> +			if (law_start <=3D phys && phys < law_end) {
> +				law_target =3D law[i].lawar & LAWAR_TARGET_MASK;
> +				break;
> +			}
> +		}
> +	}
> +
> +	if (i =3D=3D 0 || i =3D=3D num_laws) {
> +		/* This should never happen*/
> +		ret =3D -ENOENT;
> +		goto error;
> +	}
> +
> +	/* Find a free LAW entry */
> +	while (law[--i].lawar & LAWAR_EN) {
> +		if (i =3D=3D 0) {
> +			/* No higher priority LAW slots available */
> +			ret =3D -ENOENT;
> +			goto error;
> +		}
> +	}
> +
> +	law[i].lawbarh =3D upper_32_bits(phys);
> +	law[i].lawbarl =3D lower_32_bits(phys);
> +	wmb();
> +	law[i].lawar =3D LAWAR_EN | law_target | (csd_id <<
> LAWAR_CSDID_SHIFT) |
> +		(LAW_SIZE_4K + get_order(size));
> +	wmb();
> +
> +error:
> +	if (ccm)
> +		iounmap(ccm);
> +
> +	if (lac)
> +		iounmap(lac);
> +
> +	if (np)
> +		of_node_put(np);
> +
> +	return ret;
> +}
> +
> +/*
> + * Table of SVRs and the corresponding PORT_ID values. Port ID
> corresponds to a
> + * bit map of snoopers for a given range of memory mapped by a LAW.
> + *
> + * All future CoreNet-enabled SOCs will have this erratum(A-004510)
> fixed, so this
> + * table should never need to be updated.  SVRs are guaranteed to be
> unique, so
> + * there is no worry that a future SOC will inadvertently have one of
> these
> + * values.
> + */
> +static const struct {
> +	u32 svr;
> +	u32 port_id;
> +} port_id_map[] =3D {
> +	{0x82100010, 0xFF000000},	/* P2040 1.0 */
> +	{0x82100011, 0xFF000000},	/* P2040 1.1 */
> +	{0x82100110, 0xFF000000},	/* P2041 1.0 */
> +	{0x82100111, 0xFF000000},	/* P2041 1.1 */
> +	{0x82110310, 0xFF000000},	/* P3041 1.0 */
> +	{0x82110311, 0xFF000000},	/* P3041 1.1 */
> +	{0x82010020, 0xFFF80000},	/* P4040 2.0 */
> +	{0x82000020, 0xFFF80000},	/* P4080 2.0 */
> +	{0x82210010, 0xFC000000},       /* P5010 1.0 */
> +	{0x82210020, 0xFC000000},       /* P5010 2.0 */
> +	{0x82200010, 0xFC000000},	/* P5020 1.0 */
> +	{0x82050010, 0xFF800000},	/* P5021 1.0 */
> +	{0x82040010, 0xFF800000},	/* P5040 1.0 */
> +};
> +
> +#define SVR_SECURITY	0x80000	/* The Security (E) bit */
> +
> +static int __init fsl_pamu_probe(struct platform_device *pdev)
> +{
> +	void __iomem *pamu_regs =3D NULL;
> +	struct ccsr_guts __iomem *guts_regs =3D NULL;
> +	u32 pamubypenr, pamu_counter;
> +	unsigned long pamu_reg_off;
> +	unsigned long pamu_reg_base;
> +	struct pamu_isr_data *data =3D NULL;
> +	struct device_node *guts_node;
> +	u64 size;
> +	struct page *p;
> +	int ret =3D 0;
> +	int irq;
> +	phys_addr_t ppaact_phys;
> +	phys_addr_t spaact_phys;
> +	phys_addr_t omt_phys;
> +	size_t mem_size =3D 0;
> +	unsigned int order =3D 0;
> +	u32 csd_port_id =3D 0;
> +	unsigned i;
> +	/*
> +	 * enumerate all PAMUs and allocate and setup PAMU tables
> +	 * for each of them,
> +	 * NOTE : All PAMUs share the same LIODN tables.
> +	 */
> +
> +	pamu_regs =3D of_iomap(pdev->dev.of_node, 0);
> +	if (!pamu_regs) {
> +		dev_err(&pdev->dev, "ioremap of PAMU node failed\n");
> +		return -ENOMEM;
> +	}
> +	of_get_address(pdev->dev.of_node, 0, &size, NULL);
> +
> +	irq =3D irq_of_parse_and_map(pdev->dev.of_node, 0);
> +	if (irq =3D=3D NO_IRQ) {
> +		dev_warn(&pdev->dev, "no interrupts listed in PAMU node\n");
> +		goto error;
> +	}
> +
> +	data =3D kzalloc(sizeof(struct pamu_isr_data), GFP_KERNEL);
> +	if (!data) {
> +		dev_err(&pdev->dev, "PAMU isr data memory allocation
> failed\n");
> +		ret =3D -ENOMEM;
> +		goto error;
> +	}
> +	data->pamu_reg_base =3D pamu_regs;
> +	data->count =3D size / PAMU_OFFSET;
> +
> +	/* The ISR needs access to the regs, so we won't iounmap them */
> +	ret =3D request_irq(irq, pamu_av_isr, 0, "pamu", data);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "error %i installing ISR for irq %i\n",
> +			ret, irq);
> +		goto error;
> +	}
> +
> +	guts_node =3D of_find_matching_node(NULL, guts_device_ids);
> +	if (!guts_node) {
> +		dev_err(&pdev->dev, "could not find GUTS node %s\n",
> +			pdev->dev.of_node->full_name);
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	guts_regs =3D of_iomap(guts_node, 0);
> +	of_node_put(guts_node);
> +	if (!guts_regs) {
> +		dev_err(&pdev->dev, "ioremap of GUTS node failed\n");
> +		ret =3D -ENODEV;
> +		goto error;
> +	}
> +
> +	/* read in the PAMU capability registers */
> +	get_pamu_cap_values((unsigned long)pamu_regs);
> +	/*
> +	 * To simplify the allocation of a coherency domain, we allocate
> the
> +	 * PAACT and the OMT in the same memory buffer.  Unfortunately,
> this
> +	 * wastes more memory compared to allocating the buffers
> separately.
> +	 */
> +	/* Determine how much memory we need */
> +	mem_size =3D (PAGE_SIZE << get_order(PAACT_SIZE)) +
> +		(PAGE_SIZE << get_order(SPAACT_SIZE)) +
> +		(PAGE_SIZE << get_order(OMT_SIZE));
> +	order =3D get_order(mem_size);
> +
> +	p =3D alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
> +	if (!p) {
> +		dev_err(&pdev->dev, "unable to allocate PAACT/SPAACT/OMT
> block\n");
> +		ret =3D -ENOMEM;
> +		goto error;
> +	}
> +
> +	ppaact =3D page_address(p);
> +	ppaact_phys =3D page_to_phys(p);
> +
> +	/* Make sure the memory is naturally aligned */
> +	if (ppaact_phys & ((PAGE_SIZE << order) - 1)) {
> +		dev_err(&pdev->dev, "PAACT/OMT block is unaligned\n");
> +		ret =3D -ENOMEM;
> +		goto error;
> +	}
> +
> +	spaact =3D (void *)ppaact + (PAGE_SIZE << get_order(PAACT_SIZE));
> +	omt =3D (void *)spaact + (PAGE_SIZE << get_order(SPAACT_SIZE));
> +
> +	dev_dbg(&pdev->dev, "ppaact virt=3D%p phys=3D0x%llx\n", ppaact,
> +		(unsigned long long) ppaact_phys);
> +
> +	/* Check to see if we need to implement the work-around on this SOC
> */
> +
> +	/* Determine the Port ID for our coherence subdomain */
> +	for (i =3D 0; i < ARRAY_SIZE(port_id_map); i++) {
> +		if (port_id_map[i].svr =3D=3D (mfspr(SPRN_SVR) & ~SVR_SECURITY))
> {
> +			csd_port_id =3D port_id_map[i].port_id;
> +			dev_dbg(&pdev->dev, "found matching SVR %08x\n",
> +				port_id_map[i].svr);
> +			break;
> +		}
> +	}
> +
> +	if (csd_port_id) {
> +		dev_dbg(&pdev->dev, "creating coherency subdomain at address
> "
> +			"0x%llx, size %zu, port id 0x%08x", ppaact_phys,
> +			mem_size, csd_port_id);
> +
> +		ret =3D create_csd(ppaact_phys, mem_size, csd_port_id);
> +		if (ret) {
> +			dev_err(&pdev->dev, "could not create coherence "
> +				"subdomain\n");
> +			return ret;
> +		}
> +	}
> +
> +	spaact_phys =3D virt_to_phys(spaact);
> +	omt_phys =3D virt_to_phys(omt);
> +
> +	spaace_pool =3D gen_pool_create(ilog2(sizeof(struct paace)), -1);
> +	if (!spaace_pool) {
> +		ret =3D -ENOMEM;
> +		dev_err(&pdev->dev, "PAMU : failed to allocate spaace gen
> pool\n");
> +		goto error;
> +	}
> +
> +	ret =3D gen_pool_add(spaace_pool, (unsigned long)spaact, SPAACT_SIZE,
> -1);
> +	if (ret)
> +		goto error_genpool;
> +
> +	pamubypenr =3D in_be32(&guts_regs->pamubypenr);
> +
> +	for (pamu_reg_off =3D 0, pamu_counter =3D 0x80000000; pamu_reg_off <
> size;
> +	     pamu_reg_off +=3D PAMU_OFFSET, pamu_counter >>=3D 1) {
> +
> +		pamu_reg_base =3D (unsigned long) pamu_regs + pamu_reg_off;
> +		setup_one_pamu(pamu_reg_base, pamu_reg_off, ppaact_phys,
> +				 spaact_phys, omt_phys);
> +		/* Disable PAMU bypass for this PAMU */
> +		pamubypenr &=3D ~pamu_counter;
> +	}
> +
> +	setup_omt(omt);
> +
> +	/* Enable all relevant PAMU(s) */
> +	out_be32(&guts_regs->pamubypenr, pamubypenr);
> +
> +	iounmap(guts_regs);
> +
> +	/* Enable DMA for the LIODNs in the device tree*/
> +
> +	setup_liodns();
> +
> +	return 0;
> +
> +error_genpool:
> +	gen_pool_destroy(spaace_pool);
> +
> +error:
> +	if (irq !=3D NO_IRQ)
> +		free_irq(irq, data);
> +
> +	if (data) {
> +		memset(data, 0, sizeof(struct pamu_isr_data));
> +		kfree(data);
> +	}
> +
> +	if (pamu_regs)
> +		iounmap(pamu_regs);
> +
> +	if (guts_regs)
> +		iounmap(guts_regs);
> +
> +	if (ppaact)
> +		free_pages((unsigned long)ppaact, order);
> +
> +	ppaact =3D NULL;
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id fsl_of_pamu_ids[] =3D {
> +	{
> +		.compatible =3D "fsl,p4080-pamu",
> +	},
> +	{
> +		.compatible =3D "fsl,pamu",
> +	},
> +	{},
> +};
> +
> +static struct platform_driver fsl_of_pamu_driver =3D {
> +	.driver =3D {
> +		.name =3D "fsl-of-pamu",
> +		.owner =3D THIS_MODULE,
> +	},
> +	.probe =3D fsl_pamu_probe,
> +};
> +
> +static __init int fsl_pamu_init(void)
> +{
> +	struct platform_device *pdev =3D NULL;
> +	struct device_node *np;
> +	int ret;
> +
> +	/*
> +	 * The normal OF process calls the probe function at some
> +	 * indeterminate later time, after most drivers have loaded.  This
> is
> +	 * too late for us, because PAMU clients (like the Qman driver)
> +	 * depend on PAMU being initialized early.
> +	 *
> +	 * So instead, we "manually" call our probe function by creating
> the
> +	 * platform devices ourselves.
> +	 */
> +
> +	/*
> +	 * We assume that there is only one PAMU node in the device tree.
> A
> +	 * single PAMU node represents all of the PAMU devices in the SOC
> +	 * already.   Everything else already makes that assumption, and
> the
> +	 * binding for the PAMU nodes doesn't allow for any parent-child
> +	 * relationships anyway.  In other words, support for more than one
> +	 * PAMU node would require significant changes to a lot of code.
> +	 */
> +
> +	np =3D of_find_compatible_node(NULL, NULL, "fsl,pamu");
> +	if (!np) {
> +		pr_err("fsl-pamu: could not find a PAMU node\n");
> +		return -ENODEV;
> +	}
> +
> +	ret =3D platform_driver_register(&fsl_of_pamu_driver);
> +	if (ret) {
> +		pr_err("fsl-pamu: could not register driver (err=3D%i)\n",
> ret);
> +		goto error_driver_register;
> +	}
> +
> +	pdev =3D platform_device_alloc("fsl-of-pamu", 0);
> +	if (!pdev) {
> +		pr_err("fsl-pamu: could not allocate device %s\n",
> +		       np->full_name);
> +		ret =3D -ENOMEM;
> +		goto error_device_alloc;
> +	}
> +	pdev->dev.of_node =3D of_node_get(np);
> +
> +	ret =3D pamu_domain_init();
> +	if (ret)
> +		goto error_device_add;
> +
> +	ret =3D platform_device_add(pdev);
> +	if (ret) {
> +		pr_err("fsl-pamu: could not add device %s (err=3D%i)\n",
> +		       np->full_name, ret);
> +		goto error_device_add;
> +	}
> +
> +	return 0;
> +
> +error_device_add:
> +	of_node_put(pdev->dev.of_node);
> +	pdev->dev.of_node =3D NULL;
> +
> +	platform_device_put(pdev);
> +
> +error_device_alloc:
> +	platform_driver_unregister(&fsl_of_pamu_driver);
> +
> +error_driver_register:
> +	of_node_put(np);
> +
> +	return ret;
> +}
> +arch_initcall(fsl_pamu_init);
> diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
> new file mode 100644
> index 0000000..8fc1a12
> --- /dev/null
> +++ b/drivers/iommu/fsl_pamu.h
> @@ -0,0 +1,410 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License, version 2, as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
> USA.
> + *
> + * Copyright (C) 2013 Freescale Semiconductor, Inc.
> + *
> + */
> +
> +#ifndef __FSL_PAMU_H
> +#define __FSL_PAMU_H
> +
> +#include <asm/fsl_pamu_stash.h>
> +
> +/* Bit Field macros
> + *	v =3D bit field variable; m =3D mask, m##_SHIFT =3D shift, x =3D valu=
e to
> load
> + */
> +#define set_bf(v, m, x)		(v =3D ((v) & ~(m)) | (((x) <<
> (m##_SHIFT)) & (m)))
> +#define get_bf(v, m)		(((v) & (m)) >> (m##_SHIFT))
> +
> +/* PAMU CCSR space */
> +#define PAMU_PGC 0x00000000     /* Allows all peripheral accesses */
> +#define PAMU_PE 0x40000000      /* enable PAMU                    */
> +
> +/* PAMU_OFFSET to the next pamu space in ccsr */
> +#define PAMU_OFFSET 0x1000
> +
> +#define PAMU_MMAP_REGS_BASE 0
> +
> +struct pamu_mmap_regs {
> +	u32 ppbah;
> +	u32 ppbal;
> +	u32 pplah;
> +	u32 pplal;
> +	u32 spbah;
> +	u32 spbal;
> +	u32 splah;
> +	u32 splal;
> +	u32 obah;
> +	u32 obal;
> +	u32 olah;
> +	u32 olal;
> +};
> +
> +/* PAMU Error Registers */
> +#define PAMU_POES1 0x0040
> +#define PAMU_POES2 0x0044
> +#define PAMU_POEAH 0x0048
> +#define PAMU_POEAL 0x004C
> +#define PAMU_AVS1  0x0050
> +#define PAMU_AVS1_AV    0x1
> +#define PAMU_AVS1_OTV   0x6
> +#define PAMU_AVS1_APV   0x78
> +#define PAMU_AVS1_WAV   0x380
> +#define PAMU_AVS1_LAV   0x1c00
> +#define PAMU_AVS1_GCV   0x2000
> +#define PAMU_AVS1_PDV   0x4000
> +#define PAMU_AV_MASK    (PAMU_AVS1_AV | PAMU_AVS1_OTV | PAMU_AVS1_APV |
> PAMU_AVS1_WAV \
> +			| PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV)
> +#define PAMU_AVS1_LIODN_SHIFT 16
> +#define PAMU_LAV_LIODN_NOT_IN_PPAACT 0x400
> +
> +#define PAMU_AVS2  0x0054
> +#define PAMU_AVAH  0x0058
> +#define PAMU_AVAL  0x005C
> +#define PAMU_EECTL 0x0060
> +#define PAMU_EEDIS 0x0064
> +#define PAMU_EEINTEN 0x0068
> +#define PAMU_EEDET 0x006C
> +#define PAMU_EEATTR 0x0070
> +#define PAMU_EEAHI 0x0074
> +#define PAMU_EEALO 0x0078
> +#define PAMU_EEDHI 0X007C
> +#define PAMU_EEDLO 0x0080
> +#define PAMU_EECC  0x0084
> +#define PAMU_UDAD  0x0090
> +
> +/* PAMU Revision Registers */
> +#define PAMU_PR1 0x0BF8
> +#define PAMU_PR2 0x0BFC
> +
> +/* PAMU version mask */
> +#define PAMU_PR1_MASK 0xffff
> +
> +/* PAMU Capabilities Registers */
> +#define PAMU_PC1 0x0C00
> +#define PAMU_PC2 0x0C04
> +#define PAMU_PC3 0x0C08
> +#define PAMU_PC4 0x0C0C
> +
> +/* PAMU Control Register */
> +#define PAMU_PC 0x0C10
> +
> +/* PAMU control defs */
> +#define PAMU_CONTROL 0x0C10
> +#define PAMU_PC_PGC 0x80000000  /* PAMU gate closed bit */
> +#define PAMU_PC_PE   0x40000000 /* PAMU enable bit */
> +#define PAMU_PC_SPCC 0x00000010 /* sPAACE cache enable */
> +#define PAMU_PC_PPCC 0x00000001 /* pPAACE cache enable */
> +#define PAMU_PC_OCE  0x00001000 /* OMT cache enable */
> +
> +#define PAMU_PFA1 0x0C14
> +#define PAMU_PFA2 0x0C18
> +
> +#define PAMU_PC2_MLIODN(X) ((X) >> 16)
> +#define PAMU_PC3_MWCE(X) (((X) >> 21) & 0xf)
> +
> +/* PAMU Interrupt control and Status Register */
> +#define PAMU_PICS 0x0C1C
> +#define PAMU_ACCESS_VIOLATION_STAT   0x8
> +#define PAMU_ACCESS_VIOLATION_ENABLE 0x4
> +
> +/* PAMU Debug Registers */
> +#define PAMU_PD1 0x0F00
> +#define PAMU_PD2 0x0F04
> +#define PAMU_PD3 0x0F08
> +#define PAMU_PD4 0x0F0C
> +
> +#define PAACE_AP_PERMS_DENIED  0x0
> +#define PAACE_AP_PERMS_QUERY   0x1
> +#define PAACE_AP_PERMS_UPDATE  0x2
> +#define PAACE_AP_PERMS_ALL     0x3
> +
> +#define PAACE_DD_TO_HOST       0x0
> +#define PAACE_DD_TO_IO         0x1
> +#define PAACE_PT_PRIMARY       0x0
> +#define PAACE_PT_SECONDARY     0x1
> +#define PAACE_V_INVALID        0x0
> +#define PAACE_V_VALID          0x1
> +#define PAACE_MW_SUBWINDOWS    0x1
> +
> +#define PAACE_WSE_4K           0xB
> +#define PAACE_WSE_8K           0xC
> +#define PAACE_WSE_16K          0xD
> +#define PAACE_WSE_32K          0xE
> +#define PAACE_WSE_64K          0xF
> +#define PAACE_WSE_128K         0x10
> +#define PAACE_WSE_256K         0x11
> +#define PAACE_WSE_512K         0x12
> +#define PAACE_WSE_1M           0x13
> +#define PAACE_WSE_2M           0x14
> +#define PAACE_WSE_4M           0x15
> +#define PAACE_WSE_8M           0x16
> +#define PAACE_WSE_16M          0x17
> +#define PAACE_WSE_32M          0x18
> +#define PAACE_WSE_64M          0x19
> +#define PAACE_WSE_128M         0x1A
> +#define PAACE_WSE_256M         0x1B
> +#define PAACE_WSE_512M         0x1C
> +#define PAACE_WSE_1G           0x1D
> +#define PAACE_WSE_2G           0x1E
> +#define PAACE_WSE_4G           0x1F
> +
> +#define PAACE_DID_PCI_EXPRESS_1 0x00
> +#define PAACE_DID_PCI_EXPRESS_2 0x01
> +#define PAACE_DID_PCI_EXPRESS_3 0x02
> +#define PAACE_DID_PCI_EXPRESS_4 0x03
> +#define PAACE_DID_LOCAL_BUS     0x04
> +#define PAACE_DID_SRIO          0x0C
> +#define PAACE_DID_MEM_1         0x10
> +#define PAACE_DID_MEM_2         0x11
> +#define PAACE_DID_MEM_3         0x12
> +#define PAACE_DID_MEM_4         0x13
> +#define PAACE_DID_MEM_1_2       0x14
> +#define PAACE_DID_MEM_3_4       0x15
> +#define PAACE_DID_MEM_1_4       0x16
> +#define PAACE_DID_BM_SW_PORTAL  0x18
> +#define PAACE_DID_PAMU          0x1C
> +#define PAACE_DID_CAAM          0x21
> +#define PAACE_DID_QM_SW_PORTAL  0x3C
> +#define PAACE_DID_CORE0_INST    0x80
> +#define PAACE_DID_CORE0_DATA    0x81
> +#define PAACE_DID_CORE1_INST    0x82
> +#define PAACE_DID_CORE1_DATA    0x83
> +#define PAACE_DID_CORE2_INST    0x84
> +#define PAACE_DID_CORE2_DATA    0x85
> +#define PAACE_DID_CORE3_INST    0x86
> +#define PAACE_DID_CORE3_DATA    0x87
> +#define PAACE_DID_CORE4_INST    0x88
> +#define PAACE_DID_CORE4_DATA    0x89
> +#define PAACE_DID_CORE5_INST    0x8A
> +#define PAACE_DID_CORE5_DATA    0x8B
> +#define PAACE_DID_CORE6_INST    0x8C
> +#define PAACE_DID_CORE6_DATA    0x8D
> +#define PAACE_DID_CORE7_INST    0x8E
> +#define PAACE_DID_CORE7_DATA    0x8F
> +#define PAACE_DID_BROADCAST     0xFF
> +
> +#define PAACE_ATM_NO_XLATE      0x00
> +#define PAACE_ATM_WINDOW_XLATE  0x01
> +#define PAACE_ATM_PAGE_XLATE    0x02
> +#define PAACE_ATM_WIN_PG_XLATE  \
> +                (PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE)
> +#define PAACE_OTM_NO_XLATE      0x00
> +#define PAACE_OTM_IMMEDIATE     0x01
> +#define PAACE_OTM_INDEXED       0x02
> +#define PAACE_OTM_RESERVED      0x03
> +
> +#define PAACE_M_COHERENCE_REQ   0x01
> +
> +#define PAACE_PID_0             0x0
> +#define PAACE_PID_1             0x1
> +#define PAACE_PID_2             0x2
> +#define PAACE_PID_3             0x3
> +#define PAACE_PID_4             0x4
> +#define PAACE_PID_5             0x5
> +#define PAACE_PID_6             0x6
> +#define PAACE_PID_7             0x7
> +
> +#define PAACE_TCEF_FORMAT0_8B   0x00
> +#define PAACE_TCEF_FORMAT1_RSVD 0x01
> +/*
> + * Hard coded value for the PAACT size to accomodate
> + * maximum LIODN value generated by u-boot.
> + */
> +#define PAACE_NUMBER_ENTRIES    0x500
> +/* Hard coded value for the SPAACT size */
> +#define SPAACE_NUMBER_ENTRIES	0x800
> +
> +#define	OME_NUMBER_ENTRIES      16
> +
> +/* PAACE Bit Field Defines */
> +#define PPAACE_AF_WBAL			0xfffff000
> +#define PPAACE_AF_WBAL_SHIFT		12
> +#define PPAACE_AF_WSE			0x00000fc0
> +#define PPAACE_AF_WSE_SHIFT		6
> +#define PPAACE_AF_MW			0x00000020
> +#define PPAACE_AF_MW_SHIFT		5
> +
> +#define SPAACE_AF_LIODN			0xffff0000
> +#define SPAACE_AF_LIODN_SHIFT		16
> +
> +#define PAACE_AF_AP			0x00000018
> +#define PAACE_AF_AP_SHIFT		3
> +#define PAACE_AF_DD			0x00000004
> +#define PAACE_AF_DD_SHIFT		2
> +#define PAACE_AF_PT			0x00000002
> +#define PAACE_AF_PT_SHIFT		1
> +#define PAACE_AF_V			0x00000001
> +#define PAACE_AF_V_SHIFT		0
> +
> +#define PAACE_DA_HOST_CR		0x80
> +#define PAACE_DA_HOST_CR_SHIFT		7
> +
> +#define PAACE_IA_CID			0x00FF0000
> +#define PAACE_IA_CID_SHIFT		16
> +#define PAACE_IA_WCE			0x000000F0
> +#define PAACE_IA_WCE_SHIFT		4
> +#define PAACE_IA_ATM			0x0000000C
> +#define PAACE_IA_ATM_SHIFT		2
> +#define PAACE_IA_OTM			0x00000003
> +#define PAACE_IA_OTM_SHIFT		0
> +
> +#define PAACE_WIN_TWBAL			0xfffff000
> +#define PAACE_WIN_TWBAL_SHIFT		12
> +#define PAACE_WIN_SWSE			0x00000fc0
> +#define PAACE_WIN_SWSE_SHIFT		6
> +
> +/* PAMU Data Structures */
> +/* primary / secondary paact structure */
> +struct paace {
> +	/* PAACE Offset 0x00 */
> +	u32 wbah;				/* only valid for Primary PAACE */
> +	u32 addr_bitfields;		/* See P/S PAACE_AF_* */
> +
> +	/* PAACE Offset 0x08 */
> +	/* Interpretation of first 32 bits dependent on DD above */
> +	union {
> +		struct {
> +			/* Destination ID, see PAACE_DID_* defines */
> +			u8 did;
> +			/* Partition ID */
> +			u8 pid;
> +			/* Snoop ID */
> +			u8 snpid;
> +			/* coherency_required : 1 reserved : 7 */
> +			u8 coherency_required; /* See PAACE_DA_* */
> +		} to_host;
> +		struct {
> +			/* Destination ID, see PAACE_DID_* defines */
> +			u8  did;
> +			u8  reserved1;
> +			u16 reserved2;
> +		} to_io;
> +	} domain_attr;
> +
> +	/* Implementation attributes + window count + address & operation
> translation modes */
> +	u32 impl_attr;			/* See PAACE_IA_* */
> +
> +	/* PAACE Offset 0x10 */
> +	/* Translated window base address */
> +	u32 twbah;
> +	u32 win_bitfields;			/* See PAACE_WIN_* */
> +
> +	/* PAACE Offset 0x18 */
> +	/* first secondary paace entry */
> +	u32 fspi;				/* only valid for Primary PAACE */
> +	union {
> +		struct {
> +			u8 ioea;
> +			u8 moea;
> +			u8 ioeb;
> +			u8 moeb;
> +		} immed_ot;
> +		struct {
> +			u16 reserved;
> +			u16 omi;
> +		} index_ot;
> +	} op_encode;
> +
> +	/* PAACE Offsets 0x20-0x38 */
> +	u32 reserved[8];			/* not currently implemented */
> +};
> +
> +/* OME : Operation mapping entry
> + * MOE : Mapped Operation Encodings
> + * The operation mapping table is table containing operation mapping
> entries (OME).
> + * The index of a particular OME is programmed in the PAACE entry for
> translation
> + * in bound I/O operations corresponding to an LIODN. The OMT is used
> for translation
> + * specifically in case of the indexed translation mode. Each OME
> contains a 128
> + * byte mapped operation encoding (MOE), where each byte represents an
> MOE.
> + */
> +#define NUM_MOE 128
> +struct ome {
> +	u8 moe[NUM_MOE];
> +} __attribute__((packed));
> +
> +#define PAACT_SIZE              (sizeof(struct paace) *
> PAACE_NUMBER_ENTRIES)
> +#define SPAACT_SIZE              (sizeof(struct paace) *
> SPAACE_NUMBER_ENTRIES)
> +#define OMT_SIZE                (sizeof(struct ome) *
> OME_NUMBER_ENTRIES)
> +
> +#define PAMU_PAGE_SHIFT 12
> +#define PAMU_PAGE_SIZE  4096ULL
> +
> +#define IOE_READ        0x00
> +#define IOE_READ_IDX    0x00
> +#define IOE_WRITE       0x81
> +#define IOE_WRITE_IDX   0x01
> +#define IOE_EREAD0      0x82    /* Enhanced read type 0 */
> +#define IOE_EREAD0_IDX  0x02    /* Enhanced read type 0 */
> +#define IOE_EWRITE0     0x83    /* Enhanced write type 0 */
> +#define IOE_EWRITE0_IDX 0x03    /* Enhanced write type 0 */
> +#define IOE_DIRECT0     0x84    /* Directive type 0 */
> +#define IOE_DIRECT0_IDX 0x04    /* Directive type 0 */
> +#define IOE_EREAD1      0x85    /* Enhanced read type 1 */
> +#define IOE_EREAD1_IDX  0x05    /* Enhanced read type 1 */
> +#define IOE_EWRITE1     0x86    /* Enhanced write type 1 */
> +#define IOE_EWRITE1_IDX 0x06    /* Enhanced write type 1 */
> +#define IOE_DIRECT1     0x87    /* Directive type 1 */
> +#define IOE_DIRECT1_IDX 0x07    /* Directive type 1 */
> +#define IOE_RAC         0x8c    /* Read with Atomic clear */
> +#define IOE_RAC_IDX     0x0c    /* Read with Atomic clear */
> +#define IOE_RAS         0x8d    /* Read with Atomic set */
> +#define IOE_RAS_IDX     0x0d    /* Read with Atomic set */
> +#define IOE_RAD         0x8e    /* Read with Atomic decrement */
> +#define IOE_RAD_IDX     0x0e    /* Read with Atomic decrement */
> +#define IOE_RAI         0x8f    /* Read with Atomic increment */
> +#define IOE_RAI_IDX     0x0f    /* Read with Atomic increment */
> +
> +#define EOE_READ        0x00
> +#define EOE_WRITE       0x01
> +#define EOE_RAC         0x0c    /* Read with Atomic clear */
> +#define EOE_RAS         0x0d    /* Read with Atomic set */
> +#define EOE_RAD         0x0e    /* Read with Atomic decrement */
> +#define EOE_RAI         0x0f    /* Read with Atomic increment */
> +#define EOE_LDEC        0x10    /* Load external cache */
> +#define EOE_LDECL       0x11    /* Load external cache with stash lock
> */
> +#define EOE_LDECPE      0x12    /* Load external cache with preferred
> exclusive */
> +#define EOE_LDECPEL     0x13    /* Load external cache with preferred
> exclusive and lock */
> +#define EOE_LDECFE      0x14    /* Load external cache with forced
> exclusive */
> +#define EOE_LDECFEL     0x15    /* Load external cache with forced
> exclusive and lock */
> +#define EOE_RSA         0x16    /* Read with stash allocate */
> +#define EOE_RSAU        0x17    /* Read with stash allocate and unlock
> */
> +#define EOE_READI       0x18    /* Read with invalidate */
> +#define EOE_RWNITC      0x19    /* Read with no intention to cache */
> +#define EOE_WCI         0x1a    /* Write cache inhibited */
> +#define EOE_WWSA        0x1b    /* Write with stash allocate */
> +#define EOE_WWSAL       0x1c    /* Write with stash allocate and lock */
> +#define EOE_WWSAO       0x1d    /* Write with stash allocate only */
> +#define EOE_WWSAOL      0x1e    /* Write with stash allocate only and
> lock */
> +#define EOE_VALID       0x80
> +
> +/* Function prototypes */
> +int pamu_domain_init(void);
> +int pamu_enable_liodn(int liodn);
> +int pamu_disable_liodn(int liodn);
> +void pamu_free_subwins(int liodn);
> +int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t
> win_size,
> +		       u32 omi, unsigned long rpn, u32 snoopid, uint32_t
> stashid,
> +		       u32 subwin_cnt, int prot);
> +int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin_addr,
> +		       phys_addr_t subwin_size, u32 omi, unsigned long rpn,
> +		       uint32_t snoopid, u32 stashid, int enable, int prot);
> +
> +u32 get_stash_id(u32 stash_dest_hint, u32 vcpu);
> +void get_ome_index(u32 *omi_index, struct device *dev);
> +int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value);
> +int pamu_disable_spaace(int liodn, u32 subwin);
> +u32 pamu_get_max_subwin_cnt(void);
> +
> +#endif  /* __FSL_PAMU_H */
> diff --git a/drivers/iommu/fsl_pamu_domain.c
> b/drivers/iommu/fsl_pamu_domain.c
> new file mode 100644
> index 0000000..14d803a
> --- /dev/null
> +++ b/drivers/iommu/fsl_pamu_domain.c
> @@ -0,0 +1,1172 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License, version 2, as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
> USA.
> + *
> + * Copyright (C) 2013 Freescale Semiconductor, Inc.
> + * Author: Varun Sethi <varun.sethi@freescale.com>
> + *
> + */
> +
> +#define pr_fmt(fmt)    "fsl-pamu-domain: %s: " fmt, __func__
> +
> +#include <linux/init.h>
> +#include <linux/iommu.h>
> +#include <linux/notifier.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/of_platform.h>
> +#include <linux/bootmem.h>
> +#include <linux/err.h>
> +#include <asm/io.h>
> +#include <asm/bitops.h>
> +
> +#include <asm/pci-bridge.h>
> +#include <sysdev/fsl_pci.h>
> +
> +#include "fsl_pamu_domain.h"
> +#include "pci.h"
> +
> +/*
> + * Global spinlock that needs to be held while
> + * configuring PAMU.
> + */
> +static DEFINE_SPINLOCK(iommu_lock);
> +
> +static struct kmem_cache *fsl_pamu_domain_cache;
> +static struct kmem_cache *iommu_devinfo_cache;
> +static DEFINE_SPINLOCK(device_domain_lock);
> +
> +static int __init iommu_init_mempool(void)
> +{
> +
> +	fsl_pamu_domain_cache =3D kmem_cache_create("fsl_pamu_domain",
> +					 sizeof(struct fsl_dma_domain),
> +					 0,
> +					 SLAB_HWCACHE_ALIGN,
> +
> +					 NULL);
> +	if (!fsl_pamu_domain_cache) {
> +		pr_debug("Couldn't create fsl iommu_domain cache\n");
> +		return -ENOMEM;
> +	}
> +
> +	iommu_devinfo_cache =3D kmem_cache_create("iommu_devinfo",
> +					 sizeof(struct device_domain_info),
> +					 0,
> +					 SLAB_HWCACHE_ALIGN,
> +					 NULL);
> +	if (!iommu_devinfo_cache) {
> +		pr_debug("Couldn't create devinfo cache\n");
> +		kmem_cache_destroy(fsl_pamu_domain_cache);
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain,
> dma_addr_t iova)
> +{
> +	u32 win_cnt =3D dma_domain->win_cnt;
> +	struct dma_window *win_ptr =3D
> +				&dma_domain->win_arr[0];
> +	struct iommu_domain_geometry *geom;
> +
> +	geom =3D &dma_domain->iommu_domain->geometry;
> +
> +	if (!win_cnt || !dma_domain->geom_size) {
> +		pr_debug("Number of windows/geometry not configured for the
> domain\n");
> +		return 0;
> +	}
> +
> +	if (win_cnt > 1) {
> +		u64 subwin_size;
> +		dma_addr_t subwin_iova;
> +		u32 wnd;
> +
> +		subwin_size =3D dma_domain->geom_size >> ilog2(win_cnt);
> +		subwin_iova =3D iova & ~(subwin_size - 1);
> +		wnd =3D (subwin_iova - geom->aperture_start) >>
> ilog2(subwin_size);
> +		win_ptr =3D &dma_domain->win_arr[wnd];
> +	}
> +
> +	if (win_ptr->valid)
> +		return (win_ptr->paddr + (iova & (win_ptr->size - 1)));
> +
> +	return 0;
> +}
> +
> +static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain)
> +{
> +	struct dma_window *sub_win_ptr =3D
> +				&dma_domain->win_arr[0];
> +	int i, ret;
> +	unsigned long rpn, flags;
> +
> +	for (i =3D 0; i < dma_domain->win_cnt; i++) {
> +		if (sub_win_ptr[i].valid) {
> +			rpn =3D sub_win_ptr[i].paddr >>
> +				 PAMU_PAGE_SHIFT;
> +			spin_lock_irqsave(&iommu_lock, flags);
> +			ret =3D pamu_config_spaace(liodn, dma_domain->win_cnt, i,
> +						 sub_win_ptr[i].size,
> +						 ~(u32)0,
> +						 rpn,
> +						 dma_domain->snoop_id,
> +						 dma_domain->stash_id,
> +						 (i > 0) ? 1 : 0,
> +						 sub_win_ptr[i].prot);
> +			spin_unlock_irqrestore(&iommu_lock, flags);
> +			if (ret) {
> +				pr_debug("PAMU SPAACE configuration failed for
> liodn %d\n",
> +					 liodn);
> +				return ret;
> +			}
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int map_win(int liodn, struct fsl_dma_domain *dma_domain)
> +{
> +	int ret;
> +	struct dma_window *wnd =3D &dma_domain->win_arr[0];
> +	phys_addr_t wnd_addr =3D dma_domain->iommu_domain-
> >geometry.aperture_start;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&iommu_lock, flags);
> +	ret =3D pamu_config_ppaace(liodn, wnd_addr,
> +				 wnd->size,
> +				 ~(u32)0,
> +				 wnd->paddr >> PAMU_PAGE_SHIFT,
> +				 dma_domain->snoop_id, dma_domain->stash_id,
> +				 0, wnd->prot);
> +	spin_unlock_irqrestore(&iommu_lock, flags);
> +	if (ret)
> +		pr_debug("PAMU PAACE configuration failed for liodn %d\n",
> +			liodn);
> +
> +	return ret;
> +}
> +
> +/* Map the DMA window corresponding to the LIODN */
> +static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
> +{
> +	if (dma_domain->win_cnt > 1)
> +		return map_subwins(liodn, dma_domain);
> +	else
> +		return map_win(liodn, dma_domain);
> +
> +}
> +
> +/* Update window/subwindow mapping for the LIODN */
> +static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain,
> u32 wnd_nr)
> +{
> +	int ret;
> +	struct dma_window *wnd =3D &dma_domain->win_arr[wnd_nr];
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&iommu_lock, flags);
> +	if (dma_domain->win_cnt > 1) {
> +		ret =3D pamu_config_spaace(liodn, dma_domain->win_cnt, wnd_nr,
> +					 wnd->size,
> +					 ~(u32)0,
> +					 wnd->paddr >> PAMU_PAGE_SHIFT,
> +					 dma_domain->snoop_id,
> +					 dma_domain->stash_id,
> +					 (wnd_nr > 0) ? 1 : 0,
> +					 wnd->prot);
> +		if (ret)
> +			pr_debug("Subwindow reconfiguration failed for liodn
> %d\n", liodn);
> +	} else {
> +		phys_addr_t wnd_addr;
> +
> +		wnd_addr =3D dma_domain->iommu_domain->geometry.aperture_start;
> +
> +		ret =3D pamu_config_ppaace(liodn, wnd_addr,
> +					 wnd->size,
> +					 ~(u32)0,
> +					 wnd->paddr >> PAMU_PAGE_SHIFT,
> +					dma_domain->snoop_id, dma_domain->stash_id,
> +					0, wnd->prot);
> +		if (ret)
> +			pr_debug("Window reconfiguration failed for liodn
> %d\n", liodn);
> +	}
> +
> +	spin_unlock_irqrestore(&iommu_lock, flags);
> +
> +	return ret;
> +}
> +
> +static int update_liodn_stash(int liodn, struct fsl_dma_domain
> *dma_domain,
> +				 u32 val)
> +{
> +	int ret =3D 0, i;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&iommu_lock, flags);
> +	if (!dma_domain->win_arr) {
> +		pr_debug("Windows not configured, stash destination update
> failed for liodn %d\n", liodn);
> +		spin_unlock_irqrestore(&iommu_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	for (i =3D 0; i < dma_domain->win_cnt; i++) {
> +		ret =3D pamu_update_paace_stash(liodn, i, val);
> +		if (ret) {
> +			pr_debug("Failed to update SPAACE %d field for liodn
> %d\n ", i, liodn);
> +			spin_unlock_irqrestore(&iommu_lock, flags);
> +			return ret;
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&iommu_lock, flags);
> +
> +	return ret;
> +}
> +
> +/* Set the geometry parameters for a LIODN */
> +static int pamu_set_liodn(int liodn, struct device *dev,
> +			   struct fsl_dma_domain *dma_domain,
> +			   struct iommu_domain_geometry *geom_attr,
> +			   u32 win_cnt)
> +{
> +	phys_addr_t window_addr, window_size;
> +	phys_addr_t subwin_size;
> +	int ret =3D 0, i;
> +	u32 omi_index =3D ~(u32)0;
> +	unsigned long flags;
> +
> +	/*
> +	 * Configure the omi_index at the geometry setup time.
> +	 * This is a static value which depends on the type of
> +	 * device and would not change thereafter.
> +	 */
> +	get_ome_index(&omi_index, dev);
> +
> +	window_addr =3D geom_attr->aperture_start;
> +	window_size =3D dma_domain->geom_size;
> +
> +	spin_lock_irqsave(&iommu_lock, flags);
> +	ret =3D pamu_disable_liodn(liodn);
> +	if (!ret)
> +		ret =3D pamu_config_ppaace(liodn, window_addr, window_size,
> omi_index,
> +					 0, dma_domain->snoop_id,
> +					 dma_domain->stash_id, win_cnt, 0);
> +	spin_unlock_irqrestore(&iommu_lock, flags);
> +	if (ret) {
> +		pr_debug("PAMU PAACE configuration failed for liodn %d,
> win_cnt =3D%d\n", liodn, win_cnt);
> +		return ret;
> +	}
> +
> +	if (win_cnt > 1) {
> +		subwin_size =3D window_size >> ilog2(win_cnt);
> +		for (i =3D 0; i < win_cnt; i++) {
> +			spin_lock_irqsave(&iommu_lock, flags);
> +			ret =3D pamu_disable_spaace(liodn, i);
> +			if (!ret)
> +				ret =3D pamu_config_spaace(liodn, win_cnt, i,
> +							 subwin_size, omi_index,
> +							 0, dma_domain->snoop_id,
> +							 dma_domain->stash_id,
> +							 0, 0);
> +			spin_unlock_irqrestore(&iommu_lock, flags);
> +			if (ret) {
> +				pr_debug("PAMU SPAACE configuration failed for
> liodn %d\n", liodn);
> +				return ret;
> +			}
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int check_size(u64 size, dma_addr_t iova)
> +{
> +	/*
> +	 * Size must be a power of two and at least be equal
> +	 * to PAMU page size.
> +	 */
> +	if (!is_power_of_2(size) || size < PAMU_PAGE_SIZE) {
> +		pr_debug("%s: size too small or not a power of two\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* iova must be page size aligned*/
> +	if (iova & (size - 1)) {
> +		pr_debug("%s: address is not aligned with window size\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct fsl_dma_domain *iommu_alloc_dma_domain(void)
> +{
> +	struct fsl_dma_domain *domain;
> +
> +	domain =3D kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL);
> +	if (!domain)
> +		return NULL;
> +
> +	domain->stash_id =3D ~(u32)0;
> +	domain->snoop_id =3D ~(u32)0;
> +	domain->win_cnt =3D pamu_get_max_subwin_cnt();
> +	domain->geom_size =3D 0;
> +
> +	INIT_LIST_HEAD(&domain->devices);
> +
> +	spin_lock_init(&domain->domain_lock);
> +
> +	return domain;
> +}
> +
> +static inline struct device_domain_info *find_domain(struct device *dev)
> +{
> +	return dev->archdata.iommu_domain;
> +}
> +
> +static void remove_device_ref(struct device_domain_info *info, u32
> win_cnt)
> +{
> +	unsigned long flags;
> +
> +	list_del(&info->link);
> +	spin_lock_irqsave(&iommu_lock, flags);
> +	if (win_cnt > 1)
> +		pamu_free_subwins(info->liodn);
> +	pamu_disable_liodn(info->liodn);
> +	spin_unlock_irqrestore(&iommu_lock, flags);
> +	spin_lock_irqsave(&device_domain_lock, flags);
> +	info->dev->archdata.iommu_domain =3D NULL;
> +	kmem_cache_free(iommu_devinfo_cache, info);
> +	spin_unlock_irqrestore(&device_domain_lock, flags);
> +}
> +
> +static void detach_device(struct device *dev, struct fsl_dma_domain
> *dma_domain)
> +{
> +	struct device_domain_info *info, *tmp;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +	/* Remove the device from the domain device list */
> +	list_for_each_entry_safe(info, tmp, &dma_domain->devices, link) {
> +		if (!dev || (info->dev =3D=3D dev))
> +			remove_device_ref(info, dma_domain->win_cnt);
> +	}
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +}
> +
> +static void attach_device(struct fsl_dma_domain *dma_domain, int liodn,
> struct device *dev)
> +{
> +	struct device_domain_info *info, *old_domain_info;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&device_domain_lock, flags);
> +	/*
> +	 * Check here if the device is already attached to domain or not.
> +	 * If the device is already attached to a domain detach it.
> +	 */
> +	old_domain_info =3D find_domain(dev);
> +	if (old_domain_info && old_domain_info->domain !=3D dma_domain) {
> +		spin_unlock_irqrestore(&device_domain_lock, flags);
> +		detach_device(dev, old_domain_info->domain);
> +		spin_lock_irqsave(&device_domain_lock, flags);
> +	}
> +
> +	info =3D kmem_cache_zalloc(iommu_devinfo_cache, GFP_ATOMIC);
> +
> +	info->dev =3D dev;
> +	info->liodn =3D liodn;
> +	info->domain =3D dma_domain;
> +
> +	list_add(&info->link, &dma_domain->devices);
> +	/*
> +	 * In case of devices with multiple LIODNs just store
> +	 * the info for the first LIODN as all
> +	 * LIODNs share the same domain
> +	 */
> +	if (!old_domain_info)
> +		dev->archdata.iommu_domain =3D info;
> +	spin_unlock_irqrestore(&device_domain_lock, flags);
> +
> +}
> +
> +static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
> +					    dma_addr_t iova)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +
> +	if ((iova < domain->geometry.aperture_start) ||
> +		iova > (domain->geometry.aperture_end))
> +		return 0;
> +
> +	return get_phys_addr(dma_domain, iova);
> +}
> +
> +static int fsl_pamu_domain_has_cap(struct iommu_domain *domain,
> +				      unsigned long cap)
> +{
> +	return cap =3D=3D IOMMU_CAP_CACHE_COHERENCY;
> +}
> +
> +static void fsl_pamu_domain_destroy(struct iommu_domain *domain)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +
> +	domain->priv =3D NULL;
> +
> +	/* remove all the devices from the device list */
> +	detach_device(NULL, dma_domain);
> +
> +	dma_domain->enabled =3D 0;
> +	dma_domain->mapped =3D 0;
> +
> +	kmem_cache_free(fsl_pamu_domain_cache, dma_domain);
> +}
> +
> +static int fsl_pamu_domain_init(struct iommu_domain *domain)
> +{
> +	struct fsl_dma_domain *dma_domain;
> +
> +	dma_domain =3D iommu_alloc_dma_domain();
> +	if (!dma_domain) {
> +		pr_debug("dma_domain allocation failed\n");
> +		return -ENOMEM;
> +	}
> +	domain->priv =3D dma_domain;
> +	dma_domain->iommu_domain =3D domain;
> +	/* defaul geometry 64 GB i.e. maximum system address */
> +	domain->geometry.aperture_start =3D 0;
> +	domain->geometry.aperture_end =3D (1ULL << 36) - 1;
> +	domain->geometry.force_aperture =3D true;
> +
> +	return 0;
> +}
> +
> +/* Configure geometry settings for all LIODNs associated with domain */
> +static int pamu_set_domain_geometry(struct fsl_dma_domain *dma_domain,
> +				    struct iommu_domain_geometry *geom_attr,
> +				    u32 win_cnt)
> +{
> +	struct device_domain_info *info;
> +	int ret =3D 0;
> +
> +	list_for_each_entry(info, &dma_domain->devices, link) {
> +		ret =3D pamu_set_liodn(info->liodn, info->dev, dma_domain,
> +				      geom_attr, win_cnt);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* Update stash destination for all LIODNs associated with the domain */
> +static int update_domain_stash(struct fsl_dma_domain *dma_domain, u32
> val)
> +{
> +	struct device_domain_info *info;
> +	int ret =3D 0;
> +
> +	list_for_each_entry(info, &dma_domain->devices, link) {
> +		ret =3D update_liodn_stash(info->liodn, dma_domain, val);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* Update domain mappings for all LIODNs associated with the domain */
> +static int update_domain_mapping(struct fsl_dma_domain *dma_domain, u32
> wnd_nr)
> +{
> +	struct device_domain_info *info;
> +	int ret =3D 0;
> +
> +	list_for_each_entry(info, &dma_domain->devices, link) {
> +		ret =3D update_liodn(info->liodn, dma_domain, wnd_nr);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static int disable_domain_win(struct fsl_dma_domain *dma_domain, u32
> wnd_nr)
> +{
> +	struct device_domain_info *info;
> +	int ret =3D 0;
> +
> +	list_for_each_entry(info, &dma_domain->devices, link) {
> +		if (dma_domain->win_cnt =3D=3D 1 && dma_domain->enabled) {
> +			ret =3D pamu_disable_liodn(info->liodn);
> +			if (!ret)
> +				dma_domain->enabled =3D 0;
> +		} else {
> +			ret =3D pamu_disable_spaace(info->liodn, wnd_nr);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static void fsl_pamu_window_disable(struct iommu_domain *domain, u32
> wnd_nr)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +	if (!dma_domain->win_arr) {
> +		pr_debug("Number of windows not configured\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return;
> +	}
> +
> +	if (wnd_nr >=3D dma_domain->win_cnt) {
> +		pr_debug("Invalid window index\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return;
> +	}
> +
> +	if (dma_domain->win_arr[wnd_nr].valid) {
> +		ret =3D disable_domain_win(dma_domain, wnd_nr);
> +		if (!ret) {
> +			dma_domain->win_arr[wnd_nr].valid =3D 0;
> +			dma_domain->mapped--;
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +}
> +
> +static int fsl_pamu_window_enable(struct iommu_domain *domain, u32
> wnd_nr,
> +				  phys_addr_t paddr, u64 size, int prot)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	struct dma_window *wnd;
> +	int pamu_prot =3D 0;
> +	int ret;
> +	unsigned long flags;
> +	u64 win_size;
> +
> +	if (prot & IOMMU_READ)
> +		pamu_prot |=3D PAACE_AP_PERMS_QUERY;
> +	if (prot & IOMMU_WRITE)
> +		pamu_prot |=3D PAACE_AP_PERMS_UPDATE;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +	if (!dma_domain->win_arr) {
> +		pr_debug("Number of windows not configured\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -ENODEV;
> +	}
> +
> +	if (wnd_nr >=3D dma_domain->win_cnt) {
> +		pr_debug("Invalid window index\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	win_size =3D dma_domain->geom_size >> ilog2(dma_domain->win_cnt);
> +	if (size > win_size) {
> +		pr_debug("Invalid window size \n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	if (dma_domain->win_cnt =3D=3D 1) {
> +		if (dma_domain->enabled) {
> +			pr_debug("Disable the window before updating the
> mapping\n");
> +			spin_unlock_irqrestore(&dma_domain->domain_lock,
> flags);
> +			return -EBUSY;
> +		}
> +
> +		ret =3D check_size(size, domain->geometry.aperture_start);
> +		if (ret) {
> +			pr_debug("Aperture start not aligned to the size\n");
> +			spin_unlock_irqrestore(&dma_domain->domain_lock,
> flags);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	wnd =3D &dma_domain->win_arr[wnd_nr];
> +	if (!wnd->valid) {
> +		wnd->paddr =3D paddr;
> +		wnd->size =3D size;
> +		wnd->prot =3D pamu_prot;
> +
> +		ret =3D update_domain_mapping(dma_domain, wnd_nr);
> +		if (!ret) {
> +			wnd->valid =3D 1;
> +			dma_domain->mapped++;
> +		}
> +	} else {
> +		pr_debug("Disable the window before updating the mapping\n");
> +		ret =3D -EBUSY;
> +	}
> +
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +	return ret;
> +}
> +
> +/*
> + * Attach the LIODN to the DMA domain and configure the geometry
> + * and window mappings.
> + */
> +static int handle_attach_device(struct fsl_dma_domain *dma_domain,
> +				 struct device *dev, const u32 *liodn,
> +				 int num)
> +{
> +	unsigned long flags;
> +	struct iommu_domain *domain =3D dma_domain->iommu_domain;
> +	int ret =3D 0;
> +	int i;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +	for (i =3D 0; i < num; i++) {
> +
> +		/* Ensure that LIODN value is valid */
> +		if (liodn[i] >=3D PAACE_NUMBER_ENTRIES) {
> +			pr_debug("Invalid liodn %d, attach device failed for
> %s\n",
> +				liodn[i], dev->of_node->full_name);
> +			ret =3D -EINVAL;
> +			break;
> +		}
> +
> +		attach_device(dma_domain, liodn[i], dev);
> +		/*
> +		 * Check if geometry has already been configured
> +		 * for the domain. If yes, set the geometry for
> +		 * the LIODN.
> +		 */
> +		if (dma_domain->win_arr) {
> +			u32 win_cnt =3D dma_domain->win_cnt > 1 ? dma_domain-
> >win_cnt : 0;
> +			ret =3D pamu_set_liodn(liodn[i], dev, dma_domain,
> +					      &domain->geometry,
> +					      win_cnt);
> +			if (ret)
> +				break;
> +			if (dma_domain->mapped) {
> +				/*
> +				 * Create window/subwindow mapping for
> +				 * the LIODN.
> +				 */
> +				ret =3D map_liodn(liodn[i], dma_domain);
> +				if (ret)
> +					break;
> +			}
> +		}
> +	}
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +	return ret;
> +}
> +
> +static int fsl_pamu_attach_device(struct iommu_domain *domain,
> +				  struct device *dev)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	const u32 *liodn;
> +	u32 liodn_cnt;
> +	int len, ret =3D 0;
> +	struct pci_dev *pdev =3D NULL;
> +	struct pci_controller *pci_ctl;
> +
> +	/*
> +	 * Use LIODN of the PCI controller while attaching a
> +	 * PCI device.
> +	 */
> +	if (dev->bus =3D=3D &pci_bus_type) {
> +		pdev =3D to_pci_dev(dev);
> +		pci_ctl =3D pci_bus_to_host(pdev->bus);
> +		/*
> +		 * make dev point to pci controller device
> +		 * so we can get the LIODN programmed by
> +		 * u-boot.
> +		 */
> +		dev =3D pci_ctl->parent;
> +	}
> +
> +	liodn =3D of_get_property(dev->of_node, "fsl,liodn", &len);
> +	if (liodn) {
> +		liodn_cnt =3D len / sizeof(u32);
> +		ret =3D handle_attach_device(dma_domain, dev,
> +					 liodn, liodn_cnt);
> +	} else {
> +		pr_debug("missing fsl,liodn property at %s\n",
> +		          dev->of_node->full_name);
> +			ret =3D -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static void fsl_pamu_detach_device(struct iommu_domain *domain,
> +				      struct device *dev)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	const u32 *prop;
> +	int len;
> +	struct pci_dev *pdev =3D NULL;
> +	struct pci_controller *pci_ctl;
> +
> +	/*
> +	 * Use LIODN of the PCI controller while detaching a
> +	 * PCI device.
> +	 */
> +	if (dev->bus =3D=3D &pci_bus_type) {
> +		pdev =3D to_pci_dev(dev);
> +		pci_ctl =3D pci_bus_to_host(pdev->bus);
> +		/*
> +		 * make dev point to pci controller device
> +		 * so we can get the LIODN programmed by
> +		 * u-boot.
> +		 */
> +		dev =3D pci_ctl->parent;
> +	}
> +
> +	prop =3D of_get_property(dev->of_node, "fsl,liodn", &len);
> +	if (prop)
> +		detach_device(dev, dma_domain);
> +	else
> +		pr_debug("missing fsl,liodn property at %s\n",
> +		          dev->of_node->full_name);
> +}
> +
> +static  int configure_domain_geometry(struct iommu_domain *domain, void
> *data)
> +{
> +	struct iommu_domain_geometry *geom_attr =3D data;
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	dma_addr_t geom_size;
> +	unsigned long flags;
> +
> +	geom_size =3D geom_attr->aperture_end - geom_attr->aperture_start +
> 1;
> +	/*
> +	 * Sanity check the geometry size. Also, we do not support
> +	 * DMA outside of the geometry.
> +	 */
> +	if (check_size(geom_size, geom_attr->aperture_start) ||
> +		!geom_attr->force_aperture) {
> +			pr_debug("Invalid PAMU geometry attributes\n");
> +			return -EINVAL;
> +		}
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +	if (dma_domain->enabled) {
> +		pr_debug("Can't set geometry attributes as domain is
> active\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return  -EBUSY;
> +	}
> +
> +	/* Copy the domain geometry information */
> +	memcpy(&domain->geometry, geom_attr,
> +	       sizeof(struct iommu_domain_geometry));
> +	dma_domain->geom_size =3D geom_size;
> +
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +	return 0;
> +}
> +
> +/* Set the domain stash attribute */
> +static int configure_domain_stash(struct fsl_dma_domain *dma_domain,
> void *data)
> +{
> +	struct pamu_stash_attribute *stash_attr =3D data;
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +
> +	memcpy(&dma_domain->dma_stash, stash_attr,
> +		 sizeof(struct pamu_stash_attribute));
> +
> +	dma_domain->stash_id =3D get_stash_id(stash_attr->cache,
> +					    stash_attr->cpu);
> +	if (dma_domain->stash_id =3D=3D ~(u32)0) {
> +		pr_debug("Invalid stash attributes\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	ret =3D update_domain_stash(dma_domain, dma_domain->stash_id);
> +
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +	return ret;
> +}
> +
> +/* Configure domain dma state i.e. enable/disable DMA*/
> +static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain,
> bool enable)
> +{
> +	struct device_domain_info *info;
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +
> +	if (enable && !dma_domain->mapped) {
> +		pr_debug("Can't enable DMA domain without valid mapping\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -ENODEV;
> +	}
> +
> +	dma_domain->enabled =3D enable;
> +	list_for_each_entry(info, &dma_domain->devices,
> +				 link) {
> +		ret =3D (enable) ? pamu_enable_liodn(info->liodn) :
> +			pamu_disable_liodn(info->liodn);
> +		if (ret)
> +			pr_debug("Unable to set dma state for liodn %d",
> +				 info->liodn);
> +	}
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +	return 0;
> +}
> +
> +static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
> +				 enum iommu_attr attr_type, void *data)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	int ret =3D 0;
> +
> +
> +	switch (attr_type) {
> +	case DOMAIN_ATTR_GEOMETRY:
> +		ret =3D configure_domain_geometry(domain, data);
> +		break;
> +	case DOMAIN_ATTR_FSL_PAMU_STASH:
> +		ret =3D configure_domain_stash(dma_domain, data);
> +		break;
> +	case DOMAIN_ATTR_FSL_PAMU_ENABLE:
> +		ret =3D configure_domain_dma_state(dma_domain, *(int *)data);
> +		break;
> +	default:
> +		pr_debug("Unsupported attribute type\n");
> +		ret =3D -EINVAL;
> +		break;
> +	};
> +
> +	return ret;
> +}
> +
> +static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
> +				 enum iommu_attr attr_type, void *data)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	int ret =3D 0;
> +
> +
> +	switch (attr_type) {
> +	case DOMAIN_ATTR_FSL_PAMU_STASH:
> +		memcpy((struct pamu_stash_attribute *) data, &dma_domain-
> >dma_stash,
> +				 sizeof(struct pamu_stash_attribute));
> +		break;
> +	case DOMAIN_ATTR_FSL_PAMU_ENABLE:
> +		*(int *)data =3D dma_domain->enabled;
> +		break;
> +	case DOMAIN_ATTR_FSL_PAMUV1:
> +		*(int *)data =3D DOMAIN_ATTR_FSL_PAMUV1;
> +		break;
> +	default:
> +		pr_debug("Unsupported attribute type\n");
> +		ret =3D -EINVAL;
> +		break;
> +	};
> +
> +	return ret;
> +}
> +
> +#define REQ_ACS_FLAGS	(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
> PCI_ACS_UF)
> +
> +static struct iommu_group *get_device_iommu_group(struct device *dev)
> +{
> +	struct iommu_group *group;
> +
> +	group =3D iommu_group_get(dev);
> +	if (!group)
> +		group =3D iommu_group_alloc();
> +
> +	return group;
> +}
> +
> +static  bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl)
> +{
> +	u32 version;
> +
> +	/* Check the PCI controller version number by readding BRR1
> register */
> +	version =3D in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2));
> +	version &=3D PCI_FSL_BRR1_VER;
> +	/* If PCI controller version is >=3D 0x204 we can partition
> endpoints*/
> +	if (version >=3D 0x204)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +/* Get iommu group information from peer devices or devices on the
> parent bus */
> +static struct iommu_group *get_shared_pci_device_group(struct pci_dev
> *pdev)
> +{
> +	struct pci_dev *tmp;
> +	struct iommu_group *group;
> +	struct pci_bus *bus =3D pdev->bus;
> +
> +	/*
> +	 * Traverese the pci bus device list to get
> +	 * the shared iommu group.
> +	 */
> +	while (bus) {
> +		list_for_each_entry(tmp, &bus->devices, bus_list) {
> +			if (tmp =3D=3D pdev)
> +				continue;
> +			group =3D iommu_group_get(&tmp->dev);
> +			if (group)
> +				return group;
> +		}
> +
> +		bus =3D bus->parent;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct iommu_group *get_pci_device_group(struct pci_dev *pdev)
> +{
> +	struct pci_controller *pci_ctl;
> +	bool pci_endpt_partioning;
> +	struct iommu_group *group =3D NULL;
> +	struct pci_dev *bridge, *dma_pdev =3D NULL;
> +
> +	pci_ctl =3D pci_bus_to_host(pdev->bus);
> +	pci_endpt_partioning =3D check_pci_ctl_endpt_part(pci_ctl);
> +	/* We can partition PCIe devices so assign device group to the
> device */
> +	if (pci_endpt_partioning) {
> +		bridge =3D pci_find_upstream_pcie_bridge(pdev);
> +		if (bridge) {
> +			if (pci_is_pcie(bridge))
> +				dma_pdev =3D pci_get_domain_bus_and_slot(
> +						pci_domain_nr(pdev->bus),
> +						bridge->subordinate->number, 0);
> +			if (!dma_pdev)
> +				dma_pdev =3D pci_dev_get(bridge);
> +		} else
> +			dma_pdev =3D pci_dev_get(pdev);
> +
> +		/* Account for quirked devices */
> +		swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
> +
> +		/*
> +		 * If it's a multifunction device that does not support our
> +		 * required ACS flags, add to the same group as lowest
> numbered
> +		 * function that also does not suport the required ACS flags.
> +		 */
> +		if (dma_pdev->multifunction &&
> +		    !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
> +			u8 i, slot =3D PCI_SLOT(dma_pdev->devfn);
> +
> +			for (i =3D 0; i < 8; i++) {
> +				struct pci_dev *tmp;
> +
> +				tmp =3D pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot,
> i));
> +				if (!tmp)
> +					continue;
> +
> +				if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
> +					swap_pci_ref(&dma_pdev, tmp);
> +					break;
> +				}
> +				pci_dev_put(tmp);
> +			}
> +		}
> +
> +		/*
> +		 * Devices on the root bus go through the iommu.  If that's
> not us,
> +	 	 * find the next upstream device and test ACS up to the root
> bus.
> +		 * Finding the next device may require skipping virtual
> buses.
> +		 */
> +		while (!pci_is_root_bus(dma_pdev->bus)) {
> +			struct pci_bus *bus =3D dma_pdev->bus;
> +
> +			while (!bus->self) {
> +				if (!pci_is_root_bus(bus))
> +					bus =3D bus->parent;
> +				else
> +					goto root_bus;
> +			}
> +
> +			if (pci_acs_path_enabled(bus->self, NULL,
> REQ_ACS_FLAGS))
> +				break;
> +
> +			swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
> +		}
> +
> +root_bus:
> +		group =3D get_device_iommu_group(&dma_pdev->dev);
> +		pci_dev_put(dma_pdev);
> +		/*
> +		 * PCIe controller is not a paritionable entity
> +		 * free the controller device iommu_group.
> +		 */
> +		if (pci_ctl->parent->iommu_group)
> +			iommu_group_remove_device(pci_ctl->parent);
> +	} else {
> +		/*
> +		 * All devices connected to the controller will share the
> +		 * PCI controllers device group. If this is the first
> +		 * device to be probed for the pci controller, copy the
> +		 * device group information from the PCI controller device
> +		 * node and remove the PCI controller iommu group.
> +		 * For subsequent devices, the iommu group information can
> +		 * be obtained from sibling devices (i.e. from the
> bus_devices
> +		 * link list).
> +		 */
> +		if (pci_ctl->parent->iommu_group) {
> +			group =3D get_device_iommu_group(pci_ctl->parent);
> +			iommu_group_remove_device(pci_ctl->parent);
> +		} else
> +			group =3D get_shared_pci_device_group(pdev);
> +	}
> +
> +	return group;
> +}
> +
> +static int fsl_pamu_add_device(struct device *dev)
> +{
> +	struct iommu_group *group =3D NULL;
> +	struct pci_dev *pdev;
> +	const u32 *prop;
> +	int ret, len;
> +
> +	/*
> +	 * For platform devices we allocate a separate group for
> +	 * each of the devices.
> +	 */
> +	if (dev->bus =3D=3D &pci_bus_type) {
> +		pdev =3D to_pci_dev(dev);
> +		/* Don't create device groups for virtual PCI bridges */
> +		if (pdev->subordinate)
> +			return 0;
> +
> +		group =3D get_pci_device_group(pdev);
> +
> +	} else {
> +		prop =3D of_get_property(dev->of_node, "fsl,liodn", &len);
> +		if (prop)
> +			group =3D get_device_iommu_group(dev);
> +	}
> +
> +	if (!group || IS_ERR(group))
> +		return PTR_ERR(group);
> +
> +	ret =3D iommu_group_add_device(group, dev);
> +
> +	iommu_group_put(group);
> +	return ret;
> +}
> +
> +static void fsl_pamu_remove_device(struct device *dev)
> +{
> +	iommu_group_remove_device(dev);
> +}
> +
> +static int fsl_pamu_set_windows(struct iommu_domain *domain, u32
> w_count)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(&dma_domain->domain_lock, flags);
> +	/* Ensure domain is inactive i.e. DMA should be disabled for the
> domain */
> +	if (dma_domain->enabled) {
> +		pr_debug("Can't set geometry attributes as domain is
> active\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return  -EBUSY;
> +	}
> +
> +	/* Ensure that the geometry has been set for the domain */
> +	if (!dma_domain->geom_size) {
> +		pr_debug("Please configure geometry before setting the number
> of windows\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Ensure we have valid window count i.e. it should be less than
> +	 * maximum permissible limit and should be a power of two.
> +	 */
> +	if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count))
> {
> +		pr_debug("Invalid window count\n");
> +		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	ret =3D pamu_set_domain_geometry(dma_domain, &domain->geometry,
> +				((w_count > 1) ? w_count : 0));
> +	if (!ret) {
> +		if (dma_domain->win_arr)
> +			kfree(dma_domain->win_arr);
> +		dma_domain->win_arr =3D kzalloc(sizeof(struct dma_window) *
> +							  w_count, GFP_ATOMIC);
> +		if (!dma_domain->win_arr) {
> +			spin_unlock_irqrestore(&dma_domain->domain_lock,
> flags);
> +			return -ENOMEM;
> +		}
> +		dma_domain->win_cnt =3D w_count;
> +	}
> +	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
> +
> +	return ret;
> +}
> +
> +static u32 fsl_pamu_get_windows(struct iommu_domain *domain)
> +{
> +	struct fsl_dma_domain *dma_domain =3D domain->priv;
> +
> +	return dma_domain->win_cnt;
> +}
> +
> +static struct iommu_ops fsl_pamu_ops =3D {
> +	.domain_init	=3D fsl_pamu_domain_init,
> +	.domain_destroy =3D fsl_pamu_domain_destroy,
> +	.attach_dev	=3D fsl_pamu_attach_device,
> +	.detach_dev	=3D fsl_pamu_detach_device,
> +	.domain_window_enable =3D fsl_pamu_window_enable,
> +	.domain_window_disable =3D fsl_pamu_window_disable,
> +	.domain_get_windows =3D fsl_pamu_get_windows,
> +	.domain_set_windows =3D fsl_pamu_set_windows,
> +	.iova_to_phys	=3D fsl_pamu_iova_to_phys,
> +	.domain_has_cap =3D fsl_pamu_domain_has_cap,
> +	.domain_set_attr =3D fsl_pamu_set_domain_attr,
> +	.domain_get_attr =3D fsl_pamu_get_domain_attr,
> +	.add_device	=3D fsl_pamu_add_device,
> +	.remove_device	=3D fsl_pamu_remove_device,
> +};
> +
> +int pamu_domain_init()
> +{
> +	int ret =3D 0;
> +
> +	ret =3D iommu_init_mempool();
> +	if (ret)
> +		return ret;
> +
> +	bus_set_iommu(&platform_bus_type, &fsl_pamu_ops);
> +	bus_set_iommu(&pci_bus_type, &fsl_pamu_ops);
> +
> +	return ret;
> +}
> diff --git a/drivers/iommu/fsl_pamu_domain.h
> b/drivers/iommu/fsl_pamu_domain.h
> new file mode 100644
> index 0000000..c90293f
> --- /dev/null
> +++ b/drivers/iommu/fsl_pamu_domain.h
> @@ -0,0 +1,85 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License, version 2, as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
> USA.
> + *
> + * Copyright (C) 2013 Freescale Semiconductor, Inc.
> + *
> + */
> +
> +#ifndef __FSL_PAMU_DOMAIN_H
> +#define __FSL_PAMU_DOMAIN_H
> +
> +#include "fsl_pamu.h"
> +
> +struct dma_window {
> +	phys_addr_t paddr;
> +	u64 size;
> +	int valid;
> +	int prot;
> +};
> +
> +struct fsl_dma_domain {
> +	/*
> +	 * Indicates the geometry size for the domain.
> +	 * This would be set when the geometry is
> +	 * configured for the domain.
> +	 */
> +	dma_addr_t			geom_size;
> +	/*
> +	 * Number of windows assocaited with this domain.
> +	 * During domain initialization, it is set to the
> +	 * the maximum number of subwindows allowed for a LIODN.
> +	 * Minimum value for this is 1 indicating a single PAMU
> +	 * window, without any sub windows. Value can be set/
> +	 * queried by set_attr/get_attr API for DOMAIN_ATTR_WINDOWS.
> +	 * Value can only be set once the geometry has been configured.
> +	 */
> +	u32				win_cnt;
> +	/*
> +	 * win_arr contains information of the configured
> +	 * windows for a domain. This is allocated only
> +	 * when the number of windows for the domain are
> +	 * set.
> +	 */
> +	struct dma_window		*win_arr;
> +	/* list of devices associated with the domain */
> +	struct list_head		devices;
> +	/* dma_domain states:
> +	 * mapped - A particular mapping has been created
> +	 * within the configured geometry.
> +	 * enabled - DMA has been enabled for the given
> +	 * domain. This translates to setting of the
> +	 * valid bit for the primary PAACE in the PAMU
> +	 * PAACT table. Domain geometry should be set and
> +	 * it must have a valid mapping before DMA can be
> +	 * enabled for it.
> +	 *
> +	 */
> +	int				mapped;
> +	int				enabled;
> +	/* stash_id obtained from the stash attribute details */
> +	u32				stash_id;
> +	struct pamu_stash_attribute	dma_stash;
> +	u32				snoop_id;
> +	struct iommu_domain		*iommu_domain;
> +	spinlock_t			domain_lock;
> +};
> +
> +/* domain-device relationship */
> +struct device_domain_info {
> +	struct list_head link;	/* link to domain siblings */
> +	struct device *dev;
> +	u32 liodn;
> +	struct fsl_dma_domain *domain; /* pointer to domain */
> +};
> +#endif  /* __FSL_PAMU_DOMAIN_H */
> --
> 1.7.4.1

^ permalink raw reply

* Re: [PATCH 2/3] cpuidle/powernv: Enable idle powernv cpu to call into the cpuidle framework.
From: Deepthi Dharwar @ 2013-07-29 14:27 UTC (permalink / raw)
  To: Daniel Lezcano; +Cc: linux-pm, linuxppc-dev, linux-kernel
In-Reply-To: <51F35AC7.8060909@linaro.org>

On 07/27/2013 10:59 AM, Daniel Lezcano wrote:
> On 07/23/2013 11:01 AM, Deepthi Dharwar wrote:
>> This patch enables idle powernv cpu to hook on to the cpuidle
>> framework, if available, else call on to default idle platform
>> code.
> 
> Why do you need to do that ?
> 

Hi Daniel,

Well, this is needed in case when one does not compile with CPU_IDLE
config option.

When CPUIDLE is not configured, idle cpus are needed to be running some
sort of default idle code or loop ( in the worst case) if cpuidle driver
is not registered or if one decides not to have that config enabled.

Regards,
Deepthi

> 
>> Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
>> ---
>>  arch/powerpc/platforms/powernv/setup.c |   12 +++++++++++-
>>  1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
>> index 84438af..97d0951 100644
>> --- a/arch/powerpc/platforms/powernv/setup.c
>> +++ b/arch/powerpc/platforms/powernv/setup.c
>> @@ -25,6 +25,7 @@
>>  #include <linux/of.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/bug.h>
>> +#include <linux/cpuidle.h>
>>  
>>  #include <asm/machdep.h>
>>  #include <asm/firmware.h>
>> @@ -196,6 +197,15 @@ static int __init pnv_probe(void)
>>  	return 1;
>>  }
>>  
>> +void powernv_idle(void)
>> +{
>> +	/* Hook to cpuidle framework if available, else
>> +	 * call on default platform idle code
>> +	 */
>> +	if (cpuidle_idle_call())
>> +		power7_idle();
>> +}
>> +
>>  define_machine(powernv) {
>>  	.name			= "PowerNV",
>>  	.probe			= pnv_probe,
>> @@ -205,7 +215,7 @@ define_machine(powernv) {
>>  	.show_cpuinfo		= pnv_show_cpuinfo,
>>  	.progress		= pnv_progress,
>>  	.machine_shutdown	= pnv_shutdown,
>> -	.power_save             = power7_idle,
>> +	.power_save             = powernv_idle,
>>  	.calibrate_decr		= generic_calibrate_decr,
>>  #ifdef CONFIG_KEXEC
>>  	.kexec_cpu_down		= pnv_kexec_cpu_down,
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>>
> 
> 

^ permalink raw reply

* Re: [linux-pm] [PATCH 1/3] cpuidle/powernv: cpuidle backend driver for powernv
From: Deepthi Dharwar @ 2013-07-29 14:39 UTC (permalink / raw)
  To: Daniel Lezcano; +Cc: linux-pm, linuxppc-dev, linux-kernel
In-Reply-To: <51F35A2A.1080408@linaro.org>

Hi Daniel,

On 07/27/2013 10:57 AM, Daniel Lezcano wrote:
> On 07/23/2013 11:01 AM, Deepthi Dharwar wrote:
>> This patch implements a back-end cpuidle driver for
>> powernv calling power7_nap and snooze idle states.
>> This can be extended by adding more idle states
>> in the future to the existing framework.
>>
>> Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
>> ---
>>  arch/powerpc/platforms/powernv/Kconfig          |    9 +
>>  arch/powerpc/platforms/powernv/Makefile         |    1 
>>  arch/powerpc/platforms/powernv/processor_idle.c |  239 +++++++++++++++++++++++
>>  3 files changed, 249 insertions(+)
>>  create mode 100644 arch/powerpc/platforms/powernv/processor_idle.c
>>
>> diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
>> index c24684c..ace2d22 100644
>> --- a/arch/powerpc/platforms/powernv/Kconfig
>> +++ b/arch/powerpc/platforms/powernv/Kconfig
>> @@ -20,3 +20,12 @@ config PPC_POWERNV_RTAS
>>  	default y
>>  	select PPC_ICS_RTAS
>>  	select PPC_RTAS
>> +
>> +config POWERNV_IDLE
>> +	bool "CPUIdle driver for powernv platform"
>> +	depends on CPU_IDLE
>> +	depends on PPC_POWERNV
>> +	default y
>> +	help
>> +	Select this option to enable processor idle state management
>> +	through cpuidle subsystem.
>> diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
>> index 7fe5951..c0e44eb 100644
>> --- a/arch/powerpc/platforms/powernv/Makefile
>> +++ b/arch/powerpc/platforms/powernv/Makefile
>> @@ -4,3 +4,4 @@ obj-y			+= opal-rtc.o opal-nvram.o
>>  obj-$(CONFIG_SMP)	+= smp.o
>>  obj-$(CONFIG_PCI)	+= pci.o pci-p5ioc2.o pci-ioda.o
>>  obj-$(CONFIG_EEH)	+= eeh-ioda.o eeh-powernv.o
>> +obj-$(CONFIG_POWERNV_IDLE)     += processor_idle.o
>> diff --git a/arch/powerpc/platforms/powernv/processor_idle.c b/arch/powerpc/platforms/powernv/processor_idle.c
>> new file mode 100644
>> index 0000000..f43ad91a
>> --- /dev/null
>> +++ b/arch/powerpc/platforms/powernv/processor_idle.c
>> @@ -0,0 +1,239 @@
>> +/*
>> + *  processor_idle - idle state cpuidle driver.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/cpuidle.h>
>> +#include <linux/cpu.h>
>> +#include <linux/notifier.h>
>> +
>> +#include <asm/machdep.h>
>> +#include <asm/runlatch.h>
>> +
>> +struct cpuidle_driver powernv_idle_driver = {
>> +	.name =		"powernv_idle",
>> +	.owner =	THIS_MODULE,
>> +};
>> +
>> +#define MAX_IDLE_STATE_COUNT	2
>> +
>> +static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
>> +static struct cpuidle_device __percpu *powernv_cpuidle_devices;
>> +static struct cpuidle_state *cpuidle_state_table;
>> +
>> +static int snooze_loop(struct cpuidle_device *dev,
>> +			struct cpuidle_driver *drv,
>> +			int index)
>> +{
>> +	int cpu = dev->cpu;
>> +
>> +	local_irq_enable();
>> +	set_thread_flag(TIF_POLLING_NRFLAG);
>> +
>> +	while ((!need_resched()) && cpu_online(cpu)) {
>> +		ppc64_runlatch_off();
>> +		HMT_very_low();
>> +	}
> 
> Why are you using the cpu_online test here ?

Snooze state is an idle state where cpu executes an infinite loop by
reducing the priority of the thread and the idle cpu can come out of it
only if need_resched is set or in case the cpu is offlined. In order to
continue executing this loop to remain in this idle state, we need the
check just to be safe.

>> +
>> +	HMT_medium();
>> +	clear_thread_flag(TIF_POLLING_NRFLAG);
>> +	smp_mb();
>> +	return index;
>> +}
>> +
>> +
>> +static int nap_loop(struct cpuidle_device *dev,
>> +				struct cpuidle_driver *drv,
>> +				int index)
>> +{
>> +	ppc64_runlatch_off();
>> +	power7_idle();
>> +	return index;
>> +}
>> +
>> +/*
>> + * States for dedicated partition case.
>> + */
>> +static struct cpuidle_state powernv_states[MAX_IDLE_STATE_COUNT] = {
>> +	{ /* Snooze */
>> +		.name = "snooze",
>> +		.desc = "snooze",
>> +		.flags = CPUIDLE_FLAG_TIME_VALID,
>> +		.exit_latency = 0,
>> +		.target_residency = 0,
>> +		.enter = &snooze_loop },
>> +	 { /* Nap */
>> +		.name = "Nap",
>> +		.desc = "Nap",
>> +		.flags = CPUIDLE_FLAG_TIME_VALID,
>> +		.exit_latency = 10,
>> +		.target_residency = 100,
>> +		.enter = &nap_loop },
>> +};
>> +
>> +static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
>> +			unsigned long action, void *hcpu)
>> +{
>> +	int hotcpu = (unsigned long)hcpu;
>> +	struct cpuidle_device *dev =
>> +			per_cpu_ptr(powernv_cpuidle_devices, hotcpu);
>> +
>> +	if (dev && cpuidle_get_driver()) {
>> +		switch (action) {
>> +		case CPU_ONLINE:
>> +		case CPU_ONLINE_FROZEN:
>> +			cpuidle_pause_and_lock();
>> +			cpuidle_enable_device(dev);
>> +			cpuidle_resume_and_unlock();
>> +			break;
>> +
>> +		case CPU_DEAD:
>> +		case CPU_DEAD_FROZEN:
>> +			cpuidle_pause_and_lock();
>> +			cpuidle_disable_device(dev);
>> +			cpuidle_resume_and_unlock();
>> +			break;
>> +
>> +		default:
>> +			return NOTIFY_DONE;
>> +		}
>> +	}
>> +	return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block setup_hotplug_notifier = {
>> +	.notifier_call = powernv_cpuidle_add_cpu_notifier,
>> +};
> 
> This is duplicated code with the pseries cpuidle driver and IMHO it
> should be moved to the cpuidle framework.

Yes, a lot of code here is there in pseries cpuidle driver. I am
re-factoring that aspect so that we can use one back-end driver for both
pseries and powernv. I will post it out soon.

Moving the hotplug handler to cpuidle can be done as a separate feature.
This needs change in all the other archs that use cpuidle and  change in
the framework itself.

> 
>> +/*
>> + * powernv_cpuidle_driver_init()
>> + */
>> +static int powernv_cpuidle_driver_init(void)
>> +{
>> +	int idle_state;
>> +	struct cpuidle_driver *drv = &powernv_idle_driver;
>> +
>> +	drv->state_count = 0;
>> +
>> +	for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
>> +
>> +		if (idle_state > max_idle_state)
>> +			break;
>> +
>> +		/* is the state not enabled? */
>> +		if (cpuidle_state_table[idle_state].enter == NULL)
>> +			continue;
>> +
>> +		drv->states[drv->state_count] =	/* structure copy */
>> +			cpuidle_state_table[idle_state];
>> +
>> +		drv->state_count += 1;
>> +	}
>> +
>> +	return 0;
>> +}
> 
> 
> Instead of doing struct copy, why don't you use the state's 'disable'
> field of the driver and then enable the state in the routine ?

Going forward, having a single driver for powernv and pseries, I would
like to have two separate cpuidle state table for each arch. And both
would have their idle states and corresponding routines. Combining
different arch idle routines into one table and enabling/disabling them
would be quite confusing.

> 
>> +/* powernv_idle_devices_uninit(void)
>> + * unregister cpuidle devices and de-allocate memory
>> + */
>> +static void powernv_idle_devices_uninit(void)
>> +{
>> +	int i;
>> +	struct cpuidle_device *dev;
>> +
>> +	for_each_possible_cpu(i) {
>> +		dev = per_cpu_ptr(powernv_cpuidle_devices, i);
>> +		cpuidle_unregister_device(dev);
>> +	}
>> +
>> +	free_percpu(powernv_cpuidle_devices);
>> +	return;
>> +}
>> +
>> +/* powernv_idle_devices_init()
>> + * allocate, initialize and register cpuidle device
>> + */
>> +static int powernv_idle_devices_init(void)
>> +{
>> +	int i;
>> +	struct cpuidle_driver *drv = &powernv_idle_driver;
>> +	struct cpuidle_device *dev;
>> +
>> +	powernv_cpuidle_devices = alloc_percpu(struct cpuidle_device);
>> +	if (powernv_cpuidle_devices == NULL)
>> +		return -ENOMEM;
>> +
>> +	for_each_possible_cpu(i) {
>> +		dev = per_cpu_ptr(powernv_cpuidle_devices, i);
>> +		dev->state_count = drv->state_count;
>> +		dev->cpu = i;
>> +		if (cpuidle_register_device(dev)) {
>> +			printk(KERN_DEBUG \
>> +				"cpuidle_register_device %d failed!\n", i);
>> +			return -EIO;
>> +		}
>> +	}
>> +	return 0;
> 
> 
> There is now the cpuidle_register(struct cpuidle_driver *, cpumask *);
> 
> You can get rid of the cpuidle_device struct and this init routine.

Thanks for the pointer. I will look into this.


>> +}
>> +
>> +/*
>> + * powernv_idle_probe()
>> + * Choose state table for shared versus dedicated partition
>> + */
>> +static int powernv_idle_probe(void)
>> +{
>> +
>> +	if (cpuidle_disable != IDLE_NO_OVERRIDE)
>> +		return -ENODEV;
>> +
>> +	cpuidle_state_table = powernv_states;
>> +	return 0;
>> +}
>> +
>> +static int __init powernv_processor_idle_init(void)
>> +{
>> +	int retval;
>> +
>> +	retval = powernv_idle_probe();
>> +	if (retval)
>> +		return retval;
>> +
>> +	powernv_cpuidle_driver_init();
>> +	retval = cpuidle_register_driver(&powernv_idle_driver);
>> +	if (retval) {
>> +		printk(KERN_DEBUG "Registration of powernv driver failed.\n");
>> +		return retval;
>> +	}
>> +
>> +	retval = powernv_idle_devices_init();
>> +	if (retval) {
>> +		powernv_idle_devices_uninit();
>> +		cpuidle_unregister_driver(&powernv_idle_driver);
>> +		return retval;
>> +	}
>> +
>> +	register_cpu_notifier(&setup_hotplug_notifier);
>> +	printk(KERN_DEBUG "powernv_idle_driver registered\n");
>> +
>> +	return 0;
>> +}
>> +
>> +static void __exit powernv_processor_idle_exit(void)
>> +{
>> +
>> +	unregister_cpu_notifier(&setup_hotplug_notifier);
>> +	powernv_idle_devices_uninit();
>> +	cpuidle_unregister_driver(&powernv_idle_driver);
>> +
>> +	return;
>> +}
>> +
>> +module_init(powernv_processor_idle_init);
>> +module_exit(powernv_processor_idle_exit);
>> +
>> +MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
>> +MODULE_DESCRIPTION("Cpuidle driver for POWERNV");
>> +MODULE_LICENSE("GPL");
>>
> 
> 
Thanks a lot for your time and review.

Regards,
Deepthi

^ permalink raw reply

* Re: [PATCH 2/3] cpuidle/powernv: Enable idle powernv cpu to call into the cpuidle framework.
From: Daniel Lezcano @ 2013-07-29 14:44 UTC (permalink / raw)
  To: Deepthi Dharwar; +Cc: linux-pm, linuxppc-dev, linux-kernel
In-Reply-To: <51F67BE5.10701@linux.vnet.ibm.com>

On 07/29/2013 04:27 PM, Deepthi Dharwar wrote:
> On 07/27/2013 10:59 AM, Daniel Lezcano wrote:
>> On 07/23/2013 11:01 AM, Deepthi Dharwar wrote:
>>> This patch enables idle powernv cpu to hook on to the cpuidle
>>> framework, if available, else call on to default idle platform
>>> code.
>>
>> Why do you need to do that ?
>>
> 
> Hi Daniel,
> 
> Well, this is needed in case when one does not compile with CPU_IDLE
> config option.
> 
> When CPUIDLE is not configured, idle cpus are needed to be running some
> sort of default idle code or loop ( in the worst case) if cpuidle driver
> is not registered or if one decides not to have that config enabled.

Hi Deepthi,

ok may be there is some difference with the other platform but the
arch_cpu_idle function defined in the other archs do:

void arch_cpu_idle(void)
{
        if (cpuidle_idle_call())
                x86_idle();
        else
                local_irq_enable();
}

or

void arch_cpu_idle(void)
{
        if (cpuidle_idle_call())
                default_idle();
}

When the cpuidle driver is not compiled or not loaded, cpuidle_idle_call
fails, falling back to the default idle function.

The arch_cpu_idle function is called from the generic code in
kernel/cpu/idle.c.

Is there a particular reason to do it in a different way ?

Thanks
  -- Daniel

>>
>>> Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
>>> ---
>>>  arch/powerpc/platforms/powernv/setup.c |   12 +++++++++++-
>>>  1 file changed, 11 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
>>> index 84438af..97d0951 100644
>>> --- a/arch/powerpc/platforms/powernv/setup.c
>>> +++ b/arch/powerpc/platforms/powernv/setup.c
>>> @@ -25,6 +25,7 @@
>>>  #include <linux/of.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/bug.h>
>>> +#include <linux/cpuidle.h>
>>>  
>>>  #include <asm/machdep.h>
>>>  #include <asm/firmware.h>
>>> @@ -196,6 +197,15 @@ static int __init pnv_probe(void)
>>>  	return 1;
>>>  }
>>>  
>>> +void powernv_idle(void)
>>> +{
>>> +	/* Hook to cpuidle framework if available, else
>>> +	 * call on default platform idle code
>>> +	 */
>>> +	if (cpuidle_idle_call())
>>> +		power7_idle();
>>> +}
>>> +
>>>  define_machine(powernv) {
>>>  	.name			= "PowerNV",
>>>  	.probe			= pnv_probe,
>>> @@ -205,7 +215,7 @@ define_machine(powernv) {
>>>  	.show_cpuinfo		= pnv_show_cpuinfo,
>>>  	.progress		= pnv_progress,
>>>  	.machine_shutdown	= pnv_shutdown,
>>> -	.power_save             = power7_idle,
>>> +	.power_save             = powernv_idle,
>>>  	.calibrate_decr		= generic_calibrate_decr,
>>>  #ifdef CONFIG_KEXEC
>>>  	.kexec_cpu_down		= pnv_kexec_cpu_down,
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>> Please read the FAQ at  http://www.tux.org/lkml/
>>>
>>
>>
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* Re: [linux-pm] [PATCH 1/3] cpuidle/powernv: cpuidle backend driver for powernv
From: Daniel Lezcano @ 2013-07-29 14:53 UTC (permalink / raw)
  To: Deepthi Dharwar; +Cc: linux-pm, linuxppc-dev, linux-kernel
In-Reply-To: <51F67E96.6040008@linux.vnet.ibm.com>

On 07/29/2013 04:39 PM, Deepthi Dharwar wrote:
> Hi Daniel,
> 
> On 07/27/2013 10:57 AM, Daniel Lezcano wrote:
>> On 07/23/2013 11:01 AM, Deepthi Dharwar wrote:
>>> This patch implements a back-end cpuidle driver for
>>> powernv calling power7_nap and snooze idle states.
>>> This can be extended by adding more idle states
>>> in the future to the existing framework.
>>>
>>> Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>

[ ... ]

>>> +static int snooze_loop(struct cpuidle_device *dev,
>>> +			struct cpuidle_driver *drv,
>>> +			int index)
>>> +{
>>> +	int cpu = dev->cpu;
>>> +
>>> +	local_irq_enable();
>>> +	set_thread_flag(TIF_POLLING_NRFLAG);
>>> +
>>> +	while ((!need_resched()) && cpu_online(cpu)) {
>>> +		ppc64_runlatch_off();
>>> +		HMT_very_low();
>>> +	}
>>
>> Why are you using the cpu_online test here ?
> 
> Snooze state is an idle state where cpu executes an infinite loop by
> reducing the priority of the thread and the idle cpu can come out of it
> only if need_resched is set or in case the cpu is offlined. In order to
> continue executing this loop to remain in this idle state, we need the
> check just to be safe.

Yes, but if the cpu is offline you are no longer executing this code, no ?

-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* Re: [PATCH v2 3/3] powerpc/85xx: Add C293PCIE board support
From: Scott Wood @ 2013-07-29 18:10 UTC (permalink / raw)
  To: Liu Po-B43644
  Cc: Wood Scott-B07421, Hu Mingkai-B21284, Fleming Andy-AFLEMING,
	linuxppc-dev@ozlabs.org
In-Reply-To: <D473A0D087F4EA47A30C37E4637E25E609DB3735@039-SN2MPN1-023.039d.mgd.msft.net>

On 07/28/2013 09:20:11 PM, Liu Po-B43644 wrote:
>=20
>=20
> >  -----Original Message-----
> >  From: Wood Scott-B07421
> >  Sent: Saturday, July 27, 2013 5:59 AM
> >  To: Liu Po-B43644
> >  Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Fleming =20
> Andy-
> >  AFLEMING; Hu Mingkai-B21284; Liu Po-B43644
> >  Subject: Re: [PATCH v2 3/3] powerpc/85xx: Add C293PCIE board =20
> support
> >
> >  On 07/25/2013 09:41:19 PM, Po Liu wrote:
> >  > +		partition@1900000 {
> >  > +			/* 7MB for User Area */
> >  > +			reg =3D <0x01900000 0x00700000>;
> >  > +			label =3D "NAND User area";
> >  > +		};
> >  > +
> >  > +		partition@2000000 {
> >  > +			/* 96MB for Root File System */
> >  > +			reg =3D <0x02000000 0x06000000>;
> >  > +			label =3D "NAND Root File System";
> >  > +		};
> >  > +
> >  > +		partition@8000000 {
> >  > +			/* 3968MB for Others */
> >  > +			reg =3D <0x08000000 0xF8000000>;
> >  > +			label =3D "NAND Others";
> >  > +		};
> >
> >  Again, what is the difference between "user area" and "others"?  =20
> I'm not
> >  even sure why it needs to be separate from "root file system", but =20
> at
> >  least the root filesystem should be larger given the size of the =20
> overall
> >  flash.
> Do you mean just merge up four partition into one "RFS"? Or merge up =20
> four partition into "RFS" and "User area" is better?

If you don't have a reason for separating them, then probably yes, =20
merge them all into one.  If you do keep RFS and "user area" separate, =20
then "user area" should be the larger of the two, but the RFS should be =20
more than just 96 MiB.

> >  > +			partition@580000 {
> >  > +				/* 10.5MB for Compressed RFS =20
> Image */
> >  > +				reg =3D <0x00580000 0x00a80000>;
> >  > +				label =3D "SPI Flash Compressed =20
> RFSImage";
> >  > +			};
> >
> >  Space before "Image".  Why specifiy that it's compressed, versus =20
> some
> >  other filesystem type?
> >
> Remove all the "compressed" comments when express the RFS partition?

Yes.

-Scott=

^ permalink raw reply

* Re: [PATCH 2/3] include: Convert ethernet mac address declarations to use ETH_ALEN
From: Joe Perches @ 2013-07-29 19:34 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Steve Glendinning, Samuel Ortiz, linux-media, netdev, linux-usb,
	linux-kernel, linux-acpi, Vitaly Bordug, Len Brown, linuxppc-dev,
	David S. Miller, Mauro Carvalho Chehab
In-Reply-To: <2929374.frUlkyTFNL@vostro.rjw.lan>

On Mon, 2013-07-29 at 13:59 +0200, Rafael J. Wysocki wrote:
> On Sunday, July 28, 2013 10:29:04 PM Joe Perches wrote:
> > It's convenient to have ethernet mac addresses use
> > ETH_ALEN to be able to grep for them a bit easier and
> > also to ensure that the addresses are __aligned(2).
[]
> > diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
[]
> > @@ -44,6 +44,8 @@
[]
> > +#include <linux/if_ether.h>
> > +
[]
> > @@ -605,7 +607,7 @@ struct acpi_ibft_nic {
[]
> > -	u8 mac_address[6];
> > +	u8 mac_address[ETH_ALEN];

> Please don't touch this file.
> 
> It comes from a code base outside of the kernel and should be kept in sync with
> the upstream.

Which files in include/acpi have this characteristic?
Perhaps an include/acpi/README is appropriate.

^ permalink raw reply

* Re: [PATCH 2/3] include: Convert ethernet mac address declarations to use ETH_ALEN
From: Rafael J. Wysocki @ 2013-07-29 20:06 UTC (permalink / raw)
  To: Joe Perches
  Cc: Steve Glendinning, Samuel Ortiz, linux-media, netdev, linux-usb,
	linux-kernel, linux-acpi, Vitaly Bordug, Len Brown, linuxppc-dev,
	David S. Miller, Mauro Carvalho Chehab
In-Reply-To: <1375126464.2075.46.camel@joe-AO722>

On Monday, July 29, 2013 12:34:24 PM Joe Perches wrote:
> On Mon, 2013-07-29 at 13:59 +0200, Rafael J. Wysocki wrote:
> > On Sunday, July 28, 2013 10:29:04 PM Joe Perches wrote:
> > > It's convenient to have ethernet mac addresses use
> > > ETH_ALEN to be able to grep for them a bit easier and
> > > also to ensure that the addresses are __aligned(2).
> []
> > > diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> []
> > > @@ -44,6 +44,8 @@
> []
> > > +#include <linux/if_ether.h>
> > > +
> []
> > > @@ -605,7 +607,7 @@ struct acpi_ibft_nic {
> []
> > > -	u8 mac_address[6];
> > > +	u8 mac_address[ETH_ALEN];
> 
> > Please don't touch this file.
> > 
> > It comes from a code base outside of the kernel and should be kept in sync with
> > the upstream.
> 
> Which files in include/acpi have this characteristic?

Generally, all whose names start with "ac" except for acpi_bus.h,
acpi_drivers.h and acpi_numa.h.

> Perhaps an include/acpi/README is appropriate.

Yes, we can add one.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH 1/3] mmc:core: parse voltage from device-tree
From: Scott Wood @ 2013-07-29 22:07 UTC (permalink / raw)
  To: Haijun Zhang
  Cc: linux-mmc, AFLEMING, cbouatmailru, cjb, linuxppc-dev,
	Haijun Zhang
In-Reply-To: <1375066595-14968-1-git-send-email-Haijun.Zhang@freescale.com>

On 07/28/2013 09:56:33 PM, Haijun Zhang wrote:
> Add function to support get voltage from device-tree.
> If there are voltage-range specified in device-tree node, this =20
> function
> will parse it and return the avail voltage mask.
>=20
> Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
> ---
>  drivers/mmc/core/core.c  | 48 =20
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mmc/core.h |  1 +
>  2 files changed, 49 insertions(+)

Move the code rather than copying it.

-Scott=

^ permalink raw reply

* Re: [PATCH v7 1/3] DMA: Freescale: revise device tree binding document
From: Scott Wood @ 2013-07-29 22:09 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: devicetree, vinod.koul, linux-kernel, Hongbo Zhang, djbw,
	linuxppc-dev
In-Reply-To: <1375094944-3343-2-git-send-email-hongbo.zhang@freescale.com>

On 07/29/2013 05:49:02 AM, hongbo.zhang@freescale.com wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>=20
> This patch updates the discription of each type of DMA controller and =20
> its
> channels, it is preparation for adding another new DMA controller =20
> binding, it
> also fixes some defects of indent for text alignment at the same time.
>=20
> Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>

ACK, but next time please do the whitespace fixes as a separate patch =20
so that it's easier to see what's actually changing.

-Scott=

^ permalink raw reply

* Re: [PATCH v7 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: Scott Wood @ 2013-07-29 22:10 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: devicetree, vinod.koul, linux-kernel, Hongbo Zhang, djbw,
	linuxppc-dev
In-Reply-To: <1375094944-3343-3-git-send-email-hongbo.zhang@freescale.com>

On 07/29/2013 05:49:03 AM, hongbo.zhang@freescale.com wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>=20
> Freescale QorIQ T4 and B4 introduce new 8-channel DMA engines, this =20
> patch adds
> the device tree nodes for them.
>=20
> Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
> ---
>  .../devicetree/bindings/powerpc/fsl/dma.txt        |   66 =20
> ++++++++++++++++
>  arch/powerpc/boot/dts/fsl/b4si-post.dtsi           |    4 +-
>  arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi          |   81 =20
> ++++++++++++++++++++
>  arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi          |   81 =20
> ++++++++++++++++++++
>  arch/powerpc/boot/dts/fsl/t4240si-post.dtsi        |    4 +-
>  5 files changed, 232 insertions(+), 4 deletions(-)
>  create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
>  create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi

ACK

-Scott=

^ permalink raw reply

* Re: visible memory seems wrong in kexec crash dump kernel
From: Scott Wood @ 2013-07-29 23:10 UTC (permalink / raw)
  To: Chris Friesen; +Cc: Paul Mackerras, kexec, linuxppc-dev, Vivek Goyal
In-Reply-To: <51E0F41A.20904@mail.usask.ca>

On 07/13/2013 01:30:50 AM, Chris Friesen wrote:
> On 07/12/2013 04:59 PM, Chris Friesen wrote:
>> On 07/12/2013 03:08 PM, Chris Friesen wrote:
>>=20
>>> I turned on the instrumentation in early_init_dt_scan_memory() and =20
>>> got
>>> the following when jumping to the capture kernel:
>>>=20
>>> memory scan node memory, reg size 16, data: 0 0 2 0,
>>> - 0 , 200000000
>>>=20
>>> That 0x200000000 matches the fact that I'm seeing 8GB of memory
>>> available in the recovery kernel.
>>>=20
>>> If I boot the original kernel with "crashkernel=3D224M@32M", should I
>>> expect that only 224MB is marked as "linux,usable-memory" in the
>>> recovery kernel?
>>=20
>> I started looking at the kexec side of things, and I noticed =20
>> something a
>> bit odd. In most places dealing with the device tree in kexec it =20
>> accepts
>> either "memory" or "memory@" for the memory node name. In
>> add_usable_mem_property() in arch/ppc64/fs2dt.c it seems to only =20
>> accept
>> "memory@".
>>=20
>> Is this expected behaviour? It seems to be the same in current git
>> versions of kexec-tools.
>>=20
>> On my system I see "/proc/device-tree/memory".
>>=20
>> If I modify add_usable_mem_property() to also accept "/memory" then =20
>> my
>> recovery kernel boots up with
>>=20
>> physicalMemorySize =3D 0x10000000
>>=20
>> which is 256MB (which is still a bit odd since I specified 224MB for =20
>> the
>> crashkernel).
>>=20
>> However, it then hits the BUG() call at the end of mark_bootmem() in
>> mm/bootmem.c.
>=20
> One final thing and I'll stop replying to myself. :)
>=20
> It looks like the problem is that some board-specific freescale code =20
> was calling lmb_reserve() with a base address in the 4GB range.  It =20
> seems odd that lmb_reserve() didn't throw some kind of error when the =20
> recovery kernel was supposed to be limited to 224MB.
>=20
> Rather than try and fix the bug, I turned off the (unneeded) config =20
> options related to the above lmb_reserve() calls and was able to =20
> successfully access the information I needed via /dev/oldmem.
>=20
> The upshot is that there seems to be a number of things that could be =20
> improved:
>=20
> 1) kexec should accept "/memory" and not just "/memory@"
> 2) lmb_reserve() should really respect the crashkernel memory limit
> 3) the freescale stuff really shouldn't assume it can map things =20
> wherever it feels like

What "board-specific freescale code" are you referring to?

-Scott=

^ permalink raw reply

* [PATCH v2 1/2] powerpc: Add smp_generic_cpu_bootable
From: Andy Fleming @ 2013-07-29 23:33 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev

Cell and PSeries both implemented their own versions of a
cpu_bootable smp_op which do the same thing (well, the PSeries
one has support for more than 2 threads). Copy the PSeries one
to generic code, and rename it smp_generic_cpu_bootable.

Signed-off-by: Andy Fleming <afleming@freescale.com>
---

v2: Removed Change-Id

 arch/powerpc/include/asm/smp.h |    2 ++
 arch/powerpc/kernel/smp.c      |   23 +++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ffbaabe..f2b5d41 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -182,6 +182,8 @@ extern int smt_enabled_at_boot;
 extern int smp_mpic_probe(void);
 extern void smp_mpic_setup_cpu(int cpu);
 extern int smp_generic_kick_cpu(int nr);
+extern int smp_generic_cpu_bootable(unsigned int nr);
+
 
 extern void smp_generic_give_timebase(void);
 extern void smp_generic_take_timebase(void);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 38b0ba6..3cd42aa 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -81,6 +81,29 @@ int smt_enabled_at_boot = 1;
 
 static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
 
+/*
+ * Returns 1 if the specified cpu should be brought up during boot.
+ * Used to inhibit booting threads if they've been disabled or
+ * limited on the command line
+ */
+int smp_generic_cpu_bootable(unsigned int nr)
+{
+	/* Special case - we inhibit secondary thread startup
+	 * during boot if the user requests it.
+	 */
+	if (system_state == SYSTEM_BOOTING && cpu_has_feature(CPU_FTR_SMT)) {
+		if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
+			return 0;
+		if (smt_enabled_at_boot
+		    && cpu_thread_in_core(nr) >= smt_enabled_at_boot)
+			return 0;
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL(smp_generic_cpu_bootable);
+
+
 #ifdef CONFIG_PPC64
 int smp_generic_kick_cpu(int nr)
 {
-- 
1.7.9.7

^ permalink raw reply related

* [PATCH v2 2/2] powerpc: Convert platforms to smp_generic_cpu_bootable
From: Andy Fleming @ 2013-07-29 23:33 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1375140785-9782-1-git-send-email-afleming@freescale.com>

T4, Cell, powernv, and pseries had the same implementation, so switch
them to use a generic version. A2 apparently had a version, but
removed it at some point, so we remove the declaration, too.

Signed-off-by: Andy Fleming <afleming@freescale.com>
---

v2: Removed conflict and Change-Id foo

 arch/powerpc/platforms/85xx/smp.c    |    1 +
 arch/powerpc/platforms/cell/smp.c    |   15 +--------------
 arch/powerpc/platforms/powernv/smp.c |   18 +-----------------
 arch/powerpc/platforms/pseries/smp.c |   18 +-----------------
 arch/powerpc/platforms/wsp/wsp.h     |    1 -
 5 files changed, 4 insertions(+), 49 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 5ced4f5..ea9c626 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -255,6 +255,7 @@ out:
 
 struct smp_ops_t smp_85xx_ops = {
 	.kick_cpu = smp_85xx_kick_cpu,
+	.cpu_bootable = smp_generic_cpu_bootable,
 #ifdef CONFIG_HOTPLUG_CPU
 	.cpu_disable	= generic_cpu_disable,
 	.cpu_die	= generic_cpu_die,
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index f75f6fc..90745ea 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -136,25 +136,12 @@ static int smp_cell_kick_cpu(int nr)
 	return 0;
 }
 
-static int smp_cell_cpu_bootable(unsigned int nr)
-{
-	/* Special case - we inhibit secondary thread startup
-	 * during boot if the user requests it.  Odd-numbered
-	 * cpus are assumed to be secondary threads.
-	 */
-	if (system_state == SYSTEM_BOOTING &&
-	    cpu_has_feature(CPU_FTR_SMT) &&
-	    !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
-		return 0;
-
-	return 1;
-}
 static struct smp_ops_t bpa_iic_smp_ops = {
 	.message_pass	= iic_message_pass,
 	.probe		= smp_iic_probe,
 	.kick_cpu	= smp_cell_kick_cpu,
 	.setup_cpu	= smp_cell_setup_cpu,
-	.cpu_bootable	= smp_cell_cpu_bootable,
+	.cpu_bootable	= smp_generic_cpu_bootable,
 };
 
 /* This is called very early */
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index 89e3857..908672b 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -46,22 +46,6 @@ static void pnv_smp_setup_cpu(int cpu)
 		xics_setup_cpu();
 }
 
-static int pnv_smp_cpu_bootable(unsigned int nr)
-{
-	/* Special case - we inhibit secondary thread startup
-	 * during boot if the user requests it.
-	 */
-	if (system_state == SYSTEM_BOOTING && cpu_has_feature(CPU_FTR_SMT)) {
-		if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
-			return 0;
-		if (smt_enabled_at_boot
-		    && cpu_thread_in_core(nr) >= smt_enabled_at_boot)
-			return 0;
-	}
-
-	return 1;
-}
-
 int pnv_smp_kick_cpu(int nr)
 {
 	unsigned int pcpu = get_hard_smp_processor_id(nr);
@@ -195,7 +179,7 @@ static struct smp_ops_t pnv_smp_ops = {
 	.probe		= xics_smp_probe,
 	.kick_cpu	= pnv_smp_kick_cpu,
 	.setup_cpu	= pnv_smp_setup_cpu,
-	.cpu_bootable	= pnv_smp_cpu_bootable,
+	.cpu_bootable	= smp_generic_cpu_bootable,
 #ifdef CONFIG_HOTPLUG_CPU
 	.cpu_disable	= pnv_smp_cpu_disable,
 	.cpu_die	= generic_cpu_die,
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 306643c..ca2d1f6 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -187,22 +187,6 @@ static int smp_pSeries_kick_cpu(int nr)
 	return 0;
 }
 
-static int smp_pSeries_cpu_bootable(unsigned int nr)
-{
-	/* Special case - we inhibit secondary thread startup
-	 * during boot if the user requests it.
-	 */
-	if (system_state == SYSTEM_BOOTING && cpu_has_feature(CPU_FTR_SMT)) {
-		if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
-			return 0;
-		if (smt_enabled_at_boot
-		    && cpu_thread_in_core(nr) >= smt_enabled_at_boot)
-			return 0;
-	}
-
-	return 1;
-}
-
 /* Only used on systems that support multiple IPI mechanisms */
 static void pSeries_cause_ipi_mux(int cpu, unsigned long data)
 {
@@ -237,7 +221,7 @@ static struct smp_ops_t pSeries_xics_smp_ops = {
 	.probe		= pSeries_smp_probe,
 	.kick_cpu	= smp_pSeries_kick_cpu,
 	.setup_cpu	= smp_xics_setup_cpu,
-	.cpu_bootable	= smp_pSeries_cpu_bootable,
+	.cpu_bootable	= smp_generic_cpu_bootable,
 };
 
 /* This is called very early */
diff --git a/arch/powerpc/platforms/wsp/wsp.h b/arch/powerpc/platforms/wsp/wsp.h
index 62ef21a..a563a8a 100644
--- a/arch/powerpc/platforms/wsp/wsp.h
+++ b/arch/powerpc/platforms/wsp/wsp.h
@@ -17,7 +17,6 @@ extern void scom_init_wsp(void);
 extern void a2_setup_smp(void);
 extern int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
 			       struct device_node *np);
-extern int smp_a2_cpu_bootable(unsigned int nr);
 extern int smp_a2_kick_cpu(int nr);
 
 extern void opb_pic_init(void);
-- 
1.7.9.7

^ permalink raw reply related

* Re: P1021rdb-pc
From: Scott Wood @ 2013-07-29 23:36 UTC (permalink / raw)
  To: BHARATHI KANDIMALLA; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <633176325F8AEB44967E1E3F9795BB22440FFEC9@TC-MX1.icommtele.local>

On 07/25/2013 03:29:45 AM, BHARATHI KANDIMALLA wrote:
> Dear Sir,
>=20
> We  are using  P1021rdb-pc   board  with p1021 processor.
>=20
> 1.  compilation and build process  is taking  so  much of time. How =20
> should I
> reduce the time for linux  build process?

Remove things from the .config that you don't need.

Be sure you're using a -j value that is large enough to keep all your =20
CPUs busy.

Use ccache.

Get a faster build machine. :-)

> 2.  In  kernel configuration  we are not able to select  P1021rdb., =20
> When we configured the  board for p1021RDB-PC ,  in  default kenel =20
> config  file   all the below platforms are selected , We want only  =20
> p1021rdb  , what should we select here?
>=20
>  CONFIG_PPC_CELL is not set
> CONFIG_FSL_SOC_BOOKE=3Dy
> CONFIG_FSL_85XX_CACHE_SRAM=3Dy
> CONFIG_MPC8540_ADS=3Dy
> CONFIG_MPC8560_ADS=3Dy
> CONFIG_MPC85xx_CDS=3Dy
> CONFIG_MPC85xx_MDS=3Dy
> CONFIG_MPC8536_DS=3Dy
> CONFIG_MPC85xx_DS=3Dy
> CONFIG_MPC85xx_RDB=3Dy

fsl,P1021RDB-PC is handled by mpc85xx_rdb.c (and thus =20
CONFIG_MPC85xx_RDB).

> 3. We are using  p1021 processor which has 36 bit support  , but we  =20
> have compiled uboot for 32 bit only.Is there any specfic use of 36 =20
> bit  compilation, ?

If your U-Boot is configured for 32 bits, there's no benefit to =20
enabling CONFIG_PHYS_64BIT (unless you're remapping things yourself, =20
such as moving the PCIe windows), and it can slow things down.

> 4. Now we are using  SDK 1.3.2  for  p1021 procesor .Is there any =20
> specific
> necessity that we should switch  to sdk1.4
> regarding linux drivers  specially included for  p1021 procesor?

It's generally good to use more recent code for the various =20
improvements and fixes it contains, but I don't know of a specific =20
p1021-related requirement.  Note that this list is for upstream Linux; =20
for help with Freescale SDKs go to https://community.freescale.com/

Also note that p1021rdb-pc is supported in upstream Linux; you do not =20
need to use the SDK at all unless there is something specific you need =20
beyond basic board support.

> 5.UMCC driver  is  available in  linux driver ?

No.

> where should I get some help regarding UMCC ?

community.freescale.com, support@freescale.com, or your sales/FAE =20
contact.

-Scott=

^ permalink raw reply

* Re: [PATCH v2] powerpc: Update compilation flags with core specific options
From: Scott Wood @ 2013-07-29 23:53 UTC (permalink / raw)
  To: Catalin Udma; +Cc: Catalin Udma, linuxppc-dev
In-Reply-To: <1374753254-10381-1-git-send-email-catalin.udma@freescale.com>

On 07/25/2013 06:54:14 AM, Catalin Udma wrote:
> If CONFIG_E500 is enabled, the compilation flags are updated
> specifying the target core -mcpu=3De5500/e500mc/8540
> Also remove -Wa,-me500, being incompatible with -mcpu=3De5500/e6500
> The assembler option is redundant if the -mcpu=3D flag is set.
> The patch fixes the kernel compilation problem for e5500/e6500
> when using gcc option -mcpu=3De5500/e6500.
>=20
> Signed-off-by: Catalin Udma <catalin.udma@freescale.com>
> ---
> changes for v2:
>     - update also KBUILD_AFLAGS with -mcpu and -msoft-float flags
>=20
>  arch/powerpc/Makefile |   16 +++++++++++++++-
>  1 files changed, 15 insertions(+), 1 deletions(-)
>=20
> diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
> index 0624909..cb5cbe2 100644
> --- a/arch/powerpc/Makefile
> +++ b/arch/powerpc/Makefile
> @@ -140,6 +140,21 @@ ifeq ($(CONFIG_6xx),y)
>  KBUILD_CFLAGS		+=3D -mcpu=3Dpowerpc
>  endif
>=20
> +ifeq ($(CONFIG_E500),y)
> +ifeq ($(CONFIG_64BIT),y)
> +KBUILD_CFLAGS		+=3D -mcpu=3De5500
> +KBUILD_AFLAGS		+=3D -mcpu=3De5500 -msoft-float
> +else
> +ifeq ($(CONFIG_PPC_E500MC),y)
> +KBUILD_CFLAGS		+=3D -mcpu=3De500mc
> +KBUILD_AFLAGS		+=3D -mcpu=3De500mc -msoft-float
> +else
> +KBUILD_CFLAGS		+=3D -mcpu=3D8540
> +KBUILD_AFLAGS		+=3D -mcpu=3D8540 -msoft-float
> +endif
> +endif
> +endif

Instead of specifying -msoft-float here, shouldn't it go on the main =20
KBUILD_AFLAGS in arch/powerpc/Makefile, right next to where it's added =20
for KBUILD_CFLAGS?

-Scott=

^ permalink raw reply

* Re: [PATCH] Add device file bindings for MAPLE
From: Scott Wood @ 2013-07-30  0:00 UTC (permalink / raw)
  To: Shaveta Leekha; +Cc: Shaveta Leekha, devicetree-discuss, linuxppc-dev
In-Reply-To: <1374930222-32739-1-git-send-email-shaveta@freescale.com>

On 07/27/2013 08:03:42 AM, Shaveta Leekha wrote:
> Signed-off-by: Shaveta Leekha <shaveta@freescale.com>
> ---
>  .../devicetree/bindings/powerpc/fsl/maple.txt      |   50 =20
> ++++++++++++++++++++
>  1 files changed, 50 insertions(+), 0 deletions(-)
>  create mode 100644 =20
> Documentation/devicetree/bindings/powerpc/fsl/maple.txt
>=20
> diff --git a/Documentation/devicetree/bindings/powerpc/fsl/maple.txt =20
> b/Documentation/devicetree/bindings/powerpc/fsl/maple.txt
> new file mode 100644
> index 0000000..23b80a7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/powerpc/fsl/maple.txt
> @@ -0,0 +1,50 @@
> +* Freescale MAPLE Multi Accelerator Platform Engine Baseband 3
> +  (MAPLE-B3)device nodes
> +
> +Supported chips:
> +Example: B4860
> +
> +Required properties:
> +
> +- compatible:	Should contain "fsl,maple-b3" as the value
> +		This identifies Multi Accelerator Platform Engine
> +		Baseband 3 block.
> +
> +- reg:		offset and length of the register set for the =20
> device
> +
> +- interrupts
> +	Usage: required
> +	Value type: <prop_encoded-array>
> +	Definition:  Specifies the interrupts generated by this =20
> device.  The
> +			value of the interrupts property consists of =20
> one interrupt
> +			specifier. The format of the specifier is =20
> defined by the
> +			binding document describing the node's =20
> interrupt parent.

Please clean up whitespace so the text aligns.

> +
> +		A single IRQ that handles error conditions is specified =20
> by
> +		this property.  (Typically shared with port-write).
> +
> +Devices that have LIODNs need to specify links to the parent PAMU =20
> controller
> +(the actual PAMU controller that this device is connected to) and a =20
> pointer to
> +the LIODN register, if applicable.
> +
> +- fsl,iommu-parent
> +		: <phandle>
> +		This property should be present
> +
> +- status =3D "disabled"
> +		In this example, status is set "disabled",
> +		As Maple device wouldn't be used by PPC Linux. This =20
> representation is required
> +		for doing the PAMU programming on the Linux side.

Is it proper for Linux to even set the LIODN on a device that is =20
"disabled"?  Perhaps the compatible should be different, such as =20
"fsl,maple-b3-liodn" to indicate that that is the only portion of the =20
device that is owned by this partition.

> +Example:
> +	/* B4860 */
> +
> +	maple@800000 {
> +		#address-cells =3D <0>;
> +		#size-cells =3D <0>;
> +		status =3D "disabled";
> +		compatible =3D "fsl,maple-b3";
> +		reg =3D <0x8000000 0x10000>;
> +		interrupts =3D <16 2 1 18>;
> +		fsl,iommu-parent =3D <&pamu1>;
> +	};

This error interrupt is documented as 13, not 18.  b4860 (and maybe =20
other b4?) have an erratum that says that error interrupts are =20
reversed, but this is generally implemented in b4si-post.dtsi, not in =20
block-specific include files.  Will no chip without the erratum ever =20
have maple?

-Scott=

^ permalink raw reply

* Re: [1/1] MPC831x: fix PCI express probing
From: Scott Wood @ 2013-07-30  0:19 UTC (permalink / raw)
  To: Sergey Gerasimov; +Cc: linuxppc-dev, linux-kernel, Paul Mackerras, Jia Hongtao
In-Reply-To: <1369657783-19962-1-git-send-email-Sergey.Gerasimov@astrosoft-development.com>

On Mon, May 27, 2013 at 02:29:43PM +0200, Sergey Gerasimov wrote:
> For MPC831x the bus probing function also needs the fixup to assign
> addresses to the PCI devices as it was for MPC85xx and MPC86xx.
> The fixup of the bridge vendor and device ID should be done early in
> PCI probing. Else the bridge is not detected as FIXUP_HEADER is called
> too late.
> 
> Signed-off-by: Sergey Gerasimov <Sergey.Gerasimov@astrosoft-development.com>
> 
> ---
> arch/powerpc/sysdev/fsl_pci.c | 68 +++++++++++++++++++------------------------
>  1 file changed, 30 insertions(+), 38 deletions(-)
> 
> diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
> index 028ac1f..94d1bd4 100644
> --- a/arch/powerpc/sysdev/fsl_pci.c
> +++ b/arch/powerpc/sysdev/fsl_pci.c
> @@ -84,6 +84,34 @@ static int fsl_pcie_check_link(struct pci_controller *hose)
>  	return 0;
>  }
>  
> +void fsl_pcibios_fixup_bus(struct pci_bus *bus)
> +{
> +	struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
> +	int i;
> +
> +
> +	if ((bus->parent == hose->bus)
> +		&& ((fsl_pcie_bus_fixup
> +			&& pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP))
> +			|| (hose->indirect_type
> +				& PPC_INDIRECT_TYPE_NO_PCIE_LINK))) {
> +		for (i = 0; i < 4; ++i) {
> +			struct resource *res = bus->resource[i];
> +			struct resource *par = bus->parent->resource[i];
> +			if (res) {
> +				res->start = 0;
> +				res->end   = 0;
> +				res->flags = 0;
> +			}
> +			if (res && par) {
> +				res->start = par->start;
> +				res->end   = par->end;
> +				res->flags = par->flags;
> +			}
> +		}
> +	}
> +}

Why are you moving this function?  This makes it hardaer to see the
changes you make -- and is likely the cause of unintended changes being
made due to a bad conflict resolution.  In particular, you seem to be
reverting commit 13635dfdc6aa8d2890e02dc441decfcb4ae63e14
("powerpc/fsl/pci: Fix PCIe fixup regression").

Also please confirm that the problem still exists in after "Fix PCIe
fixup regression".

-Scott

^ permalink raw reply

* Re: [PATCH] Add device file bindings for MAPLE
From: Benjamin Herrenschmidt @ 2013-07-30  0:29 UTC (permalink / raw)
  To: Scott Wood; +Cc: Shaveta Leekha, devicetree-discuss, linuxppc-dev
In-Reply-To: <1375142451.30721.68@snotra>

On Mon, 2013-07-29 at 19:00 -0500, Scott Wood wrote:
> On 07/27/2013 08:03:42 AM, Shaveta Leekha wrote:
> > Signed-off-by: Shaveta Leekha <shaveta@freescale.com>
> > ---
> >  .../devicetree/bindings/powerpc/fsl/maple.txt      |   50  
> > ++++++++++++++++++++

BTW, that's confusing, we have a platform called maple ... oh well...

Cheers,
Ben.

^ permalink raw reply

* Re: powerpc/85xx: Add P1023RDB board support
From: Scott Wood @ 2013-07-30  1:09 UTC (permalink / raw)
  To: Chunhe Lan; +Cc: linuxppc-dev
In-Reply-To: <1371198380-12792-1-git-send-email-Chunhe.Lan@freescale.com>

On Fri, Jun 14, 2013 at 04:26:20PM +0800, Chunhe Lan wrote:
> P1023RDB Specification:
> -----------------------
> Memory subsystem:
>    512MB DDR3 (Fixed DDR on board)
>    64MB NOR flash
>    128MB NAND flash

Where is NAND in the device tree?

> Ethernet:
>    eTSEC1: Connected to Atheros AR8035 GETH PHY
>    eTSEC2: Connected to Atheros AR8035 GETH PHY

Where are the PHYs in the device tree?

> +			partition@3f00000 {
> +				label = "firmware";
> +				reg = <0x03f00000 0x00080000>;
> +				read-only;
> +			};
> +			partition@3f80000 {
> +				label = "u-boot";
> +				reg = <0x03f80000 0x00080000>;
> +				read-only;
> +			};

What is "firmware" if not U-Boot?  FMan firmware?  Note that part of your
"firmware" partition contains the U-Boot environment.

> diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig
> index b80bcc6..092a746 100644
> --- a/arch/powerpc/configs/85xx/p1023rds_defconfig
> +++ b/arch/powerpc/configs/85xx/p1023rds_defconfig
> @@ -22,6 +22,7 @@ CONFIG_MODVERSIONS=y
>  # CONFIG_BLK_DEV_BSG is not set
>  CONFIG_PARTITION_ADVANCED=y
>  CONFIG_MAC_PARTITION=y
> +CONFIG_P1023_RDB=y
>  CONFIG_P1023_RDS=y
>  CONFIG_QUICC_ENGINE=y
>  CONFIG_QE_GPIO=y
> @@ -67,6 +68,7 @@ CONFIG_PROC_DEVICETREE=y
>  CONFIG_BLK_DEV_LOOP=y
>  CONFIG_BLK_DEV_RAM=y
>  CONFIG_BLK_DEV_RAM_SIZE=131072
> +CONFIG_EEPROM_AT24=y
>  CONFIG_EEPROM_LEGACY=y
>  CONFIG_BLK_DEV_SD=y
>  CONFIG_CHR_DEV_ST=y
> @@ -102,6 +104,7 @@ CONFIG_SERIAL_8250_RSA=y
>  CONFIG_SERIAL_QE=m
>  CONFIG_NVRAM=y
>  CONFIG_I2C=y
> +CONFIG_I2C_CHARDEV=y
>  CONFIG_I2C_CPM=m
>  CONFIG_I2C_MPC=y
>  CONFIG_GPIO_MPC8XXX=y
> @@ -121,6 +124,7 @@ CONFIG_USB_STORAGE=y
>  CONFIG_EDAC=y
>  CONFIG_EDAC_MM_EDAC=y
>  CONFIG_RTC_CLASS=y
> +CONFIG_RTC_DRV_DS1307=y
>  CONFIG_RTC_DRV_CMOS=y
>  CONFIG_DMADEVICES=y
>  CONFIG_FSL_DMA=y

This isn't a p1023rds.  Having one defconfig to support both boards is
good, but the defconfig should be renamed to p1023_defconfig.

> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
> index efdd37c..d0e8ff9 100644
> --- a/arch/powerpc/platforms/85xx/Kconfig
> +++ b/arch/powerpc/platforms/85xx/Kconfig
> @@ -111,6 +111,12 @@ config P1022_RDK
>  	  This option enables support for the Freescale / iVeia P1022RDK
>  	  reference board.
>  
> +config P1023_RDB
> +	bool "Freescale P1023 RDB"
> +	select P1023_RDS
> +	help
> +	  This option enables support for the P1023 RDB board
> +

Why do you need a new kconfig option, if you're supporting both boards
with the same C file?  Just update the name and description of the
existing kconfig symbol.

-Scott

^ 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