drm/rockchip: Refactor IOMMU initialisation
authorRobin Murphy <robin.murphy@arm.com>
Tue, 5 Apr 2022 14:32:50 +0000 (15:32 +0100)
committerHeiko Stuebner <heiko@sntech.de>
Mon, 2 May 2022 21:52:27 +0000 (23:52 +0200)
Defer the IOMMU domain setup until after successfully binding
components, so we can figure out IOMMU support directly from the VOP
devices themselves, rather than manually inferring it from the DT (which
also fails to account for whether the IOMMU driver is actually loaded).
Although this is somewhat of a logical cleanup, the main motivation is
to prepare for a change in the iommu_domain_alloc() interface.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/94eee7ab434fe11eb0787f691e9f1ab03a2e91be.1649168685.git.robin.murphy@arm.com
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c

index 4eaeb430c83a1a3ad5068e9203bca8dc1f1c9dff..7efd12312354b592eb5f37627f3325fa29f288f7 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/dma-mapping.h>
-#include <linux/dma-iommu.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
 #include <linux/of_graph.h>
@@ -34,7 +33,6 @@
 #define DRIVER_MAJOR   1
 #define DRIVER_MINOR   0
 
-static bool is_support_iommu = true;
 static const struct drm_driver rockchip_drm_driver;
 
 /*
@@ -48,7 +46,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
        struct rockchip_drm_private *private = drm_dev->dev_private;
        int ret;
 
-       if (!is_support_iommu)
+       if (!private->domain)
                return 0;
 
        ret = iommu_attach_device(private->domain, dev);
@@ -64,12 +62,22 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
                                    struct device *dev)
 {
        struct rockchip_drm_private *private = drm_dev->dev_private;
-       struct iommu_domain *domain = private->domain;
 
-       if (!is_support_iommu)
+       if (!private->domain)
                return;
 
-       iommu_detach_device(domain, dev);
+       iommu_detach_device(private->domain, dev);
+}
+
+void rockchip_drm_dma_init_device(struct drm_device *drm_dev,
+                                 struct device *dev)
+{
+       struct rockchip_drm_private *private = drm_dev->dev_private;
+
+       if (!device_iommu_mapped(dev))
+               private->iommu_dev = ERR_PTR(-ENODEV);
+       else if (!private->iommu_dev)
+               private->iommu_dev = dev;
 }
 
 static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
@@ -78,10 +86,10 @@ static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
        struct iommu_domain_geometry *geometry;
        u64 start, end;
 
-       if (!is_support_iommu)
+       if (IS_ERR_OR_NULL(private->iommu_dev))
                return 0;
 
-       private->domain = iommu_domain_alloc(&platform_bus_type);
+       private->domain = iommu_domain_alloc(private->iommu_dev->bus);
        if (!private->domain)
                return -ENOMEM;
 
@@ -101,7 +109,7 @@ static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
 {
        struct rockchip_drm_private *private = drm_dev->dev_private;
 
-       if (!is_support_iommu)
+       if (!private->domain)
                return;
 
        drm_mm_takedown(&private->mm);
@@ -137,25 +145,25 @@ static int rockchip_drm_bind(struct device *dev)
 
        drm_dev->dev_private = private;
 
-       ret = rockchip_drm_init_iommu(drm_dev);
-       if (ret)
-               goto err_free;
-
        ret = drmm_mode_config_init(drm_dev);
        if (ret)
-               goto err_iommu_cleanup;
+               goto err_free;
 
        rockchip_drm_mode_config_init(drm_dev);
 
        /* Try to bind all sub drivers. */
        ret = component_bind_all(dev, drm_dev);
        if (ret)
-               goto err_iommu_cleanup;
+               goto err_free;
 
-       ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+       ret = rockchip_drm_init_iommu(drm_dev);
        if (ret)
                goto err_unbind_all;
 
+       ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+       if (ret)
+               goto err_iommu_cleanup;
+
        drm_mode_config_reset(drm_dev);
 
        /* init kms poll for handling hpd */
@@ -170,10 +178,10 @@ static int rockchip_drm_bind(struct device *dev)
        return 0;
 err_kms_helper_poll_fini:
        drm_kms_helper_poll_fini(drm_dev);
-err_unbind_all:
-       component_unbind_all(dev, drm_dev);
 err_iommu_cleanup:
        rockchip_iommu_cleanup(drm_dev);
+err_unbind_all:
+       component_unbind_all(dev, drm_dev);
 err_free:
        drm_dev_put(drm_dev);
        return ret;
@@ -342,8 +350,6 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
                return -ENODEV;
 
        for (i = 0;; i++) {
-               struct device_node *iommu;
-
                port = of_parse_phandle(np, "ports", i);
                if (!port)
                        break;
@@ -353,21 +359,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
                        continue;
                }
 
-               iommu = of_parse_phandle(port->parent, "iommus", 0);
-               if (!iommu || !of_device_is_available(iommu)) {
-                       DRM_DEV_DEBUG(dev,
-                                     "no iommu attached for %pOF, using non-iommu buffers\n",
-                                     port->parent);
-                       /*
-                        * if there is a crtc not support iommu, force set all
-                        * crtc use non-iommu buffer.
-                        */
-                       is_support_iommu = false;
-               }
-
                found = true;
-
-               of_node_put(iommu);
                of_node_put(port);
        }
 
index 143a48330f849344b65c2ce209b7d0f43889fa60..008c44aef4001a330f99846470c4614f6e5073d6 100644 (file)
@@ -44,6 +44,7 @@ struct rockchip_crtc_state {
  */
 struct rockchip_drm_private {
        struct iommu_domain *domain;
+       struct device *iommu_dev;
        struct mutex mm_lock;
        struct drm_mm mm;
 };
@@ -52,6 +53,8 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
                                   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
                                    struct device *dev);
+void rockchip_drm_dma_init_device(struct drm_device *drm_dev,
+                                 struct device *dev);
 int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
 
 int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
index d53037531f40783a9119cb5dd3fca3baad154965..ff6fff085e0d7c74b848ede07b7e67402809ef39 100644 (file)
@@ -2175,6 +2175,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
                }
        }
 
+       rockchip_drm_dma_init_device(drm_dev, dev);
+
        return 0;
 
 err_disable_pm_runtime: