@@ -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);