The OMAP IOMMU driver supports both the OMAP1 and OMAP2+ IOMMU variants
by splitting the driver into a core module and a thin arch-specific
operations module.

(In practice only the OMAP2+ module omap-iommu2 is implemented, but
let's not denigrate the effort.)

The arch-specific operations module registers itself with the OMAP IOMMU
core module at initialization time. This initializes a module global
arch-specific operations pointer, used at runtime by the IOMMU
instances.

This scheme causes several issues. In addition to making it impossible
to support different OMAP IOMMU types in a single system (which in all
fairness is quite unlikely to happen), it also causes initialization
ordering issues by requiring the arch-specific operations module to be
loaded before any IOMMU user. This results in a probe breakage with the
OMAP3 ISP driver when not compiled as a module.

Fix the problem by inverting the dependency. Instead of having the
omap-iommu2 module register itself to iommu-omap, make the iommu-omap
retrieve the omap-iommu2 operations structure directly when probing the
IOMMU device. This ensures that a probed IOMMU will always have valid
arch-specific operations.

As the arch-specific operations pointer is now initialized at probe
time, this change requires turning it from a global variable into a
per-device variable.

Signed-off-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
---
 drivers/iommu/omap-iommu-debug.c |  6 ++-
 drivers/iommu/omap-iommu.c       | 94 ++++++++++++++--------------------------
 drivers/iommu/omap-iommu.h       | 10 ++++-
 drivers/iommu/omap-iommu2.c      | 18 +-------
 4 files changed, 45 insertions(+), 83 deletions(-)

diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index 531658d..35a2c3a 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -33,7 +33,9 @@ static struct dentry *iommu_debug_root;
 static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
                              size_t count, loff_t *ppos)
 {
-       u32 ver = omap_iommu_arch_version();
+       struct device *dev = file->private_data;
+       struct omap_iommu *obj = dev_to_omap_iommu(dev);
+       u32 ver = omap_iommu_arch_version(obj);
        char buf[MAXCOLUMN], *p = buf;
 
        p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
@@ -117,7 +119,7 @@ static ssize_t debug_write_pagetable(struct file *file,
                return -EINVAL;
        }
 
-       omap_iotlb_cr_to_e(&cr, &e);
+       omap_iotlb_cr_to_e(obj, &cr, &e);
        err = omap_iopgtable_store_entry(obj, &e);
        if (err)
                dev_err(obj->dev, "%s: fail to store cr\n", __func__);
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index df579f8..192c367 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -76,45 +76,10 @@ struct iotlb_lock {
        short vict;
 };
 
-/* accommodate the difference between omap1 and omap2/3 */
-static const struct iommu_functions *arch_iommu;
-
 static struct platform_driver omap_iommu_driver;
 static struct kmem_cache *iopte_cachep;
 
 /**
- * omap_install_iommu_arch - Install archtecure specific iommu functions
- * @ops:       a pointer to architecture specific iommu functions
- *
- * There are several kind of iommu algorithm(tlb, pagetable) among
- * omap series. This interface installs such an iommu algorighm.
- **/
-int omap_install_iommu_arch(const struct iommu_functions *ops)
-{
-       if (arch_iommu)
-               return -EBUSY;
-
-       arch_iommu = ops;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(omap_install_iommu_arch);
-
-/**
- * omap_uninstall_iommu_arch - Uninstall archtecure specific iommu functions
- * @ops:       a pointer to architecture specific iommu functions
- *
- * This interface uninstalls the iommu algorighm installed previously.
- **/
-void omap_uninstall_iommu_arch(const struct iommu_functions *ops)
-{
-       if (arch_iommu != ops)
-               pr_err("%s: not your arch\n", __func__);
-
-       arch_iommu = NULL;
-}
-EXPORT_SYMBOL_GPL(omap_uninstall_iommu_arch);
-
-/**
  * omap_iommu_save_ctx - Save registers for pm off-mode support
  * @dev:       client device
  **/
@@ -122,7 +87,7 @@ void omap_iommu_save_ctx(struct device *dev)
 {
        struct omap_iommu *obj = dev_to_omap_iommu(dev);
 
-       arch_iommu->save_ctx(obj);
+       obj->arch_iommu->save_ctx(obj);
 }
 EXPORT_SYMBOL_GPL(omap_iommu_save_ctx);
 
@@ -134,16 +99,16 @@ void omap_iommu_restore_ctx(struct device *dev)
 {
        struct omap_iommu *obj = dev_to_omap_iommu(dev);
 
-       arch_iommu->restore_ctx(obj);
+       obj->arch_iommu->restore_ctx(obj);
 }
 EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx);
 
 /**
  * omap_iommu_arch_version - Return running iommu arch version
  **/
-u32 omap_iommu_arch_version(void)
+u32 omap_iommu_arch_version(struct omap_iommu *obj)
 {
-       return arch_iommu->version;
+       return obj->arch_iommu->version;
 }
 EXPORT_SYMBOL_GPL(omap_iommu_arch_version);
 
@@ -153,7 +118,7 @@ static int iommu_enable(struct omap_iommu *obj)
        struct platform_device *pdev = to_platform_device(obj->dev);
        struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-       if (!arch_iommu)
+       if (!obj->arch_iommu)
                return -ENODEV;
 
        if (pdata && pdata->deassert_reset) {
@@ -166,7 +131,7 @@ static int iommu_enable(struct omap_iommu *obj)
 
        pm_runtime_get_sync(obj->dev);
 
-       err = arch_iommu->enable(obj);
+       err = obj->arch_iommu->enable(obj);
 
        return err;
 }
@@ -176,7 +141,7 @@ static void iommu_disable(struct omap_iommu *obj)
        struct platform_device *pdev = to_platform_device(obj->dev);
        struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-       arch_iommu->disable(obj);
+       obj->arch_iommu->disable(obj);
 
        pm_runtime_put_sync(obj->dev);
 
@@ -187,20 +152,21 @@ static void iommu_disable(struct omap_iommu *obj)
 /*
  *     TLB operations
  */
-void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+void omap_iotlb_cr_to_e(struct omap_iommu *obj, struct cr_regs *cr,
+                       struct iotlb_entry *e)
 {
        BUG_ON(!cr || !e);
 
-       arch_iommu->cr_to_e(cr, e);
+       obj->arch_iommu->cr_to_e(cr, e);
 }
 EXPORT_SYMBOL_GPL(omap_iotlb_cr_to_e);
 
-static inline int iotlb_cr_valid(struct cr_regs *cr)
+static inline int iotlb_cr_valid(struct omap_iommu *obj, struct cr_regs *cr)
 {
        if (!cr)
                return -EINVAL;
 
-       return arch_iommu->cr_valid(cr);
+       return obj->arch_iommu->cr_valid(cr);
 }
 
 static inline struct cr_regs *iotlb_alloc_cr(struct omap_iommu *obj,
@@ -209,22 +175,22 @@ static inline struct cr_regs *iotlb_alloc_cr(struct 
omap_iommu *obj,
        if (!e)
                return NULL;
 
-       return arch_iommu->alloc_cr(obj, e);
+       return obj->arch_iommu->alloc_cr(obj, e);
 }
 
-static u32 iotlb_cr_to_virt(struct cr_regs *cr)
+static u32 iotlb_cr_to_virt(struct omap_iommu *obj, struct cr_regs *cr)
 {
-       return arch_iommu->cr_to_virt(cr);
+       return obj->arch_iommu->cr_to_virt(cr);
 }
 
-static u32 get_iopte_attr(struct iotlb_entry *e)
+static u32 get_iopte_attr(struct omap_iommu *obj, struct iotlb_entry *e)
 {
-       return arch_iommu->get_pte_attr(e);
+       return obj->arch_iommu->get_pte_attr(e);
 }
 
 static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da)
 {
-       return arch_iommu->fault_isr(obj, da);
+       return obj->arch_iommu->fault_isr(obj, da);
 }
 
 static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l)
@@ -250,12 +216,12 @@ static void iotlb_lock_set(struct omap_iommu *obj, struct 
iotlb_lock *l)
 
 static void iotlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
 {
-       arch_iommu->tlb_read_cr(obj, cr);
+       obj->arch_iommu->tlb_read_cr(obj, cr);
 }
 
 static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
 {
-       arch_iommu->tlb_load_cr(obj, cr);
+       obj->arch_iommu->tlb_load_cr(obj, cr);
 
        iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
        iommu_write_reg(obj, 1, MMU_LD_TLB);
@@ -272,7 +238,7 @@ static inline ssize_t iotlb_dump_cr(struct omap_iommu *obj, 
struct cr_regs *cr,
 {
        BUG_ON(!cr || !buf);
 
-       return arch_iommu->dump_cr(obj, cr, buf);
+       return obj->arch_iommu->dump_cr(obj, cr, buf);
 }
 
 /* only used in iotlb iteration for-loop */
@@ -317,7 +283,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct 
iotlb_entry *e)
                struct cr_regs tmp;
 
                for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, tmp)
-                       if (!iotlb_cr_valid(&tmp))
+                       if (!iotlb_cr_valid(obj, &tmp))
                                break;
 
                if (i == obj->nr_tlb_entries) {
@@ -384,10 +350,10 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 
da)
                u32 start;
                size_t bytes;
 
-               if (!iotlb_cr_valid(&cr))
+               if (!iotlb_cr_valid(obj, &cr))
                        continue;
 
-               start = iotlb_cr_to_virt(&cr);
+               start = iotlb_cr_to_virt(obj, &cr);
                bytes = iopgsz_to_bytes(cr.cam & 3);
 
                if ((start <= da) && (da < start + bytes)) {
@@ -432,7 +398,7 @@ ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char 
*buf, ssize_t bytes)
 
        pm_runtime_get_sync(obj->dev);
 
-       bytes = arch_iommu->dump_ctx(obj, buf, bytes);
+       bytes = obj->arch_iommu->dump_ctx(obj, buf, bytes);
 
        pm_runtime_put_sync(obj->dev);
 
@@ -452,7 +418,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs 
*crs, int num)
        iotlb_lock_get(obj, &saved);
 
        for_each_iotlb_cr(obj, num, i, tmp) {
-               if (!iotlb_cr_valid(&tmp))
+               if (!iotlb_cr_valid(obj, &tmp))
                        continue;
                *p++ = tmp;
        }
@@ -666,7 +632,7 @@ iopgtable_store_entry_core(struct omap_iommu *obj, struct 
iotlb_entry *e)
                break;
        }
 
-       prot = get_iopte_attr(e);
+       prot = get_iopte_attr(obj, e);
 
        spin_lock(&obj->page_table_lock);
        err = fn(obj, e->da, e->pa, prot);
@@ -873,8 +839,10 @@ static struct omap_iommu *omap_iommu_attach(const char 
*name, u32 *iopgd)
        dev = driver_find_device(&omap_iommu_driver.driver, NULL,
                                (void *)name,
                                device_match_by_alias);
-       if (!dev)
+       if (!dev) {
+               dev_err(dev, "%s: can't find IOMMU %s\n", __func__, name);
                return ERR_PTR(-ENODEV);
+       }
 
        obj = to_iommu(dev);
 
@@ -894,6 +862,7 @@ static struct omap_iommu *omap_iommu_attach(const char 
*name, u32 *iopgd)
        flush_iotlb_all(obj);
 
        if (!try_module_get(obj->owner)) {
+               dev_err(obj->dev, "%s: can't get owner\n", __func__);
                err = -ENODEV;
                goto err_module;
        }
@@ -969,6 +938,7 @@ static int omap_iommu_probe(struct platform_device *pdev)
 
        obj->dev = &pdev->dev;
        obj->ctx = (void *)obj + sizeof(*obj);
+       obj->arch_iommu = &omap2_iommu_ops;
 
        spin_lock_init(&obj->iommu_lock);
        spin_lock_init(&obj->page_table_lock);
diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h
index 1275a82..7a90800 100644
--- a/drivers/iommu/omap-iommu.h
+++ b/drivers/iommu/omap-iommu.h
@@ -46,6 +46,9 @@ struct omap_iommu {
 
        int             nr_tlb_entries;
 
+       /* accommodate the difference between omap1 and omap2/3 */
+       const struct iommu_functions *arch_iommu;
+
        void *ctx; /* iommu context: registres saved area */
 
        int has_bus_err_back;
@@ -193,9 +196,10 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct 
device *dev)
 /*
  * global functions
  */
-extern u32 omap_iommu_arch_version(void);
+extern u32 omap_iommu_arch_version(struct omap_iommu *obj);
 
-extern void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
+extern void omap_iotlb_cr_to_e(struct omap_iommu *obj, struct cr_regs *cr,
+                              struct iotlb_entry *e);
 
 extern int
 omap_iopgtable_store_entry(struct omap_iommu *obj, struct iotlb_entry *e);
@@ -214,6 +218,8 @@ omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, 
ssize_t len);
 extern size_t
 omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t len);
 
+extern const struct iommu_functions omap2_iommu_ops;
+
 /*
  * register accessors
  */
diff --git a/drivers/iommu/omap-iommu2.c b/drivers/iommu/omap-iommu2.c
index 5e1ea3b..e72fe62 100644
--- a/drivers/iommu/omap-iommu2.c
+++ b/drivers/iommu/omap-iommu2.c
@@ -296,7 +296,7 @@ static void omap2_cr_to_e(struct cr_regs *cr, struct 
iotlb_entry *e)
        e->mixed        = cr->ram & MMU_RAM_MIXED;
 }
 
-static const struct iommu_functions omap2_iommu_ops = {
+const struct iommu_functions omap2_iommu_ops = {
        .version        = IOMMU_ARCH_VERSION,
 
        .enable         = omap2_iommu_enable,
@@ -319,19 +319,3 @@ static const struct iommu_functions omap2_iommu_ops = {
        .restore_ctx    = omap2_iommu_restore_ctx,
        .dump_ctx       = omap2_iommu_dump_ctx,
 };
-
-static int __init omap2_iommu_init(void)
-{
-       return omap_install_iommu_arch(&omap2_iommu_ops);
-}
-module_init(omap2_iommu_init);
-
-static void __exit omap2_iommu_exit(void)
-{
-       omap_uninstall_iommu_arch(&omap2_iommu_ops);
-}
-module_exit(omap2_iommu_exit);
-
-MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
-MODULE_DESCRIPTION("omap iommu: omap2/3 architecture specific functions");
-MODULE_LICENSE("GPL v2");
-- 
1.8.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" 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