arm: exynos: sysmmu: release iommu mapping during module exit
authorSubash Patel <subash.ramaswamy@linaro.org>
Fri, 20 Jul 2012 10:16:20 +0000 (15:46 +0530)
committerGerrit <chrome-bot@google.com>
Sat, 21 Jul 2012 03:45:21 +0000 (20:45 -0700)
This change will add support for detaching iommu mapping, domain
and switchoff the hardware for an attached device.

This commit adds the following changes:
a) support in dma-mapping framework to call iommu_detach_device()
b) support in the exynos to call arm_iommu_detach_device() and
   arm_iommu_release_mapping()
c) changes to the module exit of drm_drv, drm_fimd, gsc, tv and mfc

BUG=chrome-os-partner:11310
TEST=none

Change-Id: I68254d0f94c22125cd4f6cffd3d4946f400d0d68
Signed-off-by: Subash Patel <subash.ramaswamy@linaro.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/27362
Tested-by: Jon Kliegman <kliegs@chromium.org>
Reviewed-by: Sonny Rao <sonnyrao@chromium.org>
Commit-Ready: Anush Elangovan <anush@google.com>
Reviewed-by: Anush Elangovan <anush@google.com>
Reviewed-by: Pawel Osciak <posciak@google.com>
arch/arm/include/asm/dma-iommu.h
arch/arm/mach-exynos/dev-sysmmu.c
arch/arm/mach-exynos/include/mach/sysmmu.h
arch/arm/mm/dma-mapping.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/media/video/exynos/gsc/gsc-core.c
drivers/media/video/exynos/tv/mixer_drv.c
drivers/media/video/s5p-mfc/s5p_mfc.c

index 799b094..9363152 100644 (file)
@@ -29,6 +29,7 @@ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
 
 int arm_iommu_attach_device(struct device *dev,
                                        struct dma_iommu_mapping *mapping);
-
+void arm_iommu_detach_device(struct device *dev,
+                                       struct dma_iommu_mapping *mapping);
 #endif /* __KERNEL__ */
 #endif
index 2a758b0..420dabd 100644 (file)
@@ -41,6 +41,21 @@ struct dma_iommu_mapping * s5p_create_iommu_mapping(struct device *client,
        return mapping;
 }
 
+void s5p_destroy_iommu_mapping(struct device *client)
+{
+       if (!client) {
+               printk(KERN_ERR"Invalid client passed to %s()\n", __func__);
+               return;
+       }
+       /* detach the device from the IOMMU */
+       arm_iommu_detach_device(client, client->archdata.mapping);
+
+       /* release the IOMMU mapping */
+       arm_iommu_release_mapping(client->archdata.mapping);
+
+       return;
+}
+
 struct platform_device *find_sysmmu_dt(struct platform_device *pdev,
                                        char *name)
 {
index 8727468..d0afdb7 100644 (file)
@@ -32,6 +32,7 @@ static inline void platform_set_sysmmu(
 struct dma_iommu_mapping *s5p_create_iommu_mapping(struct device *client,
                                dma_addr_t base, unsigned int size, int order,
                                struct dma_iommu_mapping *mapping);
+void s5p_destroy_iommu_mapping(struct device *client);
 struct platform_device *find_sysmmu_dt(struct platform_device *pdev,
                                        char *name);
 
index 580ef6e..57be09a 100644 (file)
@@ -1571,5 +1571,22 @@ int arm_iommu_attach_device(struct device *dev,
        pr_info("Attached IOMMU controller to %s device.\n", dev_name(dev));
        return 0;
 }
-
+/**
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure
+ *
+ * Detaches specified io address space mapping from the provided device
+ */
+void arm_iommu_detach_device(struct device *dev,
+                               struct dma_iommu_mapping *mapping)
+{
+       if (!mapping || !mapping->domain) {
+               pr_err("%s(): Trying to detach a device without IOMMU mapping?\n",
+                                                               __func__);
+               return;
+       }
+       iommu_detach_device(mapping->domain, dev);
+       pr_info("Detached IOMMU controller from %s device.\n", dev_name(dev));
+       return;
+}
 #endif
index 821710d..2da377d 100644 (file)
@@ -281,6 +281,15 @@ static int iommu_init(struct platform_device *pdev)
 
        return 0;
 }
+
+static void iommu_deinit(struct platform_device *pdev)
+{
+       /* detach the device and mapping */
+       s5p_destroy_iommu_mapping(&pdev->dev);
+       DRM_DEBUG("released the IOMMU mapping\n");
+
+       return;
+}
 #endif
 
 static int exynos_drm_platform_probe(struct platform_device *pdev)
@@ -299,12 +308,15 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
        return drm_platform_init(&exynos_drm_driver, pdev);
 }
 
-static int exynos_drm_platform_remove(struct platform_device *pdev)
+static int __devexit exynos_drm_platform_remove(struct platform_device *pdev)
 {
        DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
        drm_platform_exit(&exynos_drm_driver, pdev);
 
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
        return 0;
 }
 
index 835ca1a..b3728d7 100644 (file)
@@ -874,7 +874,16 @@ static int iommu_init(struct platform_device *pdev)
 
        return 0;
 }
+
+static void iommu_deinit(struct platform_device *pdev)
+{
+       s5p_destroy_iommu_mapping(&pdev->dev);
+       DRM_DEBUG("released the IOMMU mapping\n");
+
+       return;
+}
 #endif
+
 static int __devinit fimd_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1036,6 +1045,9 @@ err_bus_clk:
        clk_put(ctx->bus_clk);
 
 err_clk_get:
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
        kfree(ctx);
        return ret;
 }
@@ -1068,7 +1080,9 @@ out:
        release_resource(ctx->regs_res);
        kfree(ctx->regs_res);
        free_irq(ctx->irq, ctx);
-
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
        kfree(ctx);
 
        return 0;
index c5afefa..5b3a268 100644 (file)
@@ -1134,6 +1134,14 @@ static int iommu_init(struct platform_device *pdev)
 
        return 0;
 }
+
+static void iommu_deinit(struct platform_device *pdev)
+{
+       s5p_destroy_iommu_mapping(&pdev->dev);
+       printk(KERN_INFO"released the IOMMU mapping\n");
+
+       return;
+}
 #endif
 static int gsc_probe(struct platform_device *pdev)
 {
@@ -1285,6 +1293,9 @@ err_req_region:
        release_resource(gsc->regs_res);
        kfree(gsc->regs_res);
 err_info:
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
        kfree(gsc);
 
        return ret;
@@ -1308,7 +1319,9 @@ static int __devexit gsc_remove(struct platform_device *pdev)
        release_resource(gsc->regs_res);
        kfree(gsc->regs_res);
        kfree(gsc);
-
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
        dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
        return 0;
 }
index ee63207..d958887 100644 (file)
@@ -1358,6 +1358,14 @@ static int iommu_init(struct platform_device *pdev)
 
        return 0;
 }
+
+static void iommu_deinit(struct platform_device *pdev)
+{
+       s5p_destroy_iommu_mapping(&pdev->dev);
+       printk(KERN_INFO"released the IOMMU mapping\n");
+
+       return;
+}
 #endif
 /* --------- DRIVER INITIALIZATION ---------- */
 
@@ -1450,7 +1458,9 @@ fail_resources:
 
 fail_mem:
        kfree(mdev);
-
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
 fail:
        dev_info(dev, "probe failed\n");
        return ret;
@@ -1466,7 +1476,9 @@ static int __devexit mxr_remove(struct platform_device *pdev)
        mxr_release_layers(mdev);
        mxr_release_video(mdev);
        mxr_release_resources(mdev);
-
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(pdev);
+#endif
        kfree(mdev);
 
        dev_info(dev, "remove sucessful\n");
index a1761e6..b7b1bf0 100644 (file)
@@ -993,6 +993,17 @@ static int iommu_init(struct platform_device *pdev,
 
        return 0;
 }
+
+static void iommu_deinit(struct device *mfc_l, struct device *mfc_r)
+{
+       s5p_destroy_iommu_mapping(mfc_l);
+       printk(KERN_INFO"released the IOMMU mapping for MFC_L\n");
+
+       s5p_destroy_iommu_mapping(mfc_r);
+       printk(KERN_INFO"released the IOMMU mapping for MFC_R\n");
+
+       return;
+}
 #endif
 
 /* MFC probe function */
@@ -1165,6 +1176,9 @@ err_v4l2_dev_reg:
 err_mem_init_ctx_1:
        vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
 err_mem_init_ctx_0:
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(dev->mem_dev_r, dev->mem_dev_l);
+#endif
 err_iommu_init:
        free_irq(dev->irq, dev);
 err_req_irq:
@@ -1201,7 +1215,9 @@ static int __devexit s5p_mfc_remove(struct platform_device *pdev)
        v4l2_device_unregister(&dev->v4l2_dev);
        vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
        vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
-
+#ifdef CONFIG_EXYNOS_IOMMU
+       iommu_deinit(dev->mem_dev_r, dev->mem_dev_l);
+#endif
        free_irq(dev->irq, dev);
        iounmap(dev->regs_base);
        if (dev->mfc_mem) {