aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core
diff options
context:
space:
mode:
authorYishai Hadas <yishaih@mellanox.com>2014-01-28 06:40:15 -0500
committerRoland Dreier <roland@purestorage.com>2014-03-04 13:34:28 -0500
commiteeb8461e36c99fdf2d058751be924a2aab215005 (patch)
treec92498349f842be5985194c840e2dd12201df861 /drivers/infiniband/core
parentcfbf8d4857c26a8a307fb7cd258074c9dcd8c691 (diff)
IB: Refactor umem to use linear SG table
This patch refactors the IB core umem code and vendor drivers to use a linear (chained) SG table instead of chunk list. With this change the relevant code becomes clearer—no need for nested loops to build and use umem. Signed-off-by: Shachar Raindel <raindel@mellanox.com> Signed-off-by: Yishai Hadas <yishaih@mellanox.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r--drivers/infiniband/core/umem.c120
1 files changed, 56 insertions, 64 deletions
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index a84112322071..a3a2e9c1639b 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -42,29 +42,29 @@
42 42
43#include "uverbs.h" 43#include "uverbs.h"
44 44
45#define IB_UMEM_MAX_PAGE_CHUNK \
46 ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \
47 ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \
48 (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
49 45
50static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty) 46static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
51{ 47{
52 struct ib_umem_chunk *chunk, *tmp; 48 struct scatterlist *sg;
49 struct page *page;
53 int i; 50 int i;
54 51
55 list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) { 52 if (umem->nmap > 0)
56 ib_dma_unmap_sg(dev, chunk->page_list, 53 ib_dma_unmap_sg(dev, umem->sg_head.sgl,
57 chunk->nents, DMA_BIDIRECTIONAL); 54 umem->nmap,
58 for (i = 0; i < chunk->nents; ++i) { 55 DMA_BIDIRECTIONAL);
59 struct page *page = sg_page(&chunk->page_list[i]);
60 56
61 if (umem->writable && dirty) 57 for_each_sg(umem->sg_head.sgl, sg, umem->npages, i) {
62 set_page_dirty_lock(page);
63 put_page(page);
64 }
65 58
66 kfree(chunk); 59 page = sg_page(sg);
60 if (umem->writable && dirty)
61 set_page_dirty_lock(page);
62 put_page(page);
67 } 63 }
64
65 sg_free_table(&umem->sg_head);
66 return;
67
68} 68}
69 69
70/** 70/**
@@ -81,15 +81,15 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
81 struct ib_umem *umem; 81 struct ib_umem *umem;
82 struct page **page_list; 82 struct page **page_list;
83 struct vm_area_struct **vma_list; 83 struct vm_area_struct **vma_list;
84 struct ib_umem_chunk *chunk;
85 unsigned long locked; 84 unsigned long locked;
86 unsigned long lock_limit; 85 unsigned long lock_limit;
87 unsigned long cur_base; 86 unsigned long cur_base;
88 unsigned long npages; 87 unsigned long npages;
89 int ret; 88 int ret;
90 int off;
91 int i; 89 int i;
92 DEFINE_DMA_ATTRS(attrs); 90 DEFINE_DMA_ATTRS(attrs);
91 struct scatterlist *sg, *sg_list_start;
92 int need_release = 0;
93 93
94 if (dmasync) 94 if (dmasync)
95 dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); 95 dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
@@ -97,7 +97,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
97 if (!can_do_mlock()) 97 if (!can_do_mlock())
98 return ERR_PTR(-EPERM); 98 return ERR_PTR(-EPERM);
99 99
100 umem = kmalloc(sizeof *umem, GFP_KERNEL); 100 umem = kzalloc(sizeof *umem, GFP_KERNEL);
101 if (!umem) 101 if (!umem)
102 return ERR_PTR(-ENOMEM); 102 return ERR_PTR(-ENOMEM);
103 103
@@ -117,8 +117,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
117 /* We assume the memory is from hugetlb until proved otherwise */ 117 /* We assume the memory is from hugetlb until proved otherwise */
118 umem->hugetlb = 1; 118 umem->hugetlb = 1;
119 119
120 INIT_LIST_HEAD(&umem->chunk_list);
121
122 page_list = (struct page **) __get_free_page(GFP_KERNEL); 120 page_list = (struct page **) __get_free_page(GFP_KERNEL);
123 if (!page_list) { 121 if (!page_list) {
124 kfree(umem); 122 kfree(umem);
@@ -147,7 +145,18 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
147 145
148 cur_base = addr & PAGE_MASK; 146 cur_base = addr & PAGE_MASK;
149 147
150 ret = 0; 148 if (npages == 0) {
149 ret = -EINVAL;
150 goto out;
151 }
152
153 ret = sg_alloc_table(&umem->sg_head, npages, GFP_KERNEL);
154 if (ret)
155 goto out;
156
157 need_release = 1;
158 sg_list_start = umem->sg_head.sgl;
159
151 while (npages) { 160 while (npages) {
152 ret = get_user_pages(current, current->mm, cur_base, 161 ret = get_user_pages(current, current->mm, cur_base,
153 min_t(unsigned long, npages, 162 min_t(unsigned long, npages,
@@ -157,54 +166,38 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
157 if (ret < 0) 166 if (ret < 0)
158 goto out; 167 goto out;
159 168
169 umem->npages += ret;
160 cur_base += ret * PAGE_SIZE; 170 cur_base += ret * PAGE_SIZE;
161 npages -= ret; 171 npages -= ret;
162 172
163 off = 0; 173 for_each_sg(sg_list_start, sg, ret, i) {
164 174 if (vma_list && !is_vm_hugetlb_page(vma_list[i]))
165 while (ret) { 175 umem->hugetlb = 0;
166 chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) * 176
167 min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK), 177 sg_set_page(sg, page_list[i], PAGE_SIZE, 0);
168 GFP_KERNEL);
169 if (!chunk) {
170 ret = -ENOMEM;
171 goto out;
172 }
173
174 chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
175 sg_init_table(chunk->page_list, chunk->nents);
176 for (i = 0; i < chunk->nents; ++i) {
177 if (vma_list &&
178 !is_vm_hugetlb_page(vma_list[i + off]))
179 umem->hugetlb = 0;
180 sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0);
181 }
182
183 chunk->nmap = ib_dma_map_sg_attrs(context->device,
184 &chunk->page_list[0],
185 chunk->nents,
186 DMA_BIDIRECTIONAL,
187 &attrs);
188 if (chunk->nmap <= 0) {
189 for (i = 0; i < chunk->nents; ++i)
190 put_page(sg_page(&chunk->page_list[i]));
191 kfree(chunk);
192
193 ret = -ENOMEM;
194 goto out;
195 }
196
197 ret -= chunk->nents;
198 off += chunk->nents;
199 list_add_tail(&chunk->list, &umem->chunk_list);
200 } 178 }
201 179
202 ret = 0; 180 /* preparing for next loop */
181 sg_list_start = sg;
203 } 182 }
204 183
184 umem->nmap = ib_dma_map_sg_attrs(context->device,
185 umem->sg_head.sgl,
186 umem->npages,
187 DMA_BIDIRECTIONAL,
188 &attrs);
189
190 if (umem->nmap <= 0) {
191 ret = -ENOMEM;
192 goto out;
193 }
194
195 ret = 0;
196
205out: 197out:
206 if (ret < 0) { 198 if (ret < 0) {
207 __ib_umem_release(context->device, umem, 0); 199 if (need_release)
200 __ib_umem_release(context->device, umem, 0);
208 kfree(umem); 201 kfree(umem);
209 } else 202 } else
210 current->mm->pinned_vm = locked; 203 current->mm->pinned_vm = locked;
@@ -278,17 +271,16 @@ EXPORT_SYMBOL(ib_umem_release);
278 271
279int ib_umem_page_count(struct ib_umem *umem) 272int ib_umem_page_count(struct ib_umem *umem)
280{ 273{
281 struct ib_umem_chunk *chunk;
282 int shift; 274 int shift;
283 int i; 275 int i;
284 int n; 276 int n;
277 struct scatterlist *sg;
285 278
286 shift = ilog2(umem->page_size); 279 shift = ilog2(umem->page_size);
287 280
288 n = 0; 281 n = 0;
289 list_for_each_entry(chunk, &umem->chunk_list, list) 282 for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i)
290 for (i = 0; i < chunk->nmap; ++i) 283 n += sg_dma_len(sg) >> shift;
291 n += sg_dma_len(&chunk->page_list[i]) >> shift;
292 284
293 return n; 285 return n;
294} 286}