|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v02 2/7] arm: omap: introduce iommu translation for IPU remoteproc
The following patch introduced platform specific MMU data
definitions and pagetable translation function for OMAP5 IPU
remoteproc. This MMU is a bit specific - it typically performs
one level translation and map a big chunks of memory. 16 Mb
supersections and 1 Mb sections are mapped instead of 4 Kb pages.
Introduced algorithm performs internal remapping of big sections
to small 4 Kb pages.
Change-Id: If20449f07e22f780e1fded67fed4f79cbe1fc156
Signed-off-by: Andrii Tseglytskyi <andrii.tseglytskyi@xxxxxxxxxxxxxxx>
---
xen/arch/arm/platforms/Makefile | 1 +
xen/arch/arm/platforms/omap_iommu.c | 247 +++++++++++++++++++++++++++++++++++
xen/arch/arm/remoteproc_iommu.c | 1 +
xen/include/xen/remoteproc_iommu.h | 2 +
4 files changed, 251 insertions(+)
create mode 100644 xen/arch/arm/platforms/omap_iommu.c
diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile
index 080ea9a..f224f08 100644
--- a/xen/arch/arm/platforms/Makefile
+++ b/xen/arch/arm/platforms/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_ARM_32) += midway.o
obj-$(CONFIG_ARM_32) += omap5.o
obj-$(CONFIG_ARM_32) += dra7xx.o
obj-$(CONFIG_ARM_32) += sunxi.o
+obj-$(CONFIG_ARM_32) += omap_iommu.o
obj-$(CONFIG_ARM_64) += xgene-storm.o
diff --git a/xen/arch/arm/platforms/omap_iommu.c
b/xen/arch/arm/platforms/omap_iommu.c
new file mode 100644
index 0000000..e0c4633
--- /dev/null
+++ b/xen/arch/arm/platforms/omap_iommu.c
@@ -0,0 +1,247 @@
+/*
+ * xen/arch/arm/platforms/omap_iommu.c
+ *
+ * Andrii Tseglytskyi <andrii.tseglytskyi@xxxxxxxxxxxxxxx>
+ * Copyright (c) 2014 GlobalLogic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/stdbool.h>
+#include <xen/mm.h>
+#include <xen/vmap.h>
+#include <xen/sched.h>
+#include <xen/remoteproc_iommu.h>
+
+#include <asm/p2m.h>
+
+/*
+ * "L2 table" address mask and size definitions.
+ */
+
+/* register where address of pagetable is stored */
+#define MMU_IPU_TTB_OFFSET 0x4c
+
+/* 1st level translation */
+#define MMU_OMAP_PGD_SHIFT 20
+#define MMU_OMAP_SUPER_SHIFT 24 /* "supersection" - 16 Mb */
+#define MMU_OMAP_SECTION_SHIFT 20 /* "section" - 1 Mb */
+#define MMU_OMAP_SECOND_LEVEL_SHIFT 10
+
+/* 2nd level translation */
+#define MMU_OMAP_PTE_SMALL_SHIFT 12 /* "small page" - 4Kb */
+#define MMU_OMAP_PTE_LARGE_SHIFT 16 /* "large page" - 64 Kb */
+
+/*
+ * some descriptor attributes.
+ */
+#define PGD_TABLE (1 << 0)
+#define PGD_SECTION (2 << 0)
+#define PGD_SUPER (1 << 18 | 2 << 0)
+
+#define ipu_pgd_is_table(x) (((x) & 3) == PGD_TABLE)
+#define ipu_pgd_is_section(x) (((x) & (1 << 18 | 3)) == PGD_SECTION)
+#define ipu_pgd_is_super(x) (((x) & (1 << 18 | 3)) == PGD_SUPER)
+
+#define PTE_SMALL (2 << 0)
+#define PTE_LARGE (1 << 0)
+
+#define OMAP_IPU_MMU_MEM_BASE 0x55082000
+
+static u32 mmu_ipu_translate_pagetable(struct mmu_info *mmu, struct
mmu_pagetable *pgt);
+
+static u32 ipu_trap_offsets[] = {
+ MMU_IPU_TTB_OFFSET,
+};
+
+static const struct pagetable_data pagetable_ipu_data = {
+ .pgd_shift = MMU_OMAP_PGD_SHIFT,
+ .super_shift = MMU_OMAP_SUPER_SHIFT,
+ .section_shift = MMU_OMAP_SECTION_SHIFT,
+ .pte_shift = MMU_OMAP_PTE_SMALL_SHIFT,
+ .pte_large_shift = MMU_OMAP_PTE_LARGE_SHIFT,
+};
+
+struct mmu_info omap_ipu_mmu = {
+ .name = "IPU_L2_MMU",
+ .pg_data = &pagetable_ipu_data,
+ .trap_offsets = ipu_trap_offsets,
+ .mem_start = OMAP_IPU_MMU_MEM_BASE,
+ .mem_size = 0x1000,
+ .num_traps = ARRAY_SIZE(ipu_trap_offsets),
+ .translate_pfunc = mmu_ipu_translate_pagetable,
+};
+
+static bool translate_supersections_to_pages = true;
+static bool translate_sections_to_pages = true;
+
+static u32 mmu_pte_table_alloc(struct mmu_info *mmu, u32 pgd, u32 sect_num,
+ struct mmu_pagetable *pgt, u32 hyp_addr)
+{
+ u32 *pte = NULL;
+ u32 i;
+
+ /* allocate pte table once */
+ if ( 0 == hyp_addr )
+ {
+ pte = xzalloc_bytes(PAGE_SIZE);
+ if ( !pte )
+ {
+ pr_mmu("failed to alloc 2nd level table");
+ return 0;
+ }
+ }
+ else
+ {
+ pte = __va(hyp_addr & MMU_SECTION_MASK(mmu->pg_data->pte_shift));
+ }
+
+ ASSERT(256 == MMU_PTRS_PER_PTE(mmu));
+
+ for ( i = 0; i < MMU_PTRS_PER_PTE(mmu); i++ )
+ {
+ u32 paddr, maddr;
+
+ paddr = pgd + (i * PAGE_SIZE);
+ maddr = p2m_lookup(current->domain, paddr, NULL);
+ ASSERT(maddr != INVALID_PADDR);
+
+ pte[i] = maddr | PTE_SMALL;
+ pgt->page_counter++;
+ }
+
+ clean_and_invalidate_xen_dcache_va_range(pte, PAGE_SIZE);
+ return __pa(pte) | PGD_TABLE;
+}
+
+static u32 mmu_ipu_translate_pagetable(struct mmu_info *mmu, struct
mmu_pagetable *pgt)
+{
+ u32 *kern_pgt, *hyp_pgt;
+ const struct pagetable_data *data;
+ u32 i;
+
+ ASSERT(mmu);
+ ASSERT(pgt);
+
+ data = mmu->pg_data;
+ kern_pgt = pgt->kern_pagetable;
+ hyp_pgt = pgt->hyp_pagetable;
+ pgt->page_counter = 0;
+
+ ASSERT(4096 == MMU_PTRS_PER_PGD(mmu));
+
+ /* 1-st level translation */
+ for ( i = 0; i < MMU_PTRS_PER_PGD(mmu); i++ )
+ {
+ paddr_t pd_maddr, pd_paddr, pd_flags;
+ u32 pd_mask;
+ u32 pgd_tmp, pgd = kern_pgt[i];
+
+ if ( !pgd )
+ {
+ /* handle the case when second level translation table
+ * was removed from kernel */
+ if ( unlikely(hyp_pgt[i]) )
+ {
+ xfree(__va(hyp_pgt[i] &
MMU_SECTION_MASK(MMU_OMAP_SECOND_LEVEL_SHIFT)));
+ hyp_pgt[i] = 0;
+ }
+
+ continue;
+ }
+
+ /* first level pointers have different formats, depending on their
type */
+ if ( ipu_pgd_is_super(pgd) )
+ pd_mask = MMU_SECTION_MASK(MMU_OMAP_SUPER_SHIFT);
+ else if ( ipu_pgd_is_section(pgd) )
+ pd_mask = MMU_SECTION_MASK(MMU_OMAP_SECTION_SHIFT);
+ else if ( ipu_pgd_is_table(pgd) )
+ pd_mask = MMU_SECTION_MASK(MMU_OMAP_SECOND_LEVEL_SHIFT);
+
+ pd_paddr = pgd & pd_mask;
+ pd_flags = pgd & ~pd_mask;
+ pd_maddr = p2m_lookup(current->domain, pd_paddr, NULL);
+ ASSERT(pd_maddr != INVALID_PADDR);
+
+ /* "supersection" 16 Mb */
+ if ( ipu_pgd_is_super(pgd) )
+ {
+ /* mapping of 16 Mb chunk is fragmented to 4 Kb pages */
+ if( likely(translate_supersections_to_pages) )
+ {
+ u32 j;
+
+ ASSERT(16 == MMU_SECTION_PER_SUPER(mmu));
+ ASSERT(1048576 == MMU_SECTION_SIZE(data->section_shift));
+
+ /* 16 Mb supersection is divided to 16 sections of 1 MB size */
+ for ( j = 0 ; j < MMU_SECTION_PER_SUPER(mmu); j++ )
+ {
+ pgd_tmp = (pgd & ~PGD_SUPER) + (j *
MMU_SECTION_SIZE(data->section_shift));
+ hyp_pgt[i + j] = mmu_pte_table_alloc(mmu, pgd_tmp, i, pgt,
hyp_pgt[i + j]);
+ }
+
+ /* move counter after supersection is translated */
+ i += (j - 1);
+ }
+ else
+ {
+ hyp_pgt[i] = pd_maddr | pd_flags;
+ }
+
+ /* "section" 1Mb */
+ }
+ else if ( ipu_pgd_is_section(pgd) )
+ {
+ if ( likely(translate_sections_to_pages) )
+ {
+ pgd_tmp = (pgd & ~PGD_SECTION);
+ hyp_pgt[i] = mmu_pte_table_alloc(mmu, pgd_tmp, i, pgt,
hyp_pgt[i]);
+ }
+ else
+ {
+ hyp_pgt[i] = pd_maddr | pd_flags;
+ }
+
+ /* "table" */
+ }
+ else if ( unlikely(ipu_pgd_is_table(pgd)) )
+ {
+ ASSERT(4096 == MMU_PTRS_PER_PGD(mmu));
+ ASSERT(256 == MMU_PTRS_PER_PTE(mmu));
+
+ hyp_pgt[i] = mmu_translate_second_level(mmu, pgt, pd_maddr,
hyp_pgt[i]);
+ hyp_pgt[i] |= pd_flags;
+
+ /* error */
+ }
+ else
+ {
+ pr_mmu("unknown entry %u: 0x%08x", i, pgd);
+ return MMU_INVALID_ADDRESS;
+ }
+ }
+
+ /* force omap IOMMU to use new pagetable */
+ clean_and_invalidate_xen_dcache_va_range(hyp_pgt, MMU_PGD_TABLE_SIZE(mmu));
+ return __pa(hyp_pgt);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/remoteproc_iommu.c b/xen/arch/arm/remoteproc_iommu.c
index b4d22d9..8291f3f 100644
--- a/xen/arch/arm/remoteproc_iommu.c
+++ b/xen/arch/arm/remoteproc_iommu.c
@@ -33,6 +33,7 @@
#include "io.h"
static struct mmu_info *mmu_list[] = {
+ &omap_ipu_mmu,
};
#define mmu_for_each(pfunc, data) \
diff --git a/xen/include/xen/remoteproc_iommu.h
b/xen/include/xen/remoteproc_iommu.h
index 22e2951..ff1c439 100644
--- a/xen/include/xen/remoteproc_iommu.h
+++ b/xen/include/xen/remoteproc_iommu.h
@@ -76,4 +76,6 @@ struct mmu_info {
u32 mmu_translate_second_level(struct mmu_info *mmu, struct mmu_pagetable *pgt,
u32 maddr, u32 hyp_addr);
+extern struct mmu_info omap_ipu_mmu;
+
#endif /* _REMOTEPROC_IOMMU_H_ */
--
1.7.9.5
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |