aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/iova.c
diff options
context:
space:
mode:
authormark gross <mgross@linux.intel.com>2008-03-04 18:22:04 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-21 00:47:06 -0400
commitddf02886cbe665d67ca750750196ea5bf524b10b (patch)
tree34a70cdd35b420d9fb0958179f8c2d9949c3b629 /drivers/pci/iova.c
parentc9e9e0bfc52ae93c246149c3b9d3a1e11677ca1a (diff)
PCI: iova RB tree setup tweak
The following patch merges two functions into one allowing for a 3% reduction in overhead in locating, allocating and inserting pages for use in IOMMU operations. Its a bit of a eye-crosser so I welcome any RB-tree / MM experts to take a look. It works by re-using some of the information gathered in the search for the pages to use in setting up the IOTLB's in the insertion of the iova structure into the RB tree. Signed-off-by: <mgross@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/iova.c')
-rw-r--r--drivers/pci/iova.c50
1 files changed, 36 insertions, 14 deletions
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
index dbcdd6bfa63a..3ef4ac064315 100644
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -73,10 +73,11 @@ iova_get_pad_size(int size, unsigned int limit_pfn)
73 return pad_size; 73 return pad_size;
74} 74}
75 75
76static int __alloc_iova_range(struct iova_domain *iovad, unsigned long size, 76static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
77 unsigned long limit_pfn, struct iova *new, bool size_aligned) 77 unsigned long size, unsigned long limit_pfn,
78 struct iova *new, bool size_aligned)
78{ 79{
79 struct rb_node *curr = NULL; 80 struct rb_node *prev, *curr = NULL;
80 unsigned long flags; 81 unsigned long flags;
81 unsigned long saved_pfn; 82 unsigned long saved_pfn;
82 unsigned int pad_size = 0; 83 unsigned int pad_size = 0;
@@ -85,8 +86,10 @@ static int __alloc_iova_range(struct iova_domain *iovad, unsigned long size,
85 spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); 86 spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
86 saved_pfn = limit_pfn; 87 saved_pfn = limit_pfn;
87 curr = __get_cached_rbnode(iovad, &limit_pfn); 88 curr = __get_cached_rbnode(iovad, &limit_pfn);
89 prev = curr;
88 while (curr) { 90 while (curr) {
89 struct iova *curr_iova = container_of(curr, struct iova, node); 91 struct iova *curr_iova = container_of(curr, struct iova, node);
92
90 if (limit_pfn < curr_iova->pfn_lo) 93 if (limit_pfn < curr_iova->pfn_lo)
91 goto move_left; 94 goto move_left;
92 else if (limit_pfn < curr_iova->pfn_hi) 95 else if (limit_pfn < curr_iova->pfn_hi)
@@ -100,6 +103,7 @@ static int __alloc_iova_range(struct iova_domain *iovad, unsigned long size,
100adjust_limit_pfn: 103adjust_limit_pfn:
101 limit_pfn = curr_iova->pfn_lo - 1; 104 limit_pfn = curr_iova->pfn_lo - 1;
102move_left: 105move_left:
106 prev = curr;
103 curr = rb_prev(curr); 107 curr = rb_prev(curr);
104 } 108 }
105 109
@@ -116,7 +120,33 @@ move_left:
116 new->pfn_lo = limit_pfn - (size + pad_size) + 1; 120 new->pfn_lo = limit_pfn - (size + pad_size) + 1;
117 new->pfn_hi = new->pfn_lo + size - 1; 121 new->pfn_hi = new->pfn_lo + size - 1;
118 122
123 /* Insert the new_iova into domain rbtree by holding writer lock */
124 /* Add new node and rebalance tree. */
125 {
126 struct rb_node **entry = &((prev)), *parent = NULL;
127 /* Figure out where to put new node */
128 while (*entry) {
129 struct iova *this = container_of(*entry,
130 struct iova, node);
131 parent = *entry;
132
133 if (new->pfn_lo < this->pfn_lo)
134 entry = &((*entry)->rb_left);
135 else if (new->pfn_lo > this->pfn_lo)
136 entry = &((*entry)->rb_right);
137 else
138 BUG(); /* this should not happen */
139 }
140
141 /* Add new node and rebalance tree. */
142 rb_link_node(&new->node, parent, entry);
143 rb_insert_color(&new->node, &iovad->rbroot);
144 }
145 __cached_rbnode_insert_update(iovad, saved_pfn, new);
146
119 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 147 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
148
149
120 return 0; 150 return 0;
121} 151}
122 152
@@ -172,23 +202,15 @@ alloc_iova(struct iova_domain *iovad, unsigned long size,
172 size = __roundup_pow_of_two(size); 202 size = __roundup_pow_of_two(size);
173 203
174 spin_lock_irqsave(&iovad->iova_alloc_lock, flags); 204 spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
175 ret = __alloc_iova_range(iovad, size, limit_pfn, new_iova, 205 ret = __alloc_and_insert_iova_range(iovad, size, limit_pfn,
176 size_aligned); 206 new_iova, size_aligned);
177 207
208 spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
178 if (ret) { 209 if (ret) {
179 spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
180 free_iova_mem(new_iova); 210 free_iova_mem(new_iova);
181 return NULL; 211 return NULL;
182 } 212 }
183 213
184 /* Insert the new_iova into domain rbtree by holding writer lock */
185 spin_lock(&iovad->iova_rbtree_lock);
186 iova_insert_rbtree(&iovad->rbroot, new_iova);
187 __cached_rbnode_insert_update(iovad, limit_pfn, new_iova);
188 spin_unlock(&iovad->iova_rbtree_lock);
189
190 spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
191
192 return new_iova; 214 return new_iova;
193} 215}
194 216