diff options
author | Mitko Haralanov <mitko.haralanov@intel.com> | 2016-03-08 14:15:22 -0500 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2016-03-21 15:55:24 -0400 |
commit | 5cd3a88d7f2b050164dc1df59a398294515126d9 (patch) | |
tree | d6d1175f3a20b9b49a6b99ec77123a6c8f9575a0 | |
parent | a489876010377481823ae5dbbd83fa32792a2e16 (diff) |
IB/hfi1: Implement SDMA-side buffer caching
Add support for caching of user buffers used for SDMA
transfers. This change improves performance by
avoiding repeatedly pinning the pages of buffers, which
are being re-used by the application.
While the cost of the pinning operation has been made
heavier by adding the extra code to search the cache tree,
re-allocate pages arrays, and future cache evictions,
that cost will be amortized against the savings when the
same buffer is re-used. It is also worth noting that in
most cases, the cost of pinning should be much lower due
to the buffer already being in the cache.
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Reviewed-by: Dean Luick <dean.luick@intel.com>
Signed-off-by: Mitko Haralanov <mitko.haralanov@intel.com>
Signed-off-by: Jubin John <jubin.john@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/staging/rdma/hfi1/user_sdma.c | 255 | ||||
-rw-r--r-- | drivers/staging/rdma/hfi1/user_sdma.h | 1 |
2 files changed, 155 insertions, 101 deletions
diff --git a/drivers/staging/rdma/hfi1/user_sdma.c b/drivers/staging/rdma/hfi1/user_sdma.c index 14fe0790a35b..a53edb96ca50 100644 --- a/drivers/staging/rdma/hfi1/user_sdma.c +++ b/drivers/staging/rdma/hfi1/user_sdma.c | |||
@@ -68,6 +68,7 @@ | |||
68 | #include "verbs.h" /* for the headers */ | 68 | #include "verbs.h" /* for the headers */ |
69 | #include "common.h" /* for struct hfi1_tid_info */ | 69 | #include "common.h" /* for struct hfi1_tid_info */ |
70 | #include "trace.h" | 70 | #include "trace.h" |
71 | #include "mmu_rb.h" | ||
71 | 72 | ||
72 | static uint hfi1_sdma_comp_ring_size = 128; | 73 | static uint hfi1_sdma_comp_ring_size = 128; |
73 | module_param_named(sdma_comp_size, hfi1_sdma_comp_ring_size, uint, S_IRUGO); | 74 | module_param_named(sdma_comp_size, hfi1_sdma_comp_ring_size, uint, S_IRUGO); |
@@ -145,9 +146,6 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12 | |||
145 | /* Last packet in the request */ | 146 | /* Last packet in the request */ |
146 | #define TXREQ_FLAGS_REQ_LAST_PKT BIT(0) | 147 | #define TXREQ_FLAGS_REQ_LAST_PKT BIT(0) |
147 | 148 | ||
148 | /* Last packet that uses a particular io vector */ | ||
149 | #define TXREQ_FLAGS_IOVEC_LAST_PKT BIT(0) | ||
150 | |||
151 | #define SDMA_REQ_IN_USE 0 | 149 | #define SDMA_REQ_IN_USE 0 |
152 | #define SDMA_REQ_FOR_THREAD 1 | 150 | #define SDMA_REQ_FOR_THREAD 1 |
153 | #define SDMA_REQ_SEND_DONE 2 | 151 | #define SDMA_REQ_SEND_DONE 2 |
@@ -183,6 +181,13 @@ struct user_sdma_iovec { | |||
183 | u64 offset; | 181 | u64 offset; |
184 | }; | 182 | }; |
185 | 183 | ||
184 | struct sdma_mmu_node { | ||
185 | struct mmu_rb_node rb; | ||
186 | atomic_t refcount; | ||
187 | struct page **pages; | ||
188 | unsigned npages; | ||
189 | }; | ||
190 | |||
186 | struct user_sdma_request { | 191 | struct user_sdma_request { |
187 | struct sdma_req_info info; | 192 | struct sdma_req_info info; |
188 | struct hfi1_user_sdma_pkt_q *pq; | 193 | struct hfi1_user_sdma_pkt_q *pq; |
@@ -252,11 +257,6 @@ struct user_sdma_txreq { | |||
252 | struct sdma_txreq txreq; | 257 | struct sdma_txreq txreq; |
253 | struct list_head list; | 258 | struct list_head list; |
254 | struct user_sdma_request *req; | 259 | struct user_sdma_request *req; |
255 | struct { | ||
256 | struct user_sdma_iovec *vec; | ||
257 | u8 flags; | ||
258 | } iovecs[3]; | ||
259 | int idx; | ||
260 | u16 flags; | 260 | u16 flags; |
261 | unsigned busycount; | 261 | unsigned busycount; |
262 | u64 seqnum; | 262 | u64 seqnum; |
@@ -277,7 +277,7 @@ static inline void pq_update(struct hfi1_user_sdma_pkt_q *); | |||
277 | static void user_sdma_free_request(struct user_sdma_request *, bool); | 277 | static void user_sdma_free_request(struct user_sdma_request *, bool); |
278 | static int pin_vector_pages(struct user_sdma_request *, | 278 | static int pin_vector_pages(struct user_sdma_request *, |
279 | struct user_sdma_iovec *); | 279 | struct user_sdma_iovec *); |
280 | static void unpin_vector_pages(struct user_sdma_iovec *); | 280 | static void unpin_vector_pages(struct page **, unsigned); |
281 | static int check_header_template(struct user_sdma_request *, | 281 | static int check_header_template(struct user_sdma_request *, |
282 | struct hfi1_pkt_header *, u32, u32); | 282 | struct hfi1_pkt_header *, u32, u32); |
283 | static int set_txreq_header(struct user_sdma_request *, | 283 | static int set_txreq_header(struct user_sdma_request *, |
@@ -296,6 +296,17 @@ static int defer_packet_queue( | |||
296 | struct sdma_txreq *, | 296 | struct sdma_txreq *, |
297 | unsigned seq); | 297 | unsigned seq); |
298 | static void activate_packet_queue(struct iowait *, int); | 298 | static void activate_packet_queue(struct iowait *, int); |
299 | static bool sdma_rb_filter(struct mmu_rb_node *, unsigned long, unsigned long); | ||
300 | static int sdma_rb_insert(struct rb_root *, struct mmu_rb_node *); | ||
301 | static void sdma_rb_remove(struct rb_root *, struct mmu_rb_node *, bool); | ||
302 | static int sdma_rb_invalidate(struct rb_root *, struct mmu_rb_node *); | ||
303 | |||
304 | static struct mmu_rb_ops sdma_rb_ops = { | ||
305 | .filter = sdma_rb_filter, | ||
306 | .insert = sdma_rb_insert, | ||
307 | .remove = sdma_rb_remove, | ||
308 | .invalidate = sdma_rb_invalidate | ||
309 | }; | ||
299 | 310 | ||
300 | static int defer_packet_queue( | 311 | static int defer_packet_queue( |
301 | struct sdma_engine *sde, | 312 | struct sdma_engine *sde, |
@@ -385,6 +396,7 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp) | |||
385 | pq->state = SDMA_PKT_Q_INACTIVE; | 396 | pq->state = SDMA_PKT_Q_INACTIVE; |
386 | atomic_set(&pq->n_reqs, 0); | 397 | atomic_set(&pq->n_reqs, 0); |
387 | init_waitqueue_head(&pq->wait); | 398 | init_waitqueue_head(&pq->wait); |
399 | pq->sdma_rb_root = RB_ROOT; | ||
388 | 400 | ||
389 | iowait_init(&pq->busy, 0, NULL, defer_packet_queue, | 401 | iowait_init(&pq->busy, 0, NULL, defer_packet_queue, |
390 | activate_packet_queue, NULL); | 402 | activate_packet_queue, NULL); |
@@ -415,6 +427,12 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp) | |||
415 | cq->nentries = hfi1_sdma_comp_ring_size; | 427 | cq->nentries = hfi1_sdma_comp_ring_size; |
416 | fd->cq = cq; | 428 | fd->cq = cq; |
417 | 429 | ||
430 | ret = hfi1_mmu_rb_register(&pq->sdma_rb_root, &sdma_rb_ops); | ||
431 | if (ret) { | ||
432 | dd_dev_err(dd, "Failed to register with MMU %d", ret); | ||
433 | goto done; | ||
434 | } | ||
435 | |||
418 | spin_lock_irqsave(&uctxt->sdma_qlock, flags); | 436 | spin_lock_irqsave(&uctxt->sdma_qlock, flags); |
419 | list_add(&pq->list, &uctxt->sdma_queues); | 437 | list_add(&pq->list, &uctxt->sdma_queues); |
420 | spin_unlock_irqrestore(&uctxt->sdma_qlock, flags); | 438 | spin_unlock_irqrestore(&uctxt->sdma_qlock, flags); |
@@ -444,6 +462,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd) | |||
444 | hfi1_cdbg(SDMA, "[%u:%u:%u] Freeing user SDMA queues", uctxt->dd->unit, | 462 | hfi1_cdbg(SDMA, "[%u:%u:%u] Freeing user SDMA queues", uctxt->dd->unit, |
445 | uctxt->ctxt, fd->subctxt); | 463 | uctxt->ctxt, fd->subctxt); |
446 | pq = fd->pq; | 464 | pq = fd->pq; |
465 | hfi1_mmu_rb_unregister(&pq->sdma_rb_root); | ||
447 | if (pq) { | 466 | if (pq) { |
448 | spin_lock_irqsave(&uctxt->sdma_qlock, flags); | 467 | spin_lock_irqsave(&uctxt->sdma_qlock, flags); |
449 | if (!list_empty(&pq->list)) | 468 | if (!list_empty(&pq->list)) |
@@ -477,7 +496,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec, | |||
477 | struct hfi1_user_sdma_pkt_q *pq = fd->pq; | 496 | struct hfi1_user_sdma_pkt_q *pq = fd->pq; |
478 | struct hfi1_user_sdma_comp_q *cq = fd->cq; | 497 | struct hfi1_user_sdma_comp_q *cq = fd->cq; |
479 | struct hfi1_devdata *dd = pq->dd; | 498 | struct hfi1_devdata *dd = pq->dd; |
480 | unsigned long idx = 0, unpinned; | 499 | unsigned long idx = 0; |
481 | u8 pcount = initial_pkt_count; | 500 | u8 pcount = initial_pkt_count; |
482 | struct sdma_req_info info; | 501 | struct sdma_req_info info; |
483 | struct user_sdma_request *req; | 502 | struct user_sdma_request *req; |
@@ -498,14 +517,6 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec, | |||
498 | return -EFAULT; | 517 | return -EFAULT; |
499 | } | 518 | } |
500 | 519 | ||
501 | /* Process any completed vectors */ | ||
502 | unpinned = xchg(&pq->unpinned, 0); | ||
503 | if (unpinned) { | ||
504 | down_write(¤t->mm->mmap_sem); | ||
505 | current->mm->pinned_vm -= unpinned; | ||
506 | up_write(¤t->mm->mmap_sem); | ||
507 | } | ||
508 | |||
509 | trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, fd->subctxt, | 520 | trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, fd->subctxt, |
510 | (u16 *)&info); | 521 | (u16 *)&info); |
511 | if (cq->comps[info.comp_idx].status == QUEUED || | 522 | if (cq->comps[info.comp_idx].status == QUEUED || |
@@ -609,7 +620,11 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec, | |||
609 | while (i < req->data_iovs) { | 620 | while (i < req->data_iovs) { |
610 | INIT_LIST_HEAD(&req->iovs[i].list); | 621 | INIT_LIST_HEAD(&req->iovs[i].list); |
611 | memcpy(&req->iovs[i].iov, iovec + idx++, sizeof(struct iovec)); | 622 | memcpy(&req->iovs[i].iov, iovec + idx++, sizeof(struct iovec)); |
612 | req->iovs[i].offset = 0; | 623 | ret = pin_vector_pages(req, &req->iovs[i]); |
624 | if (ret) { | ||
625 | req->status = ret; | ||
626 | goto free_req; | ||
627 | } | ||
613 | req->data_len += req->iovs[i++].iov.iov_len; | 628 | req->data_len += req->iovs[i++].iov.iov_len; |
614 | } | 629 | } |
615 | SDMA_DBG(req, "total data length %u", req->data_len); | 630 | SDMA_DBG(req, "total data length %u", req->data_len); |
@@ -827,9 +842,7 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) | |||
827 | tx->flags = 0; | 842 | tx->flags = 0; |
828 | tx->req = req; | 843 | tx->req = req; |
829 | tx->busycount = 0; | 844 | tx->busycount = 0; |
830 | tx->idx = -1; | ||
831 | INIT_LIST_HEAD(&tx->list); | 845 | INIT_LIST_HEAD(&tx->list); |
832 | memset(tx->iovecs, 0, sizeof(tx->iovecs)); | ||
833 | 846 | ||
834 | if (req->seqnum == req->info.npkts - 1) | 847 | if (req->seqnum == req->info.npkts - 1) |
835 | tx->flags |= TXREQ_FLAGS_REQ_LAST_PKT; | 848 | tx->flags |= TXREQ_FLAGS_REQ_LAST_PKT; |
@@ -850,18 +863,6 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) | |||
850 | WARN_ON(iovec->offset); | 863 | WARN_ON(iovec->offset); |
851 | } | 864 | } |
852 | 865 | ||
853 | /* | ||
854 | * This request might include only a header and no user | ||
855 | * data, so pin pages only if there is data and it the | ||
856 | * pages have not been pinned already. | ||
857 | */ | ||
858 | if (unlikely(!iovec->pages && iovec->iov.iov_len)) { | ||
859 | ret = pin_vector_pages(req, iovec); | ||
860 | if (ret) | ||
861 | goto free_tx; | ||
862 | } | ||
863 | |||
864 | tx->iovecs[++tx->idx].vec = iovec; | ||
865 | datalen = compute_data_length(req, tx); | 866 | datalen = compute_data_length(req, tx); |
866 | if (!datalen) { | 867 | if (!datalen) { |
867 | SDMA_DBG(req, | 868 | SDMA_DBG(req, |
@@ -960,19 +961,10 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) | |||
960 | data_sent += len; | 961 | data_sent += len; |
961 | if (unlikely(queued < datalen && | 962 | if (unlikely(queued < datalen && |
962 | pageidx == iovec->npages && | 963 | pageidx == iovec->npages && |
963 | req->iov_idx < req->data_iovs - 1 && | 964 | req->iov_idx < req->data_iovs - 1)) { |
964 | tx->idx < ARRAY_SIZE(tx->iovecs))) { | ||
965 | iovec->offset += iov_offset; | 965 | iovec->offset += iov_offset; |
966 | tx->iovecs[tx->idx].flags |= | ||
967 | TXREQ_FLAGS_IOVEC_LAST_PKT; | ||
968 | iovec = &req->iovs[++req->iov_idx]; | 966 | iovec = &req->iovs[++req->iov_idx]; |
969 | if (!iovec->pages) { | ||
970 | ret = pin_vector_pages(req, iovec); | ||
971 | if (ret) | ||
972 | goto free_txreq; | ||
973 | } | ||
974 | iov_offset = 0; | 967 | iov_offset = 0; |
975 | tx->iovecs[++tx->idx].vec = iovec; | ||
976 | } | 968 | } |
977 | } | 969 | } |
978 | /* | 970 | /* |
@@ -983,18 +975,8 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) | |||
983 | if (req_opcode(req->info.ctrl) == EXPECTED) | 975 | if (req_opcode(req->info.ctrl) == EXPECTED) |
984 | req->tidoffset += datalen; | 976 | req->tidoffset += datalen; |
985 | req->sent += data_sent; | 977 | req->sent += data_sent; |
986 | if (req->data_len) { | 978 | if (req->data_len) |
987 | tx->iovecs[tx->idx].vec->offset += iov_offset; | 979 | iovec->offset += iov_offset; |
988 | /* | ||
989 | * If we've reached the end of the io vector, mark it | ||
990 | * so the callback can unpin the pages and free it. | ||
991 | */ | ||
992 | if (tx->iovecs[tx->idx].vec->offset == | ||
993 | tx->iovecs[tx->idx].vec->iov.iov_len) | ||
994 | tx->iovecs[tx->idx].flags |= | ||
995 | TXREQ_FLAGS_IOVEC_LAST_PKT; | ||
996 | } | ||
997 | |||
998 | list_add_tail(&tx->txreq.list, &req->txps); | 980 | list_add_tail(&tx->txreq.list, &req->txps); |
999 | /* | 981 | /* |
1000 | * It is important to increment this here as it is used to | 982 | * It is important to increment this here as it is used to |
@@ -1047,38 +1029,78 @@ static inline int num_user_pages(const struct iovec *iov) | |||
1047 | 1029 | ||
1048 | static int pin_vector_pages(struct user_sdma_request *req, | 1030 | static int pin_vector_pages(struct user_sdma_request *req, |
1049 | struct user_sdma_iovec *iovec) { | 1031 | struct user_sdma_iovec *iovec) { |
1050 | int pinned, npages; | 1032 | int ret = 0, pinned, npages; |
1033 | struct page **pages; | ||
1034 | struct hfi1_user_sdma_pkt_q *pq = req->pq; | ||
1035 | struct sdma_mmu_node *node = NULL; | ||
1036 | struct mmu_rb_node *rb_node; | ||
1037 | |||
1038 | rb_node = hfi1_mmu_rb_search(&pq->sdma_rb_root, | ||
1039 | (unsigned long)iovec->iov.iov_base, | ||
1040 | iovec->iov.iov_len); | ||
1041 | if (rb_node) | ||
1042 | node = container_of(rb_node, struct sdma_mmu_node, rb); | ||
1043 | |||
1044 | if (!node) { | ||
1045 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
1046 | if (!node) | ||
1047 | return -ENOMEM; | ||
1051 | 1048 | ||
1052 | npages = num_user_pages(&iovec->iov); | 1049 | node->rb.addr = (unsigned long)iovec->iov.iov_base; |
1053 | iovec->pages = kcalloc(npages, sizeof(*iovec->pages), GFP_KERNEL); | 1050 | node->rb.len = iovec->iov.iov_len; |
1054 | if (!iovec->pages) { | 1051 | atomic_set(&node->refcount, 0); |
1055 | SDMA_DBG(req, "Failed page array alloc"); | ||
1056 | return -ENOMEM; | ||
1057 | } | 1052 | } |
1058 | 1053 | ||
1059 | pinned = hfi1_acquire_user_pages((unsigned long)iovec->iov.iov_base, | 1054 | npages = num_user_pages(&iovec->iov); |
1060 | npages, 0, iovec->pages); | 1055 | if (node->npages < npages) { |
1061 | 1056 | pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL); | |
1062 | if (pinned < 0) | 1057 | if (!pages) { |
1063 | return pinned; | 1058 | SDMA_DBG(req, "Failed page array alloc"); |
1059 | ret = -ENOMEM; | ||
1060 | goto bail; | ||
1061 | } | ||
1062 | memcpy(pages, node->pages, node->npages * sizeof(*pages)); | ||
1063 | |||
1064 | npages -= node->npages; | ||
1065 | pinned = hfi1_acquire_user_pages( | ||
1066 | ((unsigned long)iovec->iov.iov_base + | ||
1067 | (node->npages * PAGE_SIZE)), npages, 0, | ||
1068 | pages + node->npages); | ||
1069 | if (pinned < 0) { | ||
1070 | kfree(pages); | ||
1071 | ret = pinned; | ||
1072 | goto bail; | ||
1073 | } | ||
1074 | if (pinned != npages) { | ||
1075 | unpin_vector_pages(pages, pinned); | ||
1076 | ret = -EFAULT; | ||
1077 | goto bail; | ||
1078 | } | ||
1079 | kfree(node->pages); | ||
1080 | node->pages = pages; | ||
1081 | node->npages += pinned; | ||
1082 | npages = node->npages; | ||
1083 | } | ||
1084 | iovec->pages = node->pages; | ||
1085 | iovec->npages = npages; | ||
1064 | 1086 | ||
1065 | iovec->npages = pinned; | 1087 | if (!rb_node) { |
1066 | if (pinned != npages) { | 1088 | if (hfi1_mmu_rb_insert(&req->pq->sdma_rb_root, &node->rb)) |
1067 | SDMA_DBG(req, "Failed to pin pages (%d/%u)", pinned, npages); | 1089 | goto bail; |
1068 | unpin_vector_pages(iovec); | 1090 | } else { |
1069 | return -EFAULT; | 1091 | atomic_inc(&node->refcount); |
1070 | } | 1092 | } |
1071 | return 0; | 1093 | return 0; |
1094 | bail: | ||
1095 | if (!rb_node) | ||
1096 | kfree(node); | ||
1097 | return ret; | ||
1072 | } | 1098 | } |
1073 | 1099 | ||
1074 | static void unpin_vector_pages(struct user_sdma_iovec *iovec) | 1100 | static void unpin_vector_pages(struct page **pages, unsigned npages) |
1075 | { | 1101 | { |
1076 | hfi1_release_user_pages(iovec->pages, iovec->npages, 0); | 1102 | hfi1_release_user_pages(pages, npages, 0); |
1077 | 1103 | kfree(pages); | |
1078 | kfree(iovec->pages); | ||
1079 | iovec->pages = NULL; | ||
1080 | iovec->npages = 0; | ||
1081 | iovec->offset = 0; | ||
1082 | } | 1104 | } |
1083 | 1105 | ||
1084 | static int check_header_template(struct user_sdma_request *req, | 1106 | static int check_header_template(struct user_sdma_request *req, |
@@ -1360,7 +1382,6 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) | |||
1360 | struct hfi1_user_sdma_pkt_q *pq; | 1382 | struct hfi1_user_sdma_pkt_q *pq; |
1361 | struct hfi1_user_sdma_comp_q *cq; | 1383 | struct hfi1_user_sdma_comp_q *cq; |
1362 | u16 idx; | 1384 | u16 idx; |
1363 | int i, j; | ||
1364 | 1385 | ||
1365 | if (!tx->req) | 1386 | if (!tx->req) |
1366 | return; | 1387 | return; |
@@ -1369,24 +1390,6 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) | |||
1369 | pq = req->pq; | 1390 | pq = req->pq; |
1370 | cq = req->cq; | 1391 | cq = req->cq; |
1371 | 1392 | ||
1372 | /* | ||
1373 | * If we have any io vectors associated with this txreq, | ||
1374 | * check whether they need to be 'freed'. | ||
1375 | */ | ||
1376 | for (i = tx->idx; i >= 0; i--) { | ||
1377 | if (tx->iovecs[i].flags & TXREQ_FLAGS_IOVEC_LAST_PKT) { | ||
1378 | struct user_sdma_iovec *vec = | ||
1379 | tx->iovecs[i].vec; | ||
1380 | |||
1381 | for (j = 0; j < vec->npages; j++) | ||
1382 | put_page(vec->pages[j]); | ||
1383 | xadd(&pq->unpinned, vec->npages); | ||
1384 | kfree(vec->pages); | ||
1385 | vec->pages = NULL; | ||
1386 | vec->npages = 0; | ||
1387 | } | ||
1388 | } | ||
1389 | |||
1390 | if (status != SDMA_TXREQ_S_OK) { | 1393 | if (status != SDMA_TXREQ_S_OK) { |
1391 | SDMA_DBG(req, "SDMA completion with error %d", | 1394 | SDMA_DBG(req, "SDMA completion with error %d", |
1392 | status); | 1395 | status); |
@@ -1439,12 +1442,26 @@ static void user_sdma_free_request(struct user_sdma_request *req, bool unpin) | |||
1439 | kmem_cache_free(req->pq->txreq_cache, tx); | 1442 | kmem_cache_free(req->pq->txreq_cache, tx); |
1440 | } | 1443 | } |
1441 | } | 1444 | } |
1442 | if (req->data_iovs && unpin) { | 1445 | if (req->data_iovs) { |
1446 | struct sdma_mmu_node *node; | ||
1447 | struct mmu_rb_node *mnode; | ||
1443 | int i; | 1448 | int i; |
1444 | 1449 | ||
1445 | for (i = 0; i < req->data_iovs; i++) | 1450 | for (i = 0; i < req->data_iovs; i++) { |
1446 | if (req->iovs[i].npages && req->iovs[i].pages) | 1451 | mnode = hfi1_mmu_rb_search( |
1447 | unpin_vector_pages(&req->iovs[i]); | 1452 | &req->pq->sdma_rb_root, |
1453 | (unsigned long)req->iovs[i].iov.iov_base, | ||
1454 | req->iovs[i].iov.iov_len); | ||
1455 | if (!mnode) | ||
1456 | continue; | ||
1457 | |||
1458 | node = container_of(mnode, struct sdma_mmu_node, rb); | ||
1459 | if (unpin) | ||
1460 | hfi1_mmu_rb_remove(&req->pq->sdma_rb_root, | ||
1461 | &node->rb); | ||
1462 | else | ||
1463 | atomic_dec(&node->refcount); | ||
1464 | } | ||
1448 | } | 1465 | } |
1449 | kfree(req->tids); | 1466 | kfree(req->tids); |
1450 | clear_bit(SDMA_REQ_IN_USE, &req->flags); | 1467 | clear_bit(SDMA_REQ_IN_USE, &req->flags); |
@@ -1463,3 +1480,39 @@ static inline void set_comp_state(struct hfi1_user_sdma_pkt_q *pq, | |||
1463 | trace_hfi1_sdma_user_completion(pq->dd, pq->ctxt, pq->subctxt, | 1480 | trace_hfi1_sdma_user_completion(pq->dd, pq->ctxt, pq->subctxt, |
1464 | idx, state, ret); | 1481 | idx, state, ret); |
1465 | } | 1482 | } |
1483 | |||
1484 | static bool sdma_rb_filter(struct mmu_rb_node *node, unsigned long addr, | ||
1485 | unsigned long len) | ||
1486 | { | ||
1487 | return (bool)(node->addr == addr); | ||
1488 | } | ||
1489 | |||
1490 | static int sdma_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) | ||
1491 | { | ||
1492 | struct sdma_mmu_node *node = | ||
1493 | container_of(mnode, struct sdma_mmu_node, rb); | ||
1494 | |||
1495 | atomic_inc(&node->refcount); | ||
1496 | return 0; | ||
1497 | } | ||
1498 | |||
1499 | static void sdma_rb_remove(struct rb_root *root, struct mmu_rb_node *mnode, | ||
1500 | bool notifier) | ||
1501 | { | ||
1502 | struct sdma_mmu_node *node = | ||
1503 | container_of(mnode, struct sdma_mmu_node, rb); | ||
1504 | |||
1505 | if (!notifier) | ||
1506 | unpin_vector_pages(node->pages, node->npages); | ||
1507 | kfree(node); | ||
1508 | } | ||
1509 | |||
1510 | static int sdma_rb_invalidate(struct rb_root *root, struct mmu_rb_node *mnode) | ||
1511 | { | ||
1512 | struct sdma_mmu_node *node = | ||
1513 | container_of(mnode, struct sdma_mmu_node, rb); | ||
1514 | |||
1515 | if (!atomic_read(&node->refcount)) | ||
1516 | return 1; | ||
1517 | return 0; | ||
1518 | } | ||
diff --git a/drivers/staging/rdma/hfi1/user_sdma.h b/drivers/staging/rdma/hfi1/user_sdma.h index e0d0fe02d557..39866b546523 100644 --- a/drivers/staging/rdma/hfi1/user_sdma.h +++ b/drivers/staging/rdma/hfi1/user_sdma.h | |||
@@ -67,6 +67,7 @@ struct hfi1_user_sdma_pkt_q { | |||
67 | unsigned state; | 67 | unsigned state; |
68 | wait_queue_head_t wait; | 68 | wait_queue_head_t wait; |
69 | unsigned long unpinned; | 69 | unsigned long unpinned; |
70 | struct rb_root sdma_rb_root; | ||
70 | }; | 71 | }; |
71 | 72 | ||
72 | struct hfi1_user_sdma_comp_q { | 73 | struct hfi1_user_sdma_comp_q { |