From f779f9235f5fcaa887747ee13195efd81d09acce Mon Sep 17 00:00:00 2001 From: "Kanigeri, Hari" Date: Thu, 22 Apr 2010 23:26:09 +0000 Subject: omap iommu: support for OMAP4 This patch provides the iommu support for OMAP4 co-processors. Signed-off-by: Hari Kanigeri Signed-off-by: Hiroshi DOYU --- arch/arm/plat-omap/include/plat/omap44xx.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h index b3ef1a7f53c..bb94a0baee8 100644 --- a/arch/arm/plat-omap/include/plat/omap44xx.h +++ b/arch/arm/plat-omap/include/plat/omap44xx.h @@ -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 */ -- cgit From be6d8026a276e35cce1a2effaf5cd8bf6bd04814 Mon Sep 17 00:00:00 2001 From: "Kanigeri, Hari" Date: Thu, 22 Apr 2010 23:26:11 +0000 Subject: omap iommu: add TLB preservation support This patch adds TLB preservation support to IOMMU module Signed-off-by: Hari Kanigeri Signed-off-by: Hiroshi DOYU --- arch/arm/plat-omap/iommu.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 0e137663349..1e83facb6b7 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -172,15 +172,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); @@ -231,22 +228,32 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) clk_enable(obj->clk); - for (i = 0; i < obj->nr_tlb_entries; i++) { - 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)) - break; - } - - if (i == obj->nr_tlb_entries) { - dev_dbg(obj->dev, "%s: full: no entry\n", __func__); + 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) { + for (i = l.base; i < obj->nr_tlb_entries; i++) { + 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)) + break; + } + if (i == obj->nr_tlb_entries) { + dev_dbg(obj->dev, "%s: full: no entry\n", __func__); + err = -EBUSY; + goto out; + } + } else { + l.vict = l.base; + iotlb_lock_set(obj, &l); + } cr = iotlb_alloc_cr(obj, e); if (IS_ERR(cr)) { @@ -257,9 +264,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); -- cgit From 37c2836c459181cc2ec24827f549a7238e7db39c Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Tue, 27 Apr 2010 05:37:12 +0000 Subject: omap iommu: Introduce iteration macro for iotlb entry scan There are some places to scan iotlb entries. This iteration macro could make these code a bit simpler with proceeding iotlb entries transparently. Signed-off-by: Hiroshi DOYU Tested-by: Hari Kanigeri --- arch/arm/plat-omap/iommu.c | 58 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 27 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 1e83facb6b7..9598d40e276 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -25,6 +25,11 @@ #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; @@ -211,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 @@ -218,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; @@ -235,21 +253,20 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) goto out; } if (!e->prsvd) { - for (i = l.base; i < obj->nr_tlb_entries; i++) { - struct cr_regs tmp; + int 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, 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); } else { l.vict = l.base; iotlb_lock_set(obj, &l); @@ -285,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; @@ -308,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); } } @@ -379,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); -- cgit From 347815fcc63ac4c4a975bf3ca2c889c2f843ae0d Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Tue, 4 May 2010 14:52:17 +0300 Subject: omap iommu: Make CONFIG_OMAP_IOMMU_DEBUG selectable This CONFIG_OMAP_IOMMU_DEBUG option cannot be selected because it's not visible on menu. Make this option selectable. Signed-off-by: Hiroshi DOYU Cc: Laurent Pinchart --- arch/arm/plat-omap/Kconfig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 6da796ef82b..78b49a626d0 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -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" -- cgit From fa460b88e0cc2b4254271be2da49e68d748db727 Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Thu, 6 May 2010 16:10:18 +0300 Subject: omap iommu: Insert a gap page between IOVMAs against override Inserting a gap page between IOVMAs could detect an override on other IOVMA with iommu fault. This was originally suggested by Sakari Ailus and based on the work and comment by David Cohen. Signed-off-by: Hiroshi DOYU Cc: David Cohen Cc: Sakari Ailus --- arch/arm/plat-omap/iovmm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index 65c6d1ff723..5afe0135b97 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -287,16 +287,16 @@ 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) && (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", -- cgit From e0a42e4fcb6bf9f93c7e63246738333040263e3e Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Thu, 6 May 2010 17:09:25 +0300 Subject: omap iommu: Exit iteration if no possibility of available area Searching avaialable spaces should be stopped as soon as it turns out that there's no possibility with the rest of it. Signed-off-by: Hiroshi DOYU --- arch/arm/plat-omap/iovmm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index 5afe0135b97..e43983ba59c 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -287,7 +287,10 @@ 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) -- cgit From 4abb761749abfb4ec403e4054f9dae2ee604e54f Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Thu, 6 May 2010 18:24:04 +0300 Subject: omap iommu: Reject unaligned addresses at setting page table entry This rejects unaligned device virtual address('da') and physical address('pa') and informs error to caller when a page table entry is set. Otherwise, a wrong address can be used by IO device. Signed-off-by: Hiroshi DOYU Cc: Hari Kanigeri --- arch/arm/plat-omap/iommu.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 9598d40e276..bc094dbacee 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -516,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; @@ -526,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); @@ -555,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); -- cgit