Commit ad57c394 authored by Tony Lindgren's avatar Tony Lindgren

Merge branch 'v2.6.34-rc7.iommu' of git://gitorious.org/~doyu/lk/mainline into omap-for-linus

parents 0581b52e 4abb7617
...@@ -89,10 +89,7 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o ...@@ -89,10 +89,7 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
mailbox_mach-objs := mailbox.o mailbox_mach-objs := mailbox.o
iommu-y += iommu2.o obj-$(CONFIG_OMAP_IOMMU) := iommu2.o omap-iommu.o
iommu-$(CONFIG_ARCH_OMAP3) += omap3-iommu.o
obj-$(CONFIG_OMAP_IOMMU) += $(iommu-y)
i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
obj-y += $(i2c-omap-m) $(i2c-omap-y) obj-y += $(i2c-omap-m) $(i2c-omap-y)
......
...@@ -147,6 +147,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) ...@@ -147,6 +147,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
printk("\n"); printk("\n");
iommu_write_reg(obj, stat, MMU_IRQSTATUS); iommu_write_reg(obj, stat, MMU_IRQSTATUS);
omap2_iommu_disable(obj);
return stat; return stat;
} }
...@@ -184,7 +185,7 @@ static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e) ...@@ -184,7 +185,7 @@ static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e)
if (!cr) if (!cr)
return ERR_PTR(-ENOMEM); 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; cr->ram = e->pa | e->endian | e->elsz | e->mixed;
return cr; return cr;
...@@ -212,7 +213,8 @@ static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf) ...@@ -212,7 +213,8 @@ static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
char *p = buf; char *p = buf;
/* FIXME: Need more detail analysis of cam/ram */ /* 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; return p - buf;
} }
......
/* /*
* omap iommu: omap3 device registration * omap iommu: omap device registration
* *
* Copyright (C) 2008-2009 Nokia Corporation * Copyright (C) 2008-2009 Nokia Corporation
* *
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <plat/iommu.h> #include <plat/iommu.h>
#include <plat/irqs.h>
struct iommu_device { struct iommu_device {
resource_size_t base; resource_size_t base;
...@@ -20,8 +21,11 @@ struct iommu_device { ...@@ -20,8 +21,11 @@ struct iommu_device {
struct iommu_platform_data pdata; struct iommu_platform_data pdata;
struct resource res[2]; struct resource res[2];
}; };
static struct iommu_device *devices;
static int num_iommu_devices;
static struct iommu_device devices[] = { #ifdef CONFIG_ARCH_OMAP3
static struct iommu_device omap3_devices[] = {
{ {
.base = 0x480bd400, .base = 0x480bd400,
.irq = 24, .irq = 24,
...@@ -43,11 +47,48 @@ static struct iommu_device devices[] = { ...@@ -43,11 +47,48 @@ static struct iommu_device devices[] = {
}, },
#endif #endif
}; };
#define NR_IOMMU_DEVICES ARRAY_SIZE(devices) #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 *omap3_iommu_pdev[NR_IOMMU_DEVICES]; static struct platform_device **omap_iommu_pdev;
static int __init omap3_iommu_init(void) static int __init omap_iommu_init(void)
{ {
int i, err; int i, err;
struct resource res[] = { struct resource res[] = {
...@@ -55,7 +96,18 @@ static int __init omap3_iommu_init(void) ...@@ -55,7 +96,18 @@ static int __init omap3_iommu_init(void)
{ .flags = IORESOURCE_IRQ }, { .flags = IORESOURCE_IRQ },
}; };
for (i = 0; i < NR_IOMMU_DEVICES; i++) { 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; struct platform_device *pdev;
const struct iommu_device *d = &devices[i]; const struct iommu_device *d = &devices[i];
...@@ -80,26 +132,26 @@ static int __init omap3_iommu_init(void) ...@@ -80,26 +132,26 @@ static int __init omap3_iommu_init(void)
err = platform_device_add(pdev); err = platform_device_add(pdev);
if (err) if (err)
goto err_out; goto err_out;
omap3_iommu_pdev[i] = pdev; omap_iommu_pdev[i] = pdev;
} }
return 0; return 0;
err_out: err_out:
while (i--) while (i--)
platform_device_put(omap3_iommu_pdev[i]); platform_device_put(omap_iommu_pdev[i]);
return err; return err;
} }
module_init(omap3_iommu_init); module_init(omap_iommu_init);
static void __exit omap3_iommu_exit(void) static void __exit omap_iommu_exit(void)
{ {
int i; int i;
for (i = 0; i < NR_IOMMU_DEVICES; i++) for (i = 0; i < num_iommu_devices; i++)
platform_device_unregister(omap3_iommu_pdev[i]); platform_device_unregister(omap_iommu_pdev[i]);
} }
module_exit(omap3_iommu_exit); module_exit(omap_iommu_exit);
MODULE_AUTHOR("Hiroshi DOYU"); MODULE_AUTHOR("Hiroshi DOYU");
MODULE_DESCRIPTION("omap iommu: omap3 device registration"); MODULE_DESCRIPTION("omap iommu: omap device registration");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -110,8 +110,13 @@ config OMAP_IOMMU ...@@ -110,8 +110,13 @@ config OMAP_IOMMU
tristate tristate
config OMAP_IOMMU_DEBUG config OMAP_IOMMU_DEBUG
depends on OMAP_IOMMU tristate "Export OMAP IOMMU internals in DebugFS"
tristate 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 choice
prompt "System timer" prompt "System timer"
......
...@@ -48,5 +48,8 @@ ...@@ -48,5 +48,8 @@
#define OMAP44XX_MAILBOX_BASE (L4_44XX_BASE + 0xF4000) #define OMAP44XX_MAILBOX_BASE (L4_44XX_BASE + 0xF4000)
#define OMAP44XX_HSUSB_OTG_BASE (L4_44XX_BASE + 0xAB000) #define OMAP44XX_HSUSB_OTG_BASE (L4_44XX_BASE + 0xAB000)
#define OMAP4_MMU1_BASE 0x55082000
#define OMAP4_MMU2_BASE 0x4A066000
#endif /* __ASM_ARCH_OMAP44XX_H */ #endif /* __ASM_ARCH_OMAP44XX_H */
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
#include "iopgtable.h" #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 */ /* accommodate the difference between omap1 and omap2/3 */
static const struct iommu_functions *arch_iommu; static const struct iommu_functions *arch_iommu;
...@@ -172,15 +177,12 @@ static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l) ...@@ -172,15 +177,12 @@ static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l)
l->base = MMU_LOCK_BASE(val); l->base = MMU_LOCK_BASE(val);
l->vict = MMU_LOCK_VICT(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) static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l)
{ {
u32 val; u32 val;
BUG_ON(l->base != 0); /* Currently no preservation is used */
val = (l->base << MMU_LOCK_BASE_SHIFT); val = (l->base << MMU_LOCK_BASE_SHIFT);
val |= (l->vict << MMU_LOCK_VICT_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, ...@@ -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); 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 * load_iotlb_entry - Set an iommu tlb entry
* @obj: target iommu * @obj: target iommu
...@@ -221,7 +237,6 @@ static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr, ...@@ -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 load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
{ {
int i;
int err = 0; int err = 0;
struct iotlb_lock l; struct iotlb_lock l;
struct cr_regs *cr; struct cr_regs *cr;
...@@ -231,21 +246,30 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) ...@@ -231,21 +246,30 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
clk_enable(obj->clk); 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; 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); iotlb_lock_get(obj, &l);
l.vict = i; } else {
l.vict = l.base;
iotlb_lock_set(obj, &l); 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); cr = iotlb_alloc_cr(obj, e);
...@@ -257,9 +281,11 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) ...@@ -257,9 +281,11 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
iotlb_load_cr(obj, cr); iotlb_load_cr(obj, cr);
kfree(cr); kfree(cr);
if (e->prsvd)
l.base++;
/* increment victim for next tlb load */ /* increment victim for next tlb load */
if (++l.vict == obj->nr_tlb_entries) if (++l.vict == obj->nr_tlb_entries)
l.vict = 0; l.vict = l.base;
iotlb_lock_set(obj, &l); iotlb_lock_set(obj, &l);
out: out:
clk_disable(obj->clk); clk_disable(obj->clk);
...@@ -276,20 +302,15 @@ EXPORT_SYMBOL_GPL(load_iotlb_entry); ...@@ -276,20 +302,15 @@ EXPORT_SYMBOL_GPL(load_iotlb_entry);
**/ **/
void flush_iotlb_page(struct iommu *obj, u32 da) void flush_iotlb_page(struct iommu *obj, u32 da)
{ {
struct iotlb_lock l;
int i; int i;
struct cr_regs cr;
clk_enable(obj->clk); clk_enable(obj->clk);
for (i = 0; i < obj->nr_tlb_entries; i++) { for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
struct cr_regs cr;
u32 start; u32 start;
size_t bytes; 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)) if (!iotlb_cr_valid(&cr))
continue; continue;
...@@ -299,7 +320,6 @@ void flush_iotlb_page(struct iommu *obj, u32 da) ...@@ -299,7 +320,6 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
if ((start <= da) && (da < start + bytes)) { if ((start <= da) && (da < start + bytes)) {
dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n", dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
__func__, start, da, bytes); __func__, start, da, bytes);
iotlb_load_cr(obj, &cr);
iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
} }
} }
...@@ -370,26 +390,19 @@ EXPORT_SYMBOL_GPL(iommu_dump_ctx); ...@@ -370,26 +390,19 @@ EXPORT_SYMBOL_GPL(iommu_dump_ctx);
static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num) static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
{ {
int i; int i;
struct iotlb_lock saved, l; struct iotlb_lock saved;
struct cr_regs tmp;
struct cr_regs *p = crs; struct cr_regs *p = crs;
clk_enable(obj->clk); clk_enable(obj->clk);
iotlb_lock_get(obj, &saved); iotlb_lock_get(obj, &saved);
memcpy(&l, &saved, sizeof(saved));
for (i = 0; i < num; i++) { for_each_iotlb_cr(obj, num, i, tmp) {
struct cr_regs tmp;
iotlb_lock_get(obj, &l);
l.vict = i;
iotlb_lock_set(obj, &l);
iotlb_read_cr(obj, &tmp);
if (!iotlb_cr_valid(&tmp)) if (!iotlb_cr_valid(&tmp))
continue; continue;
*p++ = tmp; *p++ = tmp;
} }
iotlb_lock_set(obj, &saved); iotlb_lock_set(obj, &saved);
clk_disable(obj->clk); clk_disable(obj->clk);
...@@ -503,6 +516,12 @@ static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot) ...@@ -503,6 +516,12 @@ static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
{ {
u32 *iopgd = iopgd_offset(obj, da); 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; *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
flush_iopgd_range(iopgd, iopgd); flush_iopgd_range(iopgd, iopgd);
return 0; return 0;
...@@ -513,6 +532,12 @@ static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot) ...@@ -513,6 +532,12 @@ static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
u32 *iopgd = iopgd_offset(obj, da); u32 *iopgd = iopgd_offset(obj, da);
int i; 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++) for (i = 0; i < 16; i++)
*(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER; *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
flush_iopgd_range(iopgd, iopgd + 15); flush_iopgd_range(iopgd, iopgd + 15);
...@@ -542,6 +567,12 @@ static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot) ...@@ -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); u32 *iopte = iopte_alloc(obj, iopgd, da);
int i; 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)) if (IS_ERR(iopte))
return PTR_ERR(iopte); return PTR_ERR(iopte);
......
...@@ -287,16 +287,19 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, ...@@ -287,16 +287,19 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
prev_end = 0; prev_end = 0;
list_for_each_entry(tmp, &obj->mmap, list) { 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; goto found;
if (flags & IOVMF_DA_ANON) if (flags & IOVMF_DA_ANON)
start = roundup(tmp->da_end, alignement); start = roundup(tmp->da_end + 1, alignement);
prev_end = tmp->da_end; prev_end = tmp->da_end;
} }
if ((start >= prev_end) && (ULONG_MAX - start >= bytes)) if ((start > prev_end) && (ULONG_MAX - start >= bytes))
goto found; goto found;
dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n", dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment