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