diff options
author | Roland Dreier <rolandd@cisco.com> | 2007-03-04 19:15:11 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-05-08 21:00:37 -0400 |
commit | f7c6a7b5d59980b076abbf2ceeb8735591290285 (patch) | |
tree | 29c35b47052bba87f031a4744d8ad12ff5187149 /drivers/infiniband/hw/ipath/ipath_mr.c | |
parent | 36f021b579d195cdc5fa6f3e2bab198b4bf70643 (diff) |
IB/uverbs: Export ib_umem_get()/ib_umem_release() to modules
Export ib_umem_get()/ib_umem_release() and put low-level drivers in
control of when to call ib_umem_get() to pin and DMA map userspace,
rather than always calling it in ib_uverbs_reg_mr() before calling the
low-level driver's reg_user_mr method.
Also move these functions to be in the ib_core module instead of
ib_uverbs, so that driver modules using them do not depend on
ib_uverbs.
This has a number of advantages:
- It is better design from the standpoint of making generic code a
library that can be used or overridden by device-specific code as
the details of specific devices dictate.
- Drivers that do not need to pin userspace memory regions do not
need to take the performance hit of calling ib_mem_get(). For
example, although I have not tried to implement it in this patch,
the ipath driver should be able to avoid pinning memory and just
use copy_{to,from}_user() to access userspace memory regions.
- Buffers that need special mapping treatment can be identified by
the low-level driver. For example, it may be possible to solve
some Altix-specific memory ordering issues with mthca CQs in
userspace by mapping CQ buffers with extra flags.
- Drivers that need to pin and DMA map userspace memory for things
other than memory regions can use ib_umem_get() directly, instead
of hacks using extra parameters to their reg_phys_mr method. For
example, the mlx4 driver that is pending being merged needs to pin
and DMA map QP and CQ buffers, but it does not need to create a
memory key for these buffers. So the cleanest solution is for mlx4
to call ib_umem_get() in the create_qp and create_cq methods.
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_mr.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mr.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c index 31e70732e369..bdeef8d4f279 100644 --- a/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/drivers/infiniband/hw/ipath/ipath_mr.c | |||
@@ -31,6 +31,7 @@ | |||
31 | * SOFTWARE. | 31 | * SOFTWARE. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <rdma/ib_umem.h> | ||
34 | #include <rdma/ib_pack.h> | 35 | #include <rdma/ib_pack.h> |
35 | #include <rdma/ib_smi.h> | 36 | #include <rdma/ib_smi.h> |
36 | 37 | ||
@@ -147,6 +148,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd, | |||
147 | mr->mr.offset = 0; | 148 | mr->mr.offset = 0; |
148 | mr->mr.access_flags = acc; | 149 | mr->mr.access_flags = acc; |
149 | mr->mr.max_segs = num_phys_buf; | 150 | mr->mr.max_segs = num_phys_buf; |
151 | mr->umem = NULL; | ||
150 | 152 | ||
151 | m = 0; | 153 | m = 0; |
152 | n = 0; | 154 | n = 0; |
@@ -170,46 +172,56 @@ bail: | |||
170 | /** | 172 | /** |
171 | * ipath_reg_user_mr - register a userspace memory region | 173 | * ipath_reg_user_mr - register a userspace memory region |
172 | * @pd: protection domain for this memory region | 174 | * @pd: protection domain for this memory region |
173 | * @region: the user memory region | 175 | * @start: starting userspace address |
176 | * @length: length of region to register | ||
177 | * @virt_addr: virtual address to use (from HCA's point of view) | ||
174 | * @mr_access_flags: access flags for this memory region | 178 | * @mr_access_flags: access flags for this memory region |
175 | * @udata: unused by the InfiniPath driver | 179 | * @udata: unused by the InfiniPath driver |
176 | * | 180 | * |
177 | * Returns the memory region on success, otherwise returns an errno. | 181 | * Returns the memory region on success, otherwise returns an errno. |
178 | */ | 182 | */ |
179 | struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | 183 | struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
180 | int mr_access_flags, struct ib_udata *udata) | 184 | u64 virt_addr, int mr_access_flags, |
185 | struct ib_udata *udata) | ||
181 | { | 186 | { |
182 | struct ipath_mr *mr; | 187 | struct ipath_mr *mr; |
188 | struct ib_umem *umem; | ||
183 | struct ib_umem_chunk *chunk; | 189 | struct ib_umem_chunk *chunk; |
184 | int n, m, i; | 190 | int n, m, i; |
185 | struct ib_mr *ret; | 191 | struct ib_mr *ret; |
186 | 192 | ||
187 | if (region->length == 0) { | 193 | if (length == 0) { |
188 | ret = ERR_PTR(-EINVAL); | 194 | ret = ERR_PTR(-EINVAL); |
189 | goto bail; | 195 | goto bail; |
190 | } | 196 | } |
191 | 197 | ||
198 | umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags); | ||
199 | if (IS_ERR(umem)) | ||
200 | return (void *) umem; | ||
201 | |||
192 | n = 0; | 202 | n = 0; |
193 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 203 | list_for_each_entry(chunk, &umem->chunk_list, list) |
194 | n += chunk->nents; | 204 | n += chunk->nents; |
195 | 205 | ||
196 | mr = alloc_mr(n, &to_idev(pd->device)->lk_table); | 206 | mr = alloc_mr(n, &to_idev(pd->device)->lk_table); |
197 | if (!mr) { | 207 | if (!mr) { |
198 | ret = ERR_PTR(-ENOMEM); | 208 | ret = ERR_PTR(-ENOMEM); |
209 | ib_umem_release(umem); | ||
199 | goto bail; | 210 | goto bail; |
200 | } | 211 | } |
201 | 212 | ||
202 | mr->mr.pd = pd; | 213 | mr->mr.pd = pd; |
203 | mr->mr.user_base = region->user_base; | 214 | mr->mr.user_base = start; |
204 | mr->mr.iova = region->virt_base; | 215 | mr->mr.iova = virt_addr; |
205 | mr->mr.length = region->length; | 216 | mr->mr.length = length; |
206 | mr->mr.offset = region->offset; | 217 | mr->mr.offset = umem->offset; |
207 | mr->mr.access_flags = mr_access_flags; | 218 | mr->mr.access_flags = mr_access_flags; |
208 | mr->mr.max_segs = n; | 219 | mr->mr.max_segs = n; |
220 | mr->umem = umem; | ||
209 | 221 | ||
210 | m = 0; | 222 | m = 0; |
211 | n = 0; | 223 | n = 0; |
212 | list_for_each_entry(chunk, ®ion->chunk_list, list) { | 224 | list_for_each_entry(chunk, &umem->chunk_list, list) { |
213 | for (i = 0; i < chunk->nents; i++) { | 225 | for (i = 0; i < chunk->nents; i++) { |
214 | void *vaddr; | 226 | void *vaddr; |
215 | 227 | ||
@@ -219,7 +231,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
219 | goto bail; | 231 | goto bail; |
220 | } | 232 | } |
221 | mr->mr.map[m]->segs[n].vaddr = vaddr; | 233 | mr->mr.map[m]->segs[n].vaddr = vaddr; |
222 | mr->mr.map[m]->segs[n].length = region->page_size; | 234 | mr->mr.map[m]->segs[n].length = umem->page_size; |
223 | n++; | 235 | n++; |
224 | if (n == IPATH_SEGSZ) { | 236 | if (n == IPATH_SEGSZ) { |
225 | m++; | 237 | m++; |
@@ -253,6 +265,10 @@ int ipath_dereg_mr(struct ib_mr *ibmr) | |||
253 | i--; | 265 | i--; |
254 | kfree(mr->mr.map[i]); | 266 | kfree(mr->mr.map[i]); |
255 | } | 267 | } |
268 | |||
269 | if (mr->umem) | ||
270 | ib_umem_release(mr->umem); | ||
271 | |||
256 | kfree(mr); | 272 | kfree(mr); |
257 | return 0; | 273 | return 0; |
258 | } | 274 | } |