[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 |