Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iommu: Make IOVA domain low limit flexible

To share the IOVA allocator with other architectures, it needs to
accommodate more general aperture restrictions; move the lower limit
from a compile-time constant to a runtime domain property to allow
IOVA domains with different requirements to co-exist.

Also reword the slightly unclear description of alloc_iova since we're
touching it anyway.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>

authored by

Robin Murphy and committed by
Joerg Roedel
1b722500 85b45456

+15 -11
+6 -3
drivers/iommu/intel-iommu.c
··· 71 71 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1)) 72 72 #define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT) 73 73 74 + /* IO virtual address start page frame number */ 75 + #define IOVA_START_PFN (1) 76 + 74 77 #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) 75 78 #define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32)) 76 79 #define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64)) ··· 1635 1632 struct iova *iova; 1636 1633 int i; 1637 1634 1638 - init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN); 1635 + init_iova_domain(&reserved_iova_list, IOVA_START_PFN, DMA_32BIT_PFN); 1639 1636 1640 1637 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock, 1641 1638 &reserved_rbtree_key); ··· 1693 1690 int adjust_width, agaw; 1694 1691 unsigned long sagaw; 1695 1692 1696 - init_iova_domain(&domain->iovad, DMA_32BIT_PFN); 1693 + init_iova_domain(&domain->iovad, IOVA_START_PFN, DMA_32BIT_PFN); 1697 1694 domain_reserve_special_ranges(domain); 1698 1695 1699 1696 /* calculate AGAW */ ··· 4316 4313 { 4317 4314 int adjust_width; 4318 4315 4319 - init_iova_domain(&domain->iovad, DMA_32BIT_PFN); 4316 + init_iova_domain(&domain->iovad, IOVA_START_PFN, DMA_32BIT_PFN); 4320 4317 domain_reserve_special_ranges(domain); 4321 4318 4322 4319 /* calculate AGAW */
+6 -4
drivers/iommu/iova.c
··· 55 55 } 56 56 57 57 void 58 - init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit) 58 + init_iova_domain(struct iova_domain *iovad, unsigned long start_pfn, 59 + unsigned long pfn_32bit) 59 60 { 60 61 spin_lock_init(&iovad->iova_rbtree_lock); 61 62 iovad->rbroot = RB_ROOT; 62 63 iovad->cached32_node = NULL; 64 + iovad->start_pfn = start_pfn; 63 65 iovad->dma_32bit_pfn = pfn_32bit; 64 66 } 65 67 ··· 164 162 if (!curr) { 165 163 if (size_aligned) 166 164 pad_size = iova_get_pad_size(size, limit_pfn); 167 - if ((IOVA_START_PFN + size + pad_size) > limit_pfn) { 165 + if ((iovad->start_pfn + size + pad_size) > limit_pfn) { 168 166 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 169 167 return -ENOMEM; 170 168 } ··· 239 237 * @size: - size of page frames to allocate 240 238 * @limit_pfn: - max limit address 241 239 * @size_aligned: - set if size_aligned address range is required 242 - * This function allocates an iova in the range limit_pfn to IOVA_START_PFN 243 - * looking from limit_pfn instead from IOVA_START_PFN. If the size_aligned 240 + * This function allocates an iova in the range iovad->start_pfn to limit_pfn, 241 + * searching top-down from limit_pfn to iovad->start_pfn. If the size_aligned 244 242 * flag is set then the allocated address iova->pfn_lo will be naturally 245 243 * aligned on roundup_power_of_two(size). 246 244 */
+3 -4
include/linux/iova.h
··· 16 16 #include <linux/rbtree.h> 17 17 #include <linux/dma-mapping.h> 18 18 19 - /* IO virtual address start page frame number */ 20 - #define IOVA_START_PFN (1) 21 - 22 19 /* iova structure */ 23 20 struct iova { 24 21 struct rb_node node; ··· 28 31 spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */ 29 32 struct rb_root rbroot; /* iova domain rbtree root */ 30 33 struct rb_node *cached32_node; /* Save last alloced node */ 34 + unsigned long start_pfn; /* Lower limit for this domain */ 31 35 unsigned long dma_32bit_pfn; 32 36 }; 33 37 ··· 50 52 struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, 51 53 unsigned long pfn_hi); 52 54 void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to); 53 - void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit); 55 + void init_iova_domain(struct iova_domain *iovad, unsigned long start_pfn, 56 + unsigned long pfn_32bit); 54 57 struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn); 55 58 void put_iova_domain(struct iova_domain *iovad); 56 59 struct iova *split_and_remove_iova(struct iova_domain *iovad,