diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index ab5b0a3ff0f9..112815dee3a9 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2064,6 +2064,14 @@ forcing Dual Address Cycle for PCI cards supporting greater than 32-bit addressing. + iommu.max_align_shift= + [ARM64, X86] Limit the alignment of IOVAs to a maximum + PAGE_SIZE order. Larger IOVAs will be aligned to this + specified order. The order is expressed as a power of + two multiplied by the PAGE_SIZE. + Format: { "4" | "5" | "6" | "7" | "8" | "9" } + Default: 9 + iommu.strict= [ARM64, X86] Configure TLB invalidation behaviour Format: { "0" | "1" } 0 - Lazy mode. diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 920fcc27c9a1..55aca4094072 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -5,6 +5,7 @@ * Author: Anil S Keshavamurthy */ +#include #include #include #include @@ -15,6 +16,9 @@ /* The anchor node sits above the top of the usable address space */ #define IOVA_ANCHOR ~0UL +#define IOMMU_DEFAULT_IOVA_MAX_ALIGN_SHIFT 9 +static unsigned long iommu_max_align_shift __read_mostly = IOMMU_DEFAULT_IOVA_MAX_ALIGN_SHIFT; + static bool iova_rcache_insert(struct iova_domain *iovad, unsigned long pfn, unsigned long size); @@ -27,6 +31,29 @@ static void free_iova_rcaches(struct iova_domain *iovad); static void fq_destroy_all_entries(struct iova_domain *iovad); static void fq_flush_timeout(struct timer_list *t); +static unsigned long limit_align_shift(struct iova_domain *iovad, unsigned long shift) +{ + unsigned long max_align_shift; + + max_align_shift = iommu_max_align_shift + PAGE_SHIFT - iova_shift(iovad); + return min_t(unsigned long, max_align_shift, shift); +} + +#ifndef MODULE +static int __init iommu_set_def_max_align_shift(char *str) +{ + unsigned long max_align_shift; + + int ret = kstrtoul(str, 10, &max_align_shift); + + if (!ret) + iommu_max_align_shift = max_align_shift; + + return 0; +} +early_param("iommu.max_align_shift", iommu_set_def_max_align_shift); +#endif + static int iova_cpuhp_dead(unsigned int cpu, struct hlist_node *node) { struct iova_domain *iovad; @@ -241,7 +268,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, unsigned long high_pfn = limit_pfn, low_pfn = iovad->start_pfn; if (size_aligned) - align_mask <<= fls_long(size - 1); + align_mask <<= limit_align_shift(iovad, fls_long(size - 1)); /* Walk the tree backwards */ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);