[RFC][PATCHv3+ 1/2] driver/core: Add of_iommu_attach()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




Hi,

Experimentally I have implemented "of_iommu_attach()" called from
drvier/core to control the order of device instanciation.

In the Tegra SMMU PATCHv3, we've discussed how to control the order of
device instanciation. Thierry/Stephen proposed to insert a hook in
driver/core to control this order, depending on whether an iommu
device is ready or not."of_iommu_attach()" is implement for that
purpose now. Along with this patch, I attached DT part of modication
to this mail. I used the same iommu bindings which arm,smmu uses.

[RFC][PATCHv3+ 2/2] ARM: DT: tegra30: iommu: Add "stream-id-cells"/"mmu-masters"

"#stream-id-cells" is used to identify whether a device is IOMMU'able
or not. If a device is IOMMU'able, we'll defer to instanciate that
device till an iommu device is instanciated/ready. Once an iommu device
is instanciated, "dev->bus->iommu_ops" is set in the bus. After an
iommu device is instanciated, those defered devices are instanciated
as IOMMU'able with help of the iommu driver via iommu_ops->add_device().

We don't call bus_set_iommu() until an iommu device is instanciated
because we need to support 2 kind of IOMMU drivers, SMMU and GART so
that this bus_set_iommu() needs to be defered till an iommu device is
instanciated. So the single image can support 2 iommu drivers at once.

With this patch, the following HACK patches in v3[1] are not needed
anymore.

  patch 1: [HACK] of: dev_node has struct device pointer
  patch 2: [HACK] ARM: tegra: Populate AHB/IOMMU earlier than others
  patch 3: [HACK] amba: Move AHB to core_initcall
  patch 4: [HACK] iommu/tegra: smmu: Move IOMMU to core_initcall

Any comment would be really appreciated.

[1] Original v3:
http://lists.linuxfoundation.org/pipermail/iommu/2013-October/006724.html

[2]
http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006864.html

Signed-off-by: Hiroshi Doyu <hdoyu@xxxxxxxxxx>
---
 drivers/base/dd.c        |  5 +++++
 drivers/iommu/of_iommu.c | 34 ++++++++++++++++++++++++++++++++++
 include/linux/iommu.h    |  7 +++++++
 3 files changed, 46 insertions(+)

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 35fa368..ca76290 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -25,6 +25,7 @@
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
 #include <linux/pinctrl/devinfo.h>
+#include <linux/iommu.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -273,6 +274,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
 
 	dev->driver = drv;
 
+	ret = of_iommu_attach(dev);
+	if (ret)
+		goto probe_failed;
+
 	/* If using pinctrl, bind pins now before probing */
 	ret = pinctrl_bind_pins(dev);
 	if (ret)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index ee249bc..f211cdc 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -20,6 +20,9 @@
 #include <linux/export.h>
 #include <linux/limits.h>
 #include <linux/of.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/iommu.h>
 
 /**
  * of_get_dma_window - Parse *dma-window property and returns 0 if found.
@@ -88,3 +91,34 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_get_dma_window);
+
+static bool of_is_iommuable(struct device *dev)
+{
+	size_t bytes;
+	const __be32 *prop;
+	const char *propname = "#stream-id-cells";
+
+	prop = of_get_property(dev->of_node, propname, &bytes);
+	if (!prop || !bytes)
+		return false;
+
+	pr_debug("%s=%d %s\n", propname, bytes, dev_name(dev));
+	return true;
+}
+
+int of_iommu_attach(struct device *dev)
+{
+	struct iommu_ops *ops;
+
+	if (!of_is_iommuable(dev))
+		return 0;
+
+	ops = dev->bus->iommu_ops;
+	if (!ops)
+		return -EPROBE_DEFER;
+
+	if (ops->add_device)
+		return ops->add_device(dev);
+
+	return 0;
+}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index a444c79..de16bf2 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -232,6 +232,8 @@ static inline int report_iommu_fault(struct iommu_domain *domain,
 	return ret;
 }
 
+extern int of_iommu_attach(struct device *dev);
+
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -390,6 +392,11 @@ static inline int iommu_domain_set_attr(struct iommu_domain *domain,
 	return -EINVAL;
 }
 
+static inline int of_iommu_attach(struct device *dev)
+{
+	return 0;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
-- 
1.8.1.5

>From fa49c864c1b05df6de16cfc2d12f74fcae843e55 Mon Sep 17 00:00:00 2001
From: Hiroshi Doyu <hdoyu@xxxxxxxxxx>
Date: Wed, 6 Nov 2013 15:27:03 +0200
Subject: [RFC][PATCHv3+ 2/2] ARM: DT: tegra30: iommu: Add
 "stream-id-cells"/"mmu-masters"

Follow the same syntax as arm,smmu.

FIXME: "nvidia,memory-clients" should be removed.

Signed-off-by: Hiroshi Doyu <hdoyu@xxxxxxxxxx>
---
 arch/arm/boot/dts/tegra30.dtsi | 63 +++++++++++++++++++++++++++++++++---------
 1 file changed, 50 insertions(+), 13 deletions(-)

diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 4c7f296..5913ec9 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -87,60 +87,66 @@
 		};
 	};
 
-	host1x {
+	host1x: host1x {
 		compatible = "nvidia,tegra30-host1x", "simple-bus";
 		reg = <0x50000000 0x00024000>;
 		interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
 			     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */
 		clocks = <&tegra_car TEGRA30_CLK_HOST1X>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_HC>;
+		#stream-id-cells = <1>;
 
 		#address-cells = <1>;
 		#size-cells = <1>;
 
 		ranges = <0x54000000 0x54000000 0x04000000>;
 
-		mpe {
+		mpe: mpe {
 			compatible = "nvidia,tegra30-mpe";
 			reg = <0x54040000 0x00040000>;
 			interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_MPE>;
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_MPE>;
+			#stream-id-cells = <1>;
 		};
 
-		vi {
+		vi: vi {
 			compatible = "nvidia,tegra30-vi";
 			reg = <0x54080000 0x00040000>;
 			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_VI>;
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_VI>;
+			#stream-id-cells = <1>;
 		};
 
-		epp {
+		epp: epp {
 			compatible = "nvidia,tegra30-epp";
 			reg = <0x540c0000 0x00040000>;
 			interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_EPP>;
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_EPP>;
+			#stream-id-cells = <1>;
 		};
 
-		isp {
+		isp: isp {
 			compatible = "nvidia,tegra30-isp";
 			reg = <0x54100000 0x00040000>;
 			interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_ISP>;
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_ISP>;
+			#stream-id-cells = <1>;
 		};
 
-		gr2d {
+		gr2d: gr2d {
 			compatible = "nvidia,tegra30-gr2d";
 			reg = <0x54140000 0x00040000>;
 			interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_GR2D>;
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_G2>;
+			#stream-id-cells = <1>;
 		};
 
-		gr3d {
+		gr3d: gr3d {
 			compatible = "nvidia,tegra30-gr3d";
 			reg = <0x54180000 0x00040000>;
 			clocks = <&tegra_car TEGRA30_CLK_GR3D
@@ -148,9 +154,10 @@
 			clock-names = "3d", "3d2";
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_NV
 						TEGRA_SWGROUP_NV2>;
+			#stream-id-cells = <2>;
 		};
 
-		dc@54200000 {
+		dc: dc@54200000 {
 			compatible = "nvidia,tegra30-dc", "nvidia,tegra20-dc";
 			reg = <0x54200000 0x00040000>;
 			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
@@ -158,13 +165,14 @@
 				 <&tegra_car TEGRA30_CLK_PLL_P>;
 			clock-names = "disp1", "parent";
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_DC>;
+			#stream-id-cells = <1>;
 
 			rgb {
 				status = "disabled";
 			};
 		};
 
-		dc@54240000 {
+		dcb: dc@54240000 {
 			compatible = "nvidia,tegra30-dc";
 			reg = <0x54240000 0x00040000>;
 			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
@@ -172,6 +180,7 @@
 				 <&tegra_car TEGRA30_CLK_PLL_P>;
 			clock-names = "disp2", "parent";
 			nvidia,memory-clients = <&smmu TEGRA_SWGROUP_DCB>;
+			#stream-id-cells = <1>;
 
 			rgb {
 				status = "disabled";
@@ -329,6 +338,7 @@
 		nvidia,dma-request-selector = <&apbdma 8>;
 		clocks = <&tegra_car TEGRA30_CLK_UARTA>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
@@ -340,6 +350,7 @@
 		nvidia,dma-request-selector = <&apbdma 9>;
 		clocks = <&tegra_car TEGRA30_CLK_UARTB>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
@@ -351,6 +362,7 @@
 		nvidia,dma-request-selector = <&apbdma 10>;
 		clocks = <&tegra_car TEGRA30_CLK_UARTC>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
@@ -362,6 +374,7 @@
 		nvidia,dma-request-selector = <&apbdma 19>;
 		clocks = <&tegra_car TEGRA30_CLK_UARTD>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
@@ -373,6 +386,7 @@
 		nvidia,dma-request-selector = <&apbdma 20>;
 		clocks = <&tegra_car TEGRA30_CLK_UARTE>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
@@ -550,6 +564,25 @@
 		dma-window = <0 0x40000000>;	/* IOVA start & length */
 		nvidia,swgroups = <0x00000000 0x000779ff>;
 		nvidia,ahb = <&ahb>;
+
+		mmu-masters = <&host1x TEGRA_SWGROUP_HC>,
+			      <&mpe TEGRA_SWGROUP_MPE>,
+			      <&vi TEGRA_SWGROUP_VI>,
+			      <&epp TEGRA_SWGROUP_EPP>,
+			      <&isp TEGRA_SWGROUP_ISP>,
+			      <&gr2d TEGRA_SWGROUP_G2>,
+			      <&gr3d TEGRA_SWGROUP_NV TEGRA_SWGROUP_NV2>,
+			      <&dc TEGRA_SWGROUP_DC>,
+			      <&dcb TEGRA_SWGROUP_DCB>,
+			      <&uarta TEGRA_SWGROUP_PPCS>,
+			      <&uartb TEGRA_SWGROUP_PPCS>,
+			      <&uartc TEGRA_SWGROUP_PPCS>,
+			      <&uartd TEGRA_SWGROUP_PPCS>,
+			      <&uarte TEGRA_SWGROUP_PPCS>,
+			      <&sdhci0 TEGRA_SWGROUP_PPCS>,
+			      <&sdhci1 TEGRA_SWGROUP_PPCS>,
+			      <&sdhci2 TEGRA_SWGROUP_PPCS>,
+			      <&sdhci3 TEGRA_SWGROUP_PPCS>;
 	};
 
 	ahub {
@@ -617,39 +650,43 @@
 		};
 	};
 
-	sdhci@78000000 {
+	sdhci0: sdhci@78000000 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000000 0x200>;
 		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&tegra_car TEGRA30_CLK_SDMMC1>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
-	sdhci@78000200 {
+	sdhci1: sdhci@78000200 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000200 0x200>;
 		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&tegra_car TEGRA30_CLK_SDMMC2>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
-	sdhci@78000400 {
+	sdhci2: sdhci@78000400 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000400 0x200>;
 		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&tegra_car TEGRA30_CLK_SDMMC3>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
-	sdhci@78000600 {
+	sdhci3: sdhci@78000600 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000600 0x200>;
 		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&tegra_car TEGRA30_CLK_SDMMC4>;
 		nvidia,memory-clients = <&smmu TEGRA_SWGROUP_PPCS>;
+		#stream-id-cells = <1>;
 		status = "disabled";
 	};
 
-- 
1.8.1.5


[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux