[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v02 2/7] arm: omap: introduce iommu translation for IPU remoteproc
On Thu, 26 Jun 2014, Andrii Tseglytskyi wrote: > 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); Here is where you would need to make sure that paddr->maddr doesn't change in the future by pinning the mapping. > + 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 > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |