aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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