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

iommu/iova: Optimise attempts to allocate iova from 32bit address range

As an optimisation for PCI devices, there is always first attempt
been made to allocate iova from SAC address range. This will lead
to unnecessary attempts, when there are no free ranges
available. Adding fix to track recently failed iova address size and
allow further attempts, only if requested size is lesser than a failed
size. The size is updated when any replenish happens.

Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Ganapatrao Kulkarni <ganapatrao.kulkarni@cavium.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>

authored by

Ganapatrao Kulkarni and committed by
Joerg Roedel
bee60e94 6bf4ca7f

+16 -7
+15 -7
drivers/iommu/iova.c
··· 56 56 iovad->granule = granule; 57 57 iovad->start_pfn = start_pfn; 58 58 iovad->dma_32bit_pfn = 1UL << (32 - iova_shift(iovad)); 59 + iovad->max32_alloc_size = iovad->dma_32bit_pfn; 59 60 iovad->flush_cb = NULL; 60 61 iovad->fq = NULL; 61 62 iovad->anchor.pfn_lo = iovad->anchor.pfn_hi = IOVA_ANCHOR; ··· 140 139 141 140 cached_iova = rb_entry(iovad->cached32_node, struct iova, node); 142 141 if (free->pfn_hi < iovad->dma_32bit_pfn && 143 - free->pfn_lo >= cached_iova->pfn_lo) 142 + free->pfn_lo >= cached_iova->pfn_lo) { 144 143 iovad->cached32_node = rb_next(&free->node); 144 + iovad->max32_alloc_size = iovad->dma_32bit_pfn; 145 + } 145 146 146 147 cached_iova = rb_entry(iovad->cached_node, struct iova, node); 147 148 if (free->pfn_lo >= cached_iova->pfn_lo) ··· 193 190 194 191 /* Walk the tree backwards */ 195 192 spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); 193 + if (limit_pfn <= iovad->dma_32bit_pfn && 194 + size >= iovad->max32_alloc_size) 195 + goto iova32_full; 196 + 196 197 curr = __get_cached_rbnode(iovad, limit_pfn); 197 198 curr_iova = rb_entry(curr, struct iova, node); 198 199 do { ··· 207 200 curr_iova = rb_entry(curr, struct iova, node); 208 201 } while (curr && new_pfn <= curr_iova->pfn_hi); 209 202 210 - if (limit_pfn < size || new_pfn < iovad->start_pfn) { 211 - spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 212 - return -ENOMEM; 213 - } 203 + if (limit_pfn < size || new_pfn < iovad->start_pfn) 204 + goto iova32_full; 214 205 215 206 /* pfn_lo will point to size aligned address if size_aligned is set */ 216 207 new->pfn_lo = new_pfn; ··· 219 214 __cached_rbnode_insert_update(iovad, new); 220 215 221 216 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 222 - 223 - 224 217 return 0; 218 + 219 + iova32_full: 220 + iovad->max32_alloc_size = size; 221 + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 222 + return -ENOMEM; 225 223 } 226 224 227 225 static struct kmem_cache *iova_cache;
+1
include/linux/iova.h
··· 75 75 unsigned long granule; /* pfn granularity for this domain */ 76 76 unsigned long start_pfn; /* Lower limit for this domain */ 77 77 unsigned long dma_32bit_pfn; 78 + unsigned long max32_alloc_size; /* Size of last failed allocation */ 78 79 struct iova anchor; /* rbtree lookup anchor */ 79 80 struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE]; /* IOVA range caches */ 80 81