[PATCH] iommu/exynos: Rework intialization

From: Marek Szyprowski
Date: Thu Apr 09 2020 - 10:09:43 EST


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@xxxxxxxxxxx>
---
drivers/iommu/exynos-iommu.c | 80 +++++++++++++++++++++++++-------------------
1 file changed, 46 insertions(+), 34 deletions(-)

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)
--
1.9.1