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/iommu.c') 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 v1.2.3-70-g09d2 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/iommu.c') 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 v1.2.3-70-g09d2 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/iommu.c') 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 v1.2.3-70-g09d2