Merge branch 'v2.6.34-rc7.iommu' of git://gitorious.org/~doyu/lk/mainline into omap...
authorTony Lindgren <tony@atomide.com>
Thu, 20 May 2010 18:14:28 +0000 (11:14 -0700)
committerTony Lindgren <tony@atomide.com>
Thu, 20 May 2010 18:14:28 +0000 (11:14 -0700)
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/iommu2.c
arch/arm/mach-omap2/omap-iommu.c [new file with mode: 0644]
arch/arm/mach-omap2/omap3-iommu.c [deleted file]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/include/plat/omap44xx.h
arch/arm/plat-omap/iommu.c
arch/arm/plat-omap/iovmm.c

index 4b9fc57..7d2cf0f 100644 (file)
@@ -89,10 +89,7 @@ obj-$(CONFIG_OMAP3_EMU)                      += emu.o
 obj-$(CONFIG_OMAP_MBOX_FWK)            += mailbox_mach.o
 mailbox_mach-objs                      := mailbox.o
 
-iommu-y                                        += iommu2.o
-iommu-$(CONFIG_ARCH_OMAP3)             += omap3-iommu.o
-
-obj-$(CONFIG_OMAP_IOMMU)               += $(iommu-y)
+obj-$(CONFIG_OMAP_IOMMU)               := iommu2.o omap-iommu.o
 
 i2c-omap-$(CONFIG_I2C_OMAP)            := i2c.o
 obj-y                                  += $(i2c-omap-m) $(i2c-omap-y)
index 4f63dc6..e82da68 100644 (file)
@@ -147,6 +147,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
        printk("\n");
 
        iommu_write_reg(obj, stat, MMU_IRQSTATUS);
+       omap2_iommu_disable(obj);
        return stat;
 }
 
@@ -184,7 +185,7 @@ static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e)
        if (!cr)
                return ERR_PTR(-ENOMEM);
 
-       cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz;
+       cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz | e->valid;
        cr->ram = e->pa | e->endian | e->elsz | e->mixed;
 
        return cr;
@@ -212,7 +213,8 @@ static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
        char *p = buf;
 
        /* FIXME: Need more detail analysis of cam/ram */
-       p += sprintf(p, "%08x %08x\n", cr->cam, cr->ram);
+       p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram,
+                                       (cr->cam & MMU_CAM_P) ? 1 : 0);
 
        return p - buf;
 }
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
new file mode 100644 (file)
index 0000000..eb9bee7
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * omap iommu: omap device registration
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+
+#include <plat/iommu.h>
+#include <plat/irqs.h>
+
+struct iommu_device {
+       resource_size_t base;
+       int irq;
+       struct iommu_platform_data pdata;
+       struct resource res[2];
+};
+static struct iommu_device *devices;
+static int num_iommu_devices;
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct iommu_device omap3_devices[] = {
+       {
+               .base = 0x480bd400,
+               .irq = 24,
+               .pdata = {
+                       .name = "isp",
+                       .nr_tlb_entries = 8,
+                       .clk_name = "cam_ick",
+               },
+       },
+#if defined(CONFIG_MPU_BRIDGE_IOMMU)
+       {
+               .base = 0x5d000000,
+               .irq = 28,
+               .pdata = {
+                       .name = "iva2",
+                       .nr_tlb_entries = 32,
+                       .clk_name = "iva2_ck",
+               },
+       },
+#endif
+};
+#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices)
+static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES];
+#else
+#define omap3_devices          NULL
+#define NR_OMAP3_IOMMU_DEVICES 0
+#define omap3_iommu_pdev       NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+static struct iommu_device omap4_devices[] = {
+       {
+               .base = OMAP4_MMU1_BASE,
+               .irq = INT_44XX_DUCATI_MMU_IRQ,
+               .pdata = {
+                       .name = "ducati",
+                       .nr_tlb_entries = 32,
+                       .clk_name = "ducati_ick",
+               },
+       },
+#if defined(CONFIG_MPU_TESLA_IOMMU)
+       {
+               .base = OMAP4_MMU2_BASE,
+               .irq = INT_44XX_DSP_MMU,
+               .pdata = {
+                       .name = "tesla",
+                       .nr_tlb_entries = 32,
+                       .clk_name = "tesla_ick",
+               },
+       },
+#endif
+};
+#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices)
+static struct platform_device *omap4_iommu_pdev[NR_OMAP4_IOMMU_DEVICES];
+#else
+#define omap4_devices          NULL
+#define NR_OMAP4_IOMMU_DEVICES 0
+#define omap4_iommu_pdev       NULL
+#endif
+
+static struct platform_device **omap_iommu_pdev;
+
+static int __init omap_iommu_init(void)
+{
+       int i, err;
+       struct resource res[] = {
+               { .flags = IORESOURCE_MEM },
+               { .flags = IORESOURCE_IRQ },
+       };
+
+       if (cpu_is_omap34xx()) {
+               devices = omap3_devices;
+               omap_iommu_pdev = omap3_iommu_pdev;
+               num_iommu_devices = NR_OMAP3_IOMMU_DEVICES;
+       } else if (cpu_is_omap44xx()) {
+               devices = omap4_devices;
+               omap_iommu_pdev = omap4_iommu_pdev;
+               num_iommu_devices = NR_OMAP4_IOMMU_DEVICES;
+       } else
+               return -ENODEV;
+
+       for (i = 0; i < num_iommu_devices; i++) {
+               struct platform_device *pdev;
+               const struct iommu_device *d = &devices[i];
+
+               pdev = platform_device_alloc("omap-iommu", i);
+               if (!pdev) {
+                       err = -ENOMEM;
+                       goto err_out;
+               }
+
+               res[0].start = d->base;
+               res[0].end = d->base + MMU_REG_SIZE - 1;
+               res[1].start = res[1].end = d->irq;
+
+               err = platform_device_add_resources(pdev, res,
+                                                   ARRAY_SIZE(res));
+               if (err)
+                       goto err_out;
+               err = platform_device_add_data(pdev, &d->pdata,
+                                              sizeof(d->pdata));
+               if (err)
+                       goto err_out;
+               err = platform_device_add(pdev);
+               if (err)
+                       goto err_out;
+               omap_iommu_pdev[i] = pdev;
+       }
+       return 0;
+
+err_out:
+       while (i--)
+               platform_device_put(omap_iommu_pdev[i]);
+       return err;
+}
+module_init(omap_iommu_init);
+
+static void __exit omap_iommu_exit(void)
+{
+       int i;
+
+       for (i = 0; i < num_iommu_devices; i++)
+               platform_device_unregister(omap_iommu_pdev[i]);
+}
+module_exit(omap_iommu_exit);
+
+MODULE_AUTHOR("Hiroshi DOYU");
+MODULE_DESCRIPTION("omap iommu: omap device registration");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c
deleted file mode 100644 (file)
index fbbcb5c..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * omap iommu: omap3 device registration
- *
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-
-#include <plat/iommu.h>
-
-struct iommu_device {
-       resource_size_t base;
-       int irq;
-       struct iommu_platform_data pdata;
-       struct resource res[2];
-};
-
-static struct iommu_device devices[] = {
-       {
-               .base = 0x480bd400,
-               .irq = 24,
-               .pdata = {
-                       .name = "isp",
-                       .nr_tlb_entries = 8,
-                       .clk_name = "cam_ick",
-               },
-       },
-#if defined(CONFIG_MPU_BRIDGE_IOMMU)
-       {
-               .base = 0x5d000000,
-               .irq = 28,
-               .pdata = {
-                       .name = "iva2",
-                       .nr_tlb_entries = 32,
-                       .clk_name = "iva2_ck",
-               },
-       },
-#endif
-};
-#define NR_IOMMU_DEVICES ARRAY_SIZE(devices)
-
-static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES];
-
-static int __init omap3_iommu_init(void)
-{
-       int i, err;
-       struct resource res[] = {
-               { .flags = IORESOURCE_MEM },
-               { .flags = IORESOURCE_IRQ },
-       };
-
-       for (i = 0; i < NR_IOMMU_DEVICES; i++) {
-               struct platform_device *pdev;
-               const struct iommu_device *d = &devices[i];
-
-               pdev = platform_device_alloc("omap-iommu", i);
-               if (!pdev) {
-                       err = -ENOMEM;
-                       goto err_out;
-               }
-
-               res[0].start = d->base;
-               res[0].end = d->base + MMU_REG_SIZE - 1;
-               res[1].start = res[1].end = d->irq;
-
-               err = platform_device_add_resources(pdev, res,
-                                                   ARRAY_SIZE(res));
-               if (err)
-                       goto err_out;
-               err = platform_device_add_data(pdev, &d->pdata,
-                                              sizeof(d->pdata));
-               if (err)
-                       goto err_out;
-               err = platform_device_add(pdev);
-               if (err)
-                       goto err_out;
-               omap3_iommu_pdev[i] = pdev;
-       }
-       return 0;
-
-err_out:
-       while (i--)
-               platform_device_put(omap3_iommu_pdev[i]);
-       return err;
-}
-module_init(omap3_iommu_init);
-
-static void __exit omap3_iommu_exit(void)
-{
-       int i;
-
-       for (i = 0; i < NR_IOMMU_DEVICES; i++)
-               platform_device_unregister(omap3_iommu_pdev[i]);
-}
-module_exit(omap3_iommu_exit);
-
-MODULE_AUTHOR("Hiroshi DOYU");
-MODULE_DESCRIPTION("omap iommu: omap3 device registration");
-MODULE_LICENSE("GPL v2");
index 6da796e..78b49a6 100644 (file)
@@ -110,8 +110,13 @@ config OMAP_IOMMU
        tristate
 
 config OMAP_IOMMU_DEBUG
-       depends on OMAP_IOMMU
-       tristate
+       tristate "Export OMAP IOMMU internals in DebugFS"
+       depends on OMAP_IOMMU && DEBUG_FS
+       help
+         Select this to see extensive information about
+         the internal state of OMAP IOMMU in debugfs.
+
+         Say N unless you know you need this.
 
 choice
        prompt "System timer"
index b3ef1a7..bb94a0b 100644 (file)
@@ -48,5 +48,8 @@
 #define OMAP44XX_MAILBOX_BASE          (L4_44XX_BASE + 0xF4000)
 #define OMAP44XX_HSUSB_OTG_BASE                (L4_44XX_BASE + 0xAB000)
 
+#define OMAP4_MMU1_BASE                        0x55082000
+#define OMAP4_MMU2_BASE                        0x4A066000
+
 #endif /* __ASM_ARCH_OMAP44XX_H */
 
index 0e13766..bc094db 100644 (file)
 
 #include "iopgtable.h"
 
+#define for_each_iotlb_cr(obj, n, __i, cr)                             \
+       for (__i = 0;                                                   \
+            (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true);   \
+            __i++)
+
 /* accommodate the difference between omap1 and omap2/3 */
 static const struct iommu_functions *arch_iommu;
 
@@ -172,15 +177,12 @@ static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l)
        l->base = MMU_LOCK_BASE(val);
        l->vict = MMU_LOCK_VICT(val);
 
-       BUG_ON(l->base != 0); /* Currently no preservation is used */
 }
 
 static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l)
 {
        u32 val;
 
-       BUG_ON(l->base != 0); /* Currently no preservation is used */
-
        val = (l->base << MMU_LOCK_BASE_SHIFT);
        val |= (l->vict << MMU_LOCK_VICT_SHIFT);
 
@@ -214,6 +216,20 @@ static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
        return arch_iommu->dump_cr(obj, cr, buf);
 }
 
+/* only used in iotlb iteration for-loop */
+static struct cr_regs __iotlb_read_cr(struct iommu *obj, int n)
+{
+       struct cr_regs cr;
+       struct iotlb_lock l;
+
+       iotlb_lock_get(obj, &l);
+       l.vict = n;
+       iotlb_lock_set(obj, &l);
+       iotlb_read_cr(obj, &cr);
+
+       return cr;
+}
+
 /**
  * load_iotlb_entry - Set an iommu tlb entry
  * @obj:       target iommu
@@ -221,7 +237,6 @@ static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
  **/
 int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
 {
-       int i;
        int err = 0;
        struct iotlb_lock l;
        struct cr_regs *cr;
@@ -231,21 +246,30 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
 
        clk_enable(obj->clk);
 
-       for (i = 0; i < obj->nr_tlb_entries; i++) {
+       iotlb_lock_get(obj, &l);
+       if (l.base == obj->nr_tlb_entries) {
+               dev_warn(obj->dev, "%s: preserve entries full\n", __func__);
+               err = -EBUSY;
+               goto out;
+       }
+       if (!e->prsvd) {
+               int i;
                struct cr_regs tmp;
 
+               for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, tmp)
+                       if (!iotlb_cr_valid(&tmp))
+                               break;
+
+               if (i == obj->nr_tlb_entries) {
+                       dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
+                       err = -EBUSY;
+                       goto out;
+               }
+
                iotlb_lock_get(obj, &l);
-               l.vict = i;
+       } else {
+               l.vict = l.base;
                iotlb_lock_set(obj, &l);
-               iotlb_read_cr(obj, &tmp);
-               if (!iotlb_cr_valid(&tmp))
-                       break;
-       }
-
-       if (i == obj->nr_tlb_entries) {
-               dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
-               err = -EBUSY;
-               goto out;
        }
 
        cr = iotlb_alloc_cr(obj, e);
@@ -257,9 +281,11 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
        iotlb_load_cr(obj, cr);
        kfree(cr);
 
+       if (e->prsvd)
+               l.base++;
        /* increment victim for next tlb load */
        if (++l.vict == obj->nr_tlb_entries)
-               l.vict = 0;
+               l.vict = l.base;
        iotlb_lock_set(obj, &l);
 out:
        clk_disable(obj->clk);
@@ -276,20 +302,15 @@ EXPORT_SYMBOL_GPL(load_iotlb_entry);
  **/
 void flush_iotlb_page(struct iommu *obj, u32 da)
 {
-       struct iotlb_lock l;
        int i;
+       struct cr_regs cr;
 
        clk_enable(obj->clk);
 
-       for (i = 0; i < obj->nr_tlb_entries; i++) {
-               struct cr_regs cr;
+       for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
                u32 start;
                size_t bytes;
 
-               iotlb_lock_get(obj, &l);
-               l.vict = i;
-               iotlb_lock_set(obj, &l);
-               iotlb_read_cr(obj, &cr);
                if (!iotlb_cr_valid(&cr))
                        continue;
 
@@ -299,7 +320,6 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
                if ((start <= da) && (da < start + bytes)) {
                        dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
                                __func__, start, da, bytes);
-                       iotlb_load_cr(obj, &cr);
                        iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
                }
        }
@@ -370,26 +390,19 @@ EXPORT_SYMBOL_GPL(iommu_dump_ctx);
 static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
 {
        int i;
-       struct iotlb_lock saved, l;
+       struct iotlb_lock saved;
+       struct cr_regs tmp;
        struct cr_regs *p = crs;
 
        clk_enable(obj->clk);
-
        iotlb_lock_get(obj, &saved);
-       memcpy(&l, &saved, sizeof(saved));
 
-       for (i = 0; i < num; i++) {
-               struct cr_regs tmp;
-
-               iotlb_lock_get(obj, &l);
-               l.vict = i;
-               iotlb_lock_set(obj, &l);
-               iotlb_read_cr(obj, &tmp);
+       for_each_iotlb_cr(obj, num, i, tmp) {
                if (!iotlb_cr_valid(&tmp))
                        continue;
-
                *p++ = tmp;
        }
+
        iotlb_lock_set(obj, &saved);
        clk_disable(obj->clk);
 
@@ -503,6 +516,12 @@ static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
 {
        u32 *iopgd = iopgd_offset(obj, da);
 
+       if ((da | pa) & ~IOSECTION_MASK) {
+               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
+                       __func__, da, pa, IOSECTION_SIZE);
+               return -EINVAL;
+       }
+
        *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
        flush_iopgd_range(iopgd, iopgd);
        return 0;
@@ -513,6 +532,12 @@ static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
        u32 *iopgd = iopgd_offset(obj, da);
        int i;
 
+       if ((da | pa) & ~IOSUPER_MASK) {
+               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
+                       __func__, da, pa, IOSUPER_SIZE);
+               return -EINVAL;
+       }
+
        for (i = 0; i < 16; i++)
                *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
        flush_iopgd_range(iopgd, iopgd + 15);
@@ -542,6 +567,12 @@ static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot)
        u32 *iopte = iopte_alloc(obj, iopgd, da);
        int i;
 
+       if ((da | pa) & ~IOLARGE_MASK) {
+               dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
+                       __func__, da, pa, IOLARGE_SIZE);
+               return -EINVAL;
+       }
+
        if (IS_ERR(iopte))
                return PTR_ERR(iopte);
 
index 65c6d1f..e43983b 100644 (file)
@@ -287,16 +287,19 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
        prev_end = 0;
        list_for_each_entry(tmp, &obj->mmap, list) {
 
-               if ((prev_end <= start) && (start + bytes < tmp->da_start))
+               if (prev_end >= start)
+                       break;
+
+               if (start + bytes < tmp->da_start)
                        goto found;
 
                if (flags & IOVMF_DA_ANON)
-                       start = roundup(tmp->da_end, alignement);
+                       start = roundup(tmp->da_end + 1, alignement);
 
                prev_end = tmp->da_end;
        }
 
-       if ((start >= prev_end) && (ULONG_MAX - start >= bytes))
+       if ((start > prev_end) && (ULONG_MAX - start >= bytes))
                goto found;
 
        dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",