On Fri, Oct 25, 2019 at 07:08:39PM +0100, Robin Murphy wrote:
> Now that we can correctly extract top-level indices without relying on
> the remaining upper bits being zero, the only remaining impediments to
> using a given table for TTBR1 are the address validation on map/unmap
> and the awkward TCR translation granule format. Add a quirk so that we
> can do the right thing at those points.

Tested-by: Jordan Crouse <jcro...@codeaurora.org>

> Signed-off-by: Robin Murphy <robin.mur...@arm.com>
> ---
>  drivers/iommu/io-pgtable-arm.c | 25 +++++++++++++++++++------
>  include/linux/io-pgtable.h     |  4 ++++
>  2 files changed, 23 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
> index 9b1912ede000..e53edff56e54 100644
> --- a/drivers/iommu/io-pgtable-arm.c
> +++ b/drivers/iommu/io-pgtable-arm.c
> @@ -107,6 +107,10 @@
>  #define ARM_LPAE_TCR_TG0_64K         1
>  #define ARM_LPAE_TCR_TG0_16K         2
>  
> +#define ARM_LPAE_TCR_TG1_16K         1
> +#define ARM_LPAE_TCR_TG1_4K          2
> +#define ARM_LPAE_TCR_TG1_64K         3
> +
>  #define ARM_LPAE_TCR_SH0_SHIFT               12
>  #define ARM_LPAE_TCR_SH_NS           0
>  #define ARM_LPAE_TCR_SH_OS           2
> @@ -466,6 +470,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, 
> unsigned long iova,
>       arm_lpae_iopte *ptep = data->pgd;
>       int ret, lvl = data->start_level;
>       arm_lpae_iopte prot;
> +     long iaext = (long)iova >> cfg->ias;
>  
>       /* If no access, then nothing to do */
>       if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
> @@ -474,7 +479,9 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, 
> unsigned long iova,
>       if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
>               return -EINVAL;
>  
> -     if (WARN_ON(iova >> data->iop.cfg.ias || paddr >> data->iop.cfg.oas))
> +     if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
> +             iaext = ~iaext;
> +     if (WARN_ON(iaext || paddr >> cfg->oas))
>               return -ERANGE;
>  
>       prot = arm_lpae_prot_to_pte(data, iommu_prot);
> @@ -640,11 +647,14 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops 
> *ops, unsigned long iova,
>       struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
>       struct io_pgtable_cfg *cfg = &data->iop.cfg;
>       arm_lpae_iopte *ptep = data->pgd;
> +     long iaext = (long)iova >> cfg->ias;
>  
>       if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
>               return 0;
>  
> -     if (WARN_ON(iova >> data->iop.cfg.ias))
> +     if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
> +             iaext = ~iaext;
> +     if (WARN_ON(iaext))
>               return 0;
>  
>       return __arm_lpae_unmap(data, gather, iova, size, data->start_level, 
> ptep);
> @@ -780,9 +790,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, 
> void *cookie)
>       u64 reg;
>       struct arm_lpae_io_pgtable *data;
>       typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr;
> +     bool tg1;
>  
>       if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
> -                         IO_PGTABLE_QUIRK_NON_STRICT))
> +                         IO_PGTABLE_QUIRK_NON_STRICT |
> +                         IO_PGTABLE_QUIRK_ARM_TTBR1))
>               return NULL;
>  
>       data = arm_lpae_alloc_pgtable(cfg);
> @@ -800,15 +812,16 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg 
> *cfg, void *cookie)
>               tcr->orgn = ARM_LPAE_TCR_RGN_NC;
>       }
>  
> +     tg1 = cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1;
>       switch (ARM_LPAE_GRANULE(data)) {
>       case SZ_4K:
> -             tcr->tg = ARM_LPAE_TCR_TG0_4K;
> +             tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_4K : ARM_LPAE_TCR_TG0_4K;
>               break;
>       case SZ_16K:
> -             tcr->tg = ARM_LPAE_TCR_TG0_16K;
> +             tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_16K : ARM_LPAE_TCR_TG0_16K;
>               break;
>       case SZ_64K:
> -             tcr->tg = ARM_LPAE_TCR_TG0_64K;
> +             tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_64K : ARM_LPAE_TCR_TG0_64K;
>               break;
>       }
>  
> diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
> index 6ae104cedfd7..d7c5cb685e50 100644
> --- a/include/linux/io-pgtable.h
> +++ b/include/linux/io-pgtable.h
> @@ -83,12 +83,16 @@ struct io_pgtable_cfg {
>        * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs
>        *      on unmap, for DMA domains using the flush queue mechanism for
>        *      delayed invalidation.
> +      *
> +      * IO_PGTABLE_QUIRK_ARM_TTBR1: (ARM LPAE format) Configure the table
> +      *      for use in the upper half of a split address space.
>        */
>       #define IO_PGTABLE_QUIRK_ARM_NS         BIT(0)
>       #define IO_PGTABLE_QUIRK_NO_PERMS       BIT(1)
>       #define IO_PGTABLE_QUIRK_TLBI_ON_MAP    BIT(2)
>       #define IO_PGTABLE_QUIRK_ARM_MTK_EXT    BIT(3)
>       #define IO_PGTABLE_QUIRK_NON_STRICT     BIT(4)
> +     #define IO_PGTABLE_QUIRK_ARM_TTBR1      BIT(5)
>       unsigned long                   quirks;
>       unsigned long                   pgsize_bitmap;
>       unsigned int                    ias;
> -- 
> 2.21.0.dirty
> 

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to