[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.