diff mbox series

iommu/exynos: Rework intialization

Message ID 20200409140928.1403-1-m.szyprowski@samsung.com (mailing list archive)
State Not Applicable
Headers show
Series iommu/exynos: Rework intialization | expand

Commit Message

Marek Szyprowski April 9, 2020, 2:09 p.m. UTC
Fix initialization after driver conversion to
probe_device()/release_device(). Prepared on top of:
https://git.kernel.org/pub/scm/linux/kernel/git/joro/linux.git/log/?h=iommu-probe-device

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/iommu/exynos-iommu.c | 80 +++++++++++++++++++++++++-------------------
 1 file changed, 46 insertions(+), 34 deletions(-)
diff mbox series

Patch

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index f865c90..53c784f 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -565,6 +565,7 @@  static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
 }
 
 static const struct iommu_ops exynos_iommu_ops;
+static int exynos_iommu_initialize_owner(struct device *sysmmu);
 
 static int exynos_sysmmu_probe(struct platform_device *pdev)
 {
@@ -573,6 +574,8 @@  static int exynos_sysmmu_probe(struct platform_device *pdev)
 	struct sysmmu_drvdata *data;
 	struct resource *res;
 
+	dev_info(dev, "%s %d\n", __func__, __LINE__);
+
 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -649,6 +652,8 @@  static int exynos_sysmmu_probe(struct platform_device *pdev)
 
 	pm_runtime_enable(dev);
 
+	exynos_iommu_initialize_owner(dev);
+
 	return 0;
 }
 
@@ -1225,24 +1230,8 @@  static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *iommu_domain,
 
 static struct iommu_device *exynos_iommu_probe_device(struct device *dev)
 {
-	struct exynos_iommu_owner *owner = dev->archdata.iommu;
-	struct sysmmu_drvdata *data;
-
-	if (!has_sysmmu(dev))
-		return ERR_PTR(-ENODEV);
-
-	list_for_each_entry(data, &owner->controllers, owner_node) {
-		/*
-		 * SYSMMU will be runtime activated via device link
-		 * (dependency) to its master device, so there are no
-		 * direct calls to pm_runtime_get/put in this driver.
-		 */
-		data->link = device_link_add(dev, data->sysmmu,
-					     DL_FLAG_STATELESS |
-					     DL_FLAG_PM_RUNTIME);
-	}
-
-	return &owner->iommu;
+	/* this is called too early on ARM 32bit to do anything usefull */
+	return ERR_PTR(-ENODEV);
 }
 
 static void exynos_iommu_release_device(struct device *dev)
@@ -1268,7 +1257,8 @@  static void exynos_iommu_release_device(struct device *dev)
 		device_link_del(data->link);
 }
 
-static int exynos_iommu_device_init(struct exynos_iommu_owner *owner)
+static int exynos_iommu_device_init(struct device *dev,
+				    struct exynos_iommu_owner *owner)
 {
 	static u32 counter = 0;
 	int ret;
@@ -1287,6 +1277,12 @@  static int exynos_iommu_device_init(struct exynos_iommu_owner *owner)
 
 	iommu_device_set_ops(&owner->iommu, &exynos_iommu_ops);
 
+	/*
+	 * the above iommu_device_set_ops is not enough, initializing fwspec
+	 * is also required
+	 */
+	iommu_fwspec_init(dev, &dev->of_node->fwnode, &exynos_iommu_ops);
+
 	return 0;
 }
 
@@ -1308,7 +1304,7 @@  static int exynos_owner_init(struct device *dev)
 	if (!owner)
 		return -ENOMEM;
 
-	ret = exynos_iommu_device_init(owner);
+	ret = exynos_iommu_device_init(dev, owner);
 	if (ret)
 		goto out_free_owner;
 
@@ -1330,34 +1326,51 @@  static int exynos_owner_init(struct device *dev)
 	return ret;
 }
 
-static int exynos_iommu_of_xlate(struct device *dev,
-				 struct of_phandle_args *spec)
+static int exynos_iommu_dev_match_owner(struct device *dev, const void *data)
+{
+	const struct device *sysmmu = data;
+	struct device_node *np;
+	int idx = 0;
+
+	do {
+		np = of_parse_phandle(dev->of_node, "iommus", idx++);
+		if (np == sysmmu->of_node)
+			return true;
+	} while (np);
+
+	return false;
+}
+
+static int exynos_iommu_initialize_owner(struct device *sysmmu)
 {
-	struct platform_device *sysmmu = of_find_device_by_node(spec->np);
-	struct sysmmu_drvdata *data, *entry;
+	struct sysmmu_drvdata *data = dev_get_drvdata(sysmmu);
 	struct exynos_iommu_owner *owner;
+	struct device *dev;
 	int ret;
 
-	if (!sysmmu)
+	dev = bus_find_device(&platform_bus_type, NULL, sysmmu,
+			      exynos_iommu_dev_match_owner);
+	if (!dev)
 		return -ENODEV;
 
-	data = platform_get_drvdata(sysmmu);
-	if (!data)
-		return -ENODEV;
+	dev_info(sysmmu, "found master device %s\n", dev_name(dev));
 
 	ret = exynos_owner_init(dev);
 	if (ret)
 		return ret;
 
 	owner = dev->archdata.iommu;
-
-	list_for_each_entry(entry, &owner->controllers, owner_node)
-		if (entry == data)
-			return 0;
-
 	list_add_tail(&data->owner_node, &owner->controllers);
 	data->master = dev;
 
+	/*
+	 * SYSMMU will be runtime activated via device link
+	 * (dependency) to its master device, so there are no
+	 * direct calls to pm_runtime_get/put in this driver.
+	 */
+	data->link = device_link_add(dev, data->sysmmu,
+				     DL_FLAG_STATELESS |
+				     DL_FLAG_PM_RUNTIME);
 	return 0;
 }
 
@@ -1373,7 +1386,6 @@  static int exynos_iommu_of_xlate(struct device *dev,
 	.probe_device = exynos_iommu_probe_device,
 	.release_device = exynos_iommu_release_device,
 	.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
-	.of_xlate = exynos_iommu_of_xlate,
 };
 
 static int __init exynos_iommu_init(void)