summaryrefslogtreecommitdiffstats
path: root/include/linux/iova.h
diff options
context:
space:
mode:
authorOmer Peleg <omer@cs.technion.ac.il>2016-04-20 04:34:11 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2016-04-20 15:42:24 -0400
commit9257b4a206fc0229dd5f84b78e4d1ebf3f91d270 (patch)
treebc41e95277e951a0160b80d07133e42614eb68d3 /include/linux/iova.h
parent2aac630429d986a43ac59525a4cff47a624dc58e (diff)
iommu/iova: introduce per-cpu caching to iova allocation
IOVA allocation has two problems that impede high-throughput I/O. First, it can do a linear search over the allocated IOVA ranges. Second, the rbtree spinlock that serializes IOVA allocations becomes contended. Address these problems by creating an API for caching allocated IOVA ranges, so that the IOVA allocator isn't accessed frequently. This patch adds a per-CPU cache, from which CPUs can alloc/free IOVAs without taking the rbtree spinlock. The per-CPU caches are backed by a global cache, to avoid invoking the (linear-time) IOVA allocator without needing to make the per-CPU cache size excessive. This design is based on magazines, as described in "Magazines and Vmem: Extending the Slab Allocator to Many CPUs and Arbitrary Resources" (currently available at https://www.usenix.org/legacy/event/usenix01/bonwick.html) Adding caching on top of the existing rbtree allocator maintains the property that IOVAs are densely packed in the IO virtual address space, which is important for keeping IOMMU page table usage low. To keep the cache size reasonable, we bound the IOVA space a CPU can cache by 32 MiB (we cache a bounded number of IOVA ranges, and only ranges of size <= 128 KiB). The shared global cache is bounded at 4 MiB of IOVA space. Signed-off-by: Omer Peleg <omer@cs.technion.ac.il> [mad@cs.technion.ac.il: rebased, cleaned up and reworded the commit message] Signed-off-by: Adam Morrison <mad@cs.technion.ac.il> Reviewed-by: Shaohua Li <shli@fb.com> Reviewed-by: Ben Serebrin <serebrin@google.com> [dwmw2: split out VT-d part into a separate patch] Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'include/linux/iova.h')
-rw-r--r--include/linux/iova.h23
1 files changed, 21 insertions, 2 deletions
diff --git a/include/linux/iova.h b/include/linux/iova.h
index 92f7177db2ce..f27bb2c62fca 100644
--- a/include/linux/iova.h
+++ b/include/linux/iova.h
@@ -19,8 +19,21 @@
19/* iova structure */ 19/* iova structure */
20struct iova { 20struct iova {
21 struct rb_node node; 21 struct rb_node node;
22 unsigned long pfn_hi; /* IOMMU dish out addr hi */ 22 unsigned long pfn_hi; /* Highest allocated pfn */
23 unsigned long pfn_lo; /* IOMMU dish out addr lo */ 23 unsigned long pfn_lo; /* Lowest allocated pfn */
24};
25
26struct iova_magazine;
27struct iova_cpu_rcache;
28
29#define IOVA_RANGE_CACHE_MAX_SIZE 6 /* log of max cached IOVA range size (in pages) */
30#define MAX_GLOBAL_MAGS 32 /* magazines per bin */
31
32struct iova_rcache {
33 spinlock_t lock;
34 unsigned long depot_size;
35 struct iova_magazine *depot[MAX_GLOBAL_MAGS];
36 struct iova_cpu_rcache __percpu *cpu_rcaches;
24}; 37};
25 38
26/* holds all the iova translations for a domain */ 39/* holds all the iova translations for a domain */
@@ -31,6 +44,7 @@ struct iova_domain {
31 unsigned long granule; /* pfn granularity for this domain */ 44 unsigned long granule; /* pfn granularity for this domain */
32 unsigned long start_pfn; /* Lower limit for this domain */ 45 unsigned long start_pfn; /* Lower limit for this domain */
33 unsigned long dma_32bit_pfn; 46 unsigned long dma_32bit_pfn;
47 struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE]; /* IOVA range caches */
34}; 48};
35 49
36static inline unsigned long iova_size(struct iova *iova) 50static inline unsigned long iova_size(struct iova *iova)
@@ -78,6 +92,10 @@ void __free_iova(struct iova_domain *iovad, struct iova *iova);
78struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size, 92struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
79 unsigned long limit_pfn, 93 unsigned long limit_pfn,
80 bool size_aligned); 94 bool size_aligned);
95void free_iova_fast(struct iova_domain *iovad, unsigned long pfn,
96 unsigned long size);
97unsigned long alloc_iova_fast(struct iova_domain *iovad, unsigned long size,
98 unsigned long limit_pfn);
81struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, 99struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
82 unsigned long pfn_hi); 100 unsigned long pfn_hi);
83void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to); 101void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
@@ -87,5 +105,6 @@ struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
87void put_iova_domain(struct iova_domain *iovad); 105void put_iova_domain(struct iova_domain *iovad);
88struct iova *split_and_remove_iova(struct iova_domain *iovad, 106struct iova *split_and_remove_iova(struct iova_domain *iovad,
89 struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi); 107 struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi);
108void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad);
90 109
91#endif 110#endif