]>
git.ipfire.org Git - thirdparty/kernel/linux.git/blob - drivers/infiniband/sw/rxe/rxe_mr.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
3 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
4 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
10 /* Return a random 8 bit key value that is
11 * different than the last_key. Set last_key to -1
12 * if this is the first key for an MR or MW
14 u8
rxe_get_next_key(u32 last_key
)
19 get_random_bytes(&key
, 1);
20 } while (key
== last_key
);
25 int mr_check_range(struct rxe_mr
*mr
, u64 iova
, size_t length
)
32 if (iova
< mr
->iova
|| length
> mr
->length
||
33 iova
> mr
->iova
+ mr
->length
- length
)
42 #define IB_ACCESS_REMOTE (IB_ACCESS_REMOTE_READ \
43 | IB_ACCESS_REMOTE_WRITE \
44 | IB_ACCESS_REMOTE_ATOMIC)
46 static void rxe_mr_init(int access
, struct rxe_mr
*mr
)
48 u32 lkey
= mr
->pelem
.index
<< 8 | rxe_get_next_key(-1);
49 u32 rkey
= (access
& IB_ACCESS_REMOTE
) ? lkey
: 0;
53 mr
->state
= RXE_MR_STATE_INVALID
;
54 mr
->type
= RXE_MR_TYPE_NONE
;
55 mr
->map_shift
= ilog2(RXE_BUF_PER_MAP
);
58 static int rxe_mr_alloc(struct rxe_mr
*mr
, int num_buf
)
62 struct rxe_map
**map
= mr
->map
;
64 num_map
= (num_buf
+ RXE_BUF_PER_MAP
- 1) / RXE_BUF_PER_MAP
;
66 mr
->map
= kmalloc_array(num_map
, sizeof(*map
), GFP_KERNEL
);
70 for (i
= 0; i
< num_map
; i
++) {
71 mr
->map
[i
] = kmalloc(sizeof(**map
), GFP_KERNEL
);
76 BUILD_BUG_ON(!is_power_of_2(RXE_BUF_PER_MAP
));
78 mr
->map_shift
= ilog2(RXE_BUF_PER_MAP
);
79 mr
->map_mask
= RXE_BUF_PER_MAP
- 1;
81 mr
->num_buf
= num_buf
;
82 mr
->num_map
= num_map
;
83 mr
->max_buf
= num_map
* RXE_BUF_PER_MAP
;
88 for (i
--; i
>= 0; i
--)
96 void rxe_mr_init_dma(struct rxe_pd
*pd
, int access
, struct rxe_mr
*mr
)
98 rxe_mr_init(access
, mr
);
100 mr
->ibmr
.pd
= &pd
->ibpd
;
102 mr
->state
= RXE_MR_STATE_VALID
;
103 mr
->type
= RXE_MR_TYPE_DMA
;
106 int rxe_mr_init_user(struct rxe_pd
*pd
, u64 start
, u64 length
, u64 iova
,
107 int access
, struct rxe_mr
*mr
)
109 struct rxe_map
**map
;
110 struct rxe_phys_buf
*buf
= NULL
;
111 struct ib_umem
*umem
;
112 struct sg_page_iter sg_iter
;
118 umem
= ib_umem_get(pd
->ibpd
.device
, start
, length
, access
);
120 pr_warn("%s: Unable to pin memory region err = %d\n",
121 __func__
, (int)PTR_ERR(umem
));
126 num_buf
= ib_umem_num_pages(umem
);
128 rxe_mr_init(access
, mr
);
130 err
= rxe_mr_alloc(mr
, num_buf
);
132 pr_warn("%s: Unable to allocate memory for map\n",
134 goto err_release_umem
;
137 mr
->page_shift
= PAGE_SHIFT
;
138 mr
->page_mask
= PAGE_SIZE
- 1;
145 for_each_sgtable_page (&umem
->sgt_append
.sgt
, &sg_iter
, 0) {
146 if (num_buf
>= RXE_BUF_PER_MAP
) {
152 vaddr
= page_address(sg_page_iter_page(&sg_iter
));
154 pr_warn("%s: Unable to get virtual address\n",
157 goto err_cleanup_map
;
160 buf
->addr
= (uintptr_t)vaddr
;
161 buf
->size
= PAGE_SIZE
;
168 mr
->ibmr
.pd
= &pd
->ibpd
;
174 mr
->offset
= ib_umem_offset(umem
);
175 mr
->state
= RXE_MR_STATE_VALID
;
176 mr
->type
= RXE_MR_TYPE_MR
;
181 for (i
= 0; i
< mr
->num_map
; i
++)
185 ib_umem_release(umem
);
190 int rxe_mr_init_fast(struct rxe_pd
*pd
, int max_pages
, struct rxe_mr
*mr
)
196 /* In fastreg, we also set the rkey */
197 mr
->ibmr
.rkey
= mr
->ibmr
.lkey
;
199 err
= rxe_mr_alloc(mr
, max_pages
);
203 mr
->ibmr
.pd
= &pd
->ibpd
;
204 mr
->max_buf
= max_pages
;
205 mr
->state
= RXE_MR_STATE_FREE
;
206 mr
->type
= RXE_MR_TYPE_MR
;
214 static void lookup_iova(struct rxe_mr
*mr
, u64 iova
, int *m_out
, int *n_out
,
217 size_t offset
= iova
- mr
->iova
+ mr
->offset
;
222 if (likely(mr
->page_shift
)) {
223 *offset_out
= offset
& mr
->page_mask
;
224 offset
>>= mr
->page_shift
;
225 *n_out
= offset
& mr
->map_mask
;
226 *m_out
= offset
>> mr
->map_shift
;
231 length
= mr
->map
[map_index
]->buf
[buf_index
].size
;
233 while (offset
>= length
) {
237 if (buf_index
== RXE_BUF_PER_MAP
) {
241 length
= mr
->map
[map_index
]->buf
[buf_index
].size
;
246 *offset_out
= offset
;
250 void *iova_to_vaddr(struct rxe_mr
*mr
, u64 iova
, int length
)
256 if (mr
->state
!= RXE_MR_STATE_VALID
) {
257 pr_warn("mr not in valid state\n");
263 addr
= (void *)(uintptr_t)iova
;
267 if (mr_check_range(mr
, iova
, length
)) {
268 pr_warn("range violation\n");
273 lookup_iova(mr
, iova
, &m
, &n
, &offset
);
275 if (offset
+ length
> mr
->map
[m
]->buf
[n
].size
) {
276 pr_warn("crosses page boundary\n");
281 addr
= (void *)(uintptr_t)mr
->map
[m
]->buf
[n
].addr
+ offset
;
287 /* copy data from a range (vaddr, vaddr+length-1) to or from
288 * a mr object starting at iova.
290 int rxe_mr_copy(struct rxe_mr
*mr
, u64 iova
, void *addr
, int length
,
291 enum rxe_mr_copy_dir dir
)
296 struct rxe_map
**map
;
297 struct rxe_phys_buf
*buf
;
305 if (mr
->type
== RXE_MR_TYPE_DMA
) {
308 src
= (dir
== RXE_TO_MR_OBJ
) ? addr
: ((void *)(uintptr_t)iova
);
310 dest
= (dir
== RXE_TO_MR_OBJ
) ? ((void *)(uintptr_t)iova
) : addr
;
312 memcpy(dest
, src
, length
);
317 WARN_ON_ONCE(!mr
->map
);
319 err
= mr_check_range(mr
, iova
, length
);
325 lookup_iova(mr
, iova
, &m
, &i
, &offset
);
328 buf
= map
[0]->buf
+ i
;
333 va
= (u8
*)(uintptr_t)buf
->addr
+ offset
;
334 src
= (dir
== RXE_TO_MR_OBJ
) ? addr
: va
;
335 dest
= (dir
== RXE_TO_MR_OBJ
) ? va
: addr
;
337 bytes
= buf
->size
- offset
;
342 memcpy(dest
, src
, bytes
);
351 if (i
== RXE_BUF_PER_MAP
) {
364 /* copy data in or out of a wqe, i.e. sg list
365 * under the control of a dma descriptor
370 struct rxe_dma_info
*dma
,
373 enum rxe_mr_copy_dir dir
)
376 struct rxe_sge
*sge
= &dma
->sge
[dma
->cur_sge
];
377 int offset
= dma
->sge_offset
;
378 int resid
= dma
->resid
;
379 struct rxe_mr
*mr
= NULL
;
386 if (length
> resid
) {
391 if (sge
->length
&& (offset
< sge
->length
)) {
392 mr
= lookup_mr(pd
, access
, sge
->lkey
, RXE_LOOKUP_LOCAL
);
402 if (offset
>= sge
->length
) {
411 if (dma
->cur_sge
>= dma
->num_sge
) {
417 mr
= lookup_mr(pd
, access
, sge
->lkey
,
428 if (bytes
> sge
->length
- offset
)
429 bytes
= sge
->length
- offset
;
432 iova
= sge
->addr
+ offset
;
434 err
= rxe_mr_copy(mr
, iova
, addr
, bytes
, dir
);
445 dma
->sge_offset
= offset
;
460 int advance_dma_data(struct rxe_dma_info
*dma
, unsigned int length
)
462 struct rxe_sge
*sge
= &dma
->sge
[dma
->cur_sge
];
463 int offset
= dma
->sge_offset
;
464 int resid
= dma
->resid
;
469 if (offset
>= sge
->length
) {
473 if (dma
->cur_sge
>= dma
->num_sge
)
479 if (bytes
> sge
->length
- offset
)
480 bytes
= sge
->length
- offset
;
487 dma
->sge_offset
= offset
;
493 /* (1) find the mr corresponding to lkey/rkey
494 * depending on lookup_type
495 * (2) verify that the (qp) pd matches the mr pd
496 * (3) verify that the mr can support the requested access
497 * (4) verify that mr state is valid
499 struct rxe_mr
*lookup_mr(struct rxe_pd
*pd
, int access
, u32 key
,
500 enum rxe_mr_lookup_type type
)
503 struct rxe_dev
*rxe
= to_rdev(pd
->ibpd
.device
);
504 int index
= key
>> 8;
506 mr
= rxe_pool_get_index(&rxe
->mr_pool
, index
);
510 if (unlikely((type
== RXE_LOOKUP_LOCAL
&& mr_lkey(mr
) != key
) ||
511 (type
== RXE_LOOKUP_REMOTE
&& mr_rkey(mr
) != key
) ||
512 mr_pd(mr
) != pd
|| (access
&& !(access
& mr
->access
)) ||
513 mr
->state
!= RXE_MR_STATE_VALID
)) {
521 int rxe_invalidate_mr(struct rxe_qp
*qp
, u32 rkey
)
523 struct rxe_dev
*rxe
= to_rdev(qp
->ibqp
.device
);
527 mr
= rxe_pool_get_index(&rxe
->mr_pool
, rkey
>> 8);
529 pr_err("%s: No MR for rkey %#x\n", __func__
, rkey
);
534 if (rkey
!= mr
->ibmr
.rkey
) {
535 pr_err("%s: rkey (%#x) doesn't match mr->ibmr.rkey (%#x)\n",
536 __func__
, rkey
, mr
->ibmr
.rkey
);
541 if (atomic_read(&mr
->num_mw
) > 0) {
542 pr_warn("%s: Attempt to invalidate an MR while bound to MWs\n",
548 mr
->state
= RXE_MR_STATE_FREE
;
557 int rxe_dereg_mr(struct ib_mr
*ibmr
, struct ib_udata
*udata
)
559 struct rxe_mr
*mr
= to_rmr(ibmr
);
561 if (atomic_read(&mr
->num_mw
) > 0) {
562 pr_warn("%s: Attempt to deregister an MR while bound to MWs\n",
567 mr
->state
= RXE_MR_STATE_ZOMBIE
;
568 rxe_drop_ref(mr_pd(mr
));
575 void rxe_mr_cleanup(struct rxe_pool_entry
*arg
)
577 struct rxe_mr
*mr
= container_of(arg
, typeof(*mr
), pelem
);
580 ib_umem_release(mr
->umem
);
583 for (i
= 0; i
< mr
->num_map
; i
++)