From 2281bbc545bb8fcc3115e50d41e72b317b056782 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 5 Dec 2019 15:38:46 -0800 Subject: [PATCH 1/2] iommu/iova: Support disabling domain iova alignment Currently the IOVA framework automatically applies IOVA alignment to provided IOVAs based on the requested IOVA size and the alignment configs which are enabled. Some clients who don't require any IOVA alignment would benefit from the reduced fragmentation that would result from disabling IOVA alignment. Add support to allow clients to disable IOVA alignment on an IOMMU domain. Change-Id: Ifa6a75576e7a084c443abf38726d790b883f00b3 Signed-off-by: Patrick Daly [lmark@codeaurora.org: cleanup change] Signed-off-by: Liam Mark --- drivers/iommu/Kconfig | 16 ++++++++++++++++ drivers/iommu/dma-iommu.c | 21 +++++++++++++++++++++ drivers/iommu/iova.c | 8 ++++++++ include/linux/dma-iommu.h | 16 ++++++++++++++++ include/linux/iova.h | 3 +++ 5 files changed, 64 insertions(+) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index e58534f5a48d..0e6a77626aec 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -35,6 +35,22 @@ config IOMMU_IOVA_ALIGNMENT The order is expressed a power of two multiplied by the PAGE_SIZE. If unsure, leave the default value "9". + +config DMA_CONFIGURE_ALIGNMENT + bool "Configure IOVA alignment" + help + Currently the IOVA framework automatically applies IOVA + alignment to provided IOVAs based on the requested IOVA size and + the alignment configs which are enabled. + + Some clients who don't require any IOVA alignment would + benefit from the reduced fragmentation that would result from + disabling IOVA alignment. + + Enable this option to allow clients to disable IOVA alignment on + an IOMMU domain. + + If unsure, say N. endif menuconfig IOMMU_SUPPORT diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index a06832d10321..f708eb80247f 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -400,6 +400,27 @@ int iommu_dma_enable_best_fit_algo(struct device *dev) } EXPORT_SYMBOL(iommu_dma_enable_best_fit_algo); +#ifdef CONFIG_DMA_CONFIGURE_ALIGNMENT +/* + * Should be called prior to using dma-apis. + */ +int iommu_dma_configure_alignment(struct device *dev, bool force_no_align) +{ + struct iommu_domain *domain; + struct iova_domain *iovad; + + domain = iommu_get_domain_for_dev(dev); + if (!domain || !domain->iova_cookie) + return -EINVAL; + + iovad = &((struct iommu_dma_cookie *)domain->iova_cookie)->iovad; + + iovad->force_no_align = force_no_align; + return 0; +} +EXPORT_SYMBOL(iommu_dma_configure_alignment); +#endif + /** * dma_info_to_prot - Translate DMA API directions and attributes to IOMMU API * page flags. diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 4eec92be81fe..e9dc3e3cdf7f 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -51,6 +51,9 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule, rb_link_node(&iovad->anchor.node, NULL, &iovad->rbroot.rb_node); rb_insert_color(&iovad->anchor.node, &iovad->rbroot); iovad->best_fit = false; +#ifdef CONFIG_DMA_CONFIGURE_ALIGNMENT + iovad->force_no_align = false; +#endif init_iova_rcaches(iovad); } EXPORT_SYMBOL_GPL(init_iova_domain); @@ -385,6 +388,11 @@ alloc_iova(struct iova_domain *iovad, unsigned long size, if (!new_iova) return NULL; +#ifdef CONFIG_DMA_CONFIGURE_ALIGNMENT + if (iovad->force_no_align) + size_aligned = false; +#endif + if (iovad->best_fit) { ret = __alloc_and_insert_iova_best_fit(iovad, size, limit_pfn + 1, new_iova, size_aligned); diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index 42f60dbdc1ef..794a1e11d855 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -58,6 +58,16 @@ int iommu_dma_reserve_iova(struct device *dev, dma_addr_t base, int iommu_dma_enable_best_fit_algo(struct device *dev); +#ifdef CONFIG_DMA_CONFIGURE_ALIGNMENT +int iommu_dma_configure_alignment(struct device *dev, bool force_no_align); +#else /* CONFIG_DMA_CONFIGURE_ALIGNMENT */ +static inline int iommu_dma_configure_alignment(struct device *dev, + bool force_no_align) +{ + return -ENOTSUPP; +} +#endif + #else /* CONFIG_IOMMU_DMA */ struct iommu_domain; @@ -110,5 +120,11 @@ static inline int iommu_dma_enable_best_fit_algo(struct device *dev) return -ENODEV; } +static inline int iommu_dma_configure_alignment(struct device *dev, + bool force_no_align) +{ + return -ENODEV; +} + #endif /* CONFIG_IOMMU_DMA */ #endif /* __DMA_IOMMU_H */ diff --git a/include/linux/iova.h b/include/linux/iova.h index 58713bb72a48..e2da73217721 100644 --- a/include/linux/iova.h +++ b/include/linux/iova.h @@ -96,6 +96,9 @@ struct iova_domain { atomic_t fq_timer_on; /* 1 when timer is active, 0 when not */ bool best_fit; +#ifdef CONFIG_DMA_CONFIGURE_ALIGNMENT + bool force_no_align; +#endif }; static inline unsigned long iova_size(struct iova *iova) From 4abcdc70ab280f672e80fca1012083e1daa7da84 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 24 Apr 2020 10:01:26 -0700 Subject: [PATCH 2/2] defconfig: lahaina: Enable DMA_CONFIGURE_ALIGNMENT Enable support for configuring IOVA alignment since some IOMMU clients don't require any IOVA alignment and therefore would benefit from the reduced fragmentation that would result. Change-Id: Ide09a63d2efe1256d3424a9cebee4f330c07ca02 Signed-off-by: Liam Mark --- arch/arm64/configs/vendor/lahaina_QGKI.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/lahaina_QGKI.config b/arch/arm64/configs/vendor/lahaina_QGKI.config index 5040c8af5091..82b6e30e8e31 100644 --- a/arch/arm64/configs/vendor/lahaina_QGKI.config +++ b/arch/arm64/configs/vendor/lahaina_QGKI.config @@ -44,6 +44,7 @@ CONFIG_CMA_DIRECT_UTILIZATION=y CONFIG_CMA_PCP_LISTS=y CONFIG_DMA_COHERENT_HINT_CACHED=y CONFIG_PRIORITIZE_OOM_TASKS=y +CONFIG_DMA_CONFIGURE_ALIGNMENT=y # CONFIG_ZONE_DEVICE is not set # CONFIG_BUG_ON_HW_MEM_ONLINE_FAIL is not set CONFIG_MSM_BT_POWER=m