Prevent module implementing arch_iommu from being unloaded while the
arch_iommu is in use, essentially while the iommu has been acquired using
iommu_get() by increasing module use count.

This assumes that the arch_iommu has to be uninstalled at module unload
time.

Signed-off-by: Sakari Ailus <sakari.ai...@maxwell.research.nokia.com>
---
 arch/arm/plat-omap/iommu.c |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index f0fea0b..430ed94 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -35,6 +35,7 @@ static const struct iommu_functions *arch_iommu;
 
 static struct platform_driver omap_iommu_driver;
 static struct kmem_cache *iopte_cachep;
+static struct mutex arch_iommu_mutex;
 
 /**
  * install_iommu_arch - Install archtecure specific iommu functions
@@ -45,10 +46,17 @@ static struct kmem_cache *iopte_cachep;
  **/
 int install_iommu_arch(const struct iommu_functions *ops)
 {
-       if (arch_iommu)
+       mutex_lock(&arch_iommu_mutex);
+
+       if (arch_iommu) {
+               mutex_unlock(&arch_iommu_mutex);
                return -EBUSY;
+       }
 
        arch_iommu = ops;
+
+       mutex_unlock(&arch_iommu_mutex);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(install_iommu_arch);
@@ -58,13 +66,22 @@ EXPORT_SYMBOL_GPL(install_iommu_arch);
  * @ops:       a pointer to architecture specific iommu functions
  *
  * This interface uninstalls the iommu algorighm installed previously.
+ *
+ * Note: This function may only be called at module_exit() function of
+ * a module which implements arch_iommu. Otherwise another mechanism
+ * from the module use count only to ensure the arch_iommu stays there
+ * has to be implemented.
  **/
 void uninstall_iommu_arch(const struct iommu_functions *ops)
 {
+       mutex_lock(&arch_iommu_mutex);
+
        if (arch_iommu != ops)
                pr_err("%s: not your arch\n", __func__);
 
        arch_iommu = NULL;
+
+       mutex_unlock(&arch_iommu_mutex);
 }
 EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
 
@@ -104,14 +121,20 @@ static int iommu_enable(struct iommu *obj)
        if (!obj)
                return -EINVAL;
 
-       if (!arch_iommu)
+       mutex_lock(&arch_iommu_mutex);
+       if (!arch_iommu || !try_module_get(arch_iommu->module)) {
+               mutex_unlock(&arch_iommu_mutex);
                return -ENOENT;
+       }
 
        clk_enable(obj->clk);
 
        err = arch_iommu->enable(obj);
 
        clk_disable(obj->clk);
+
+       mutex_unlock(&arch_iommu_mutex);
+
        return err;
 }
 
@@ -125,6 +148,8 @@ static void iommu_disable(struct iommu *obj)
        arch_iommu->disable(obj);
 
        clk_disable(obj->clk);
+
+       module_put(arch_iommu->module);
 }
 
 /*
@@ -1058,6 +1083,8 @@ static int __init omap_iommu_init(void)
                return -ENOMEM;
        iopte_cachep = p;
 
+       mutex_init(&arch_iommu_mutex);
+
        return platform_driver_register(&omap_iommu_driver);
 }
 module_init(omap_iommu_init);
-- 
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to