aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtemy Kovalyov <artemyko@mellanox.com>2017-04-05 02:23:55 -0400
committerDoug Ledford <dledford@redhat.com>2017-04-25 15:40:28 -0400
commit403cd12e2cf759ead5cbdcb62bf9872b9618d400 (patch)
tree79699ef47b0813f8f7f861f6a92397fb67b00da5
parent4df4a5bac3264efa0595b52b2a9cd5274b32f0d4 (diff)
IB/umem: Add contiguous ODP support
Currenlty ODP supports only regular MMU pages. Add ODP support for regions consisting of physically contiguous chunks of arbitrary order (huge pages for instance) to improve performance. Signed-off-by: Artemy Kovalyov <artemyko@mellanox.com> Signed-off-by: Leon Romanovsky <leon@kernel.org> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/infiniband/core/umem_odp.c50
-rw-r--r--include/rdma/ib_umem.h4
2 files changed, 33 insertions, 21 deletions
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 8ee30163497d..73053c8a9e3b 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -504,7 +504,6 @@ out:
504static int ib_umem_odp_map_dma_single_page( 504static int ib_umem_odp_map_dma_single_page(
505 struct ib_umem *umem, 505 struct ib_umem *umem,
506 int page_index, 506 int page_index,
507 u64 base_virt_addr,
508 struct page *page, 507 struct page *page,
509 u64 access_mask, 508 u64 access_mask,
510 unsigned long current_seq) 509 unsigned long current_seq)
@@ -527,7 +526,7 @@ static int ib_umem_odp_map_dma_single_page(
527 if (!(umem->odp_data->dma_list[page_index])) { 526 if (!(umem->odp_data->dma_list[page_index])) {
528 dma_addr = ib_dma_map_page(dev, 527 dma_addr = ib_dma_map_page(dev,
529 page, 528 page,
530 0, PAGE_SIZE, 529 0, BIT(umem->page_shift),
531 DMA_BIDIRECTIONAL); 530 DMA_BIDIRECTIONAL);
532 if (ib_dma_mapping_error(dev, dma_addr)) { 531 if (ib_dma_mapping_error(dev, dma_addr)) {
533 ret = -EFAULT; 532 ret = -EFAULT;
@@ -555,8 +554,9 @@ out:
555 if (remove_existing_mapping && umem->context->invalidate_range) { 554 if (remove_existing_mapping && umem->context->invalidate_range) {
556 invalidate_page_trampoline( 555 invalidate_page_trampoline(
557 umem, 556 umem,
558 base_virt_addr + (page_index * PAGE_SIZE), 557 ib_umem_start(umem) + (page_index >> umem->page_shift),
559 base_virt_addr + ((page_index+1)*PAGE_SIZE), 558 ib_umem_start(umem) + ((page_index + 1) >>
559 umem->page_shift),
560 NULL); 560 NULL);
561 ret = -EAGAIN; 561 ret = -EAGAIN;
562 } 562 }
@@ -595,10 +595,10 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
595 struct task_struct *owning_process = NULL; 595 struct task_struct *owning_process = NULL;
596 struct mm_struct *owning_mm = NULL; 596 struct mm_struct *owning_mm = NULL;
597 struct page **local_page_list = NULL; 597 struct page **local_page_list = NULL;
598 u64 off; 598 u64 page_mask, off;
599 int j, k, ret = 0, start_idx, npages = 0; 599 int j, k, ret = 0, start_idx, npages = 0, page_shift;
600 u64 base_virt_addr;
601 unsigned int flags = 0; 600 unsigned int flags = 0;
601 phys_addr_t p = 0;
602 602
603 if (access_mask == 0) 603 if (access_mask == 0)
604 return -EINVAL; 604 return -EINVAL;
@@ -611,9 +611,10 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
611 if (!local_page_list) 611 if (!local_page_list)
612 return -ENOMEM; 612 return -ENOMEM;
613 613
614 off = user_virt & (~PAGE_MASK); 614 page_shift = umem->page_shift;
615 user_virt = user_virt & PAGE_MASK; 615 page_mask = ~(BIT(page_shift) - 1);
616 base_virt_addr = user_virt; 616 off = user_virt & (~page_mask);
617 user_virt = user_virt & page_mask;
617 bcnt += off; /* Charge for the first page offset as well. */ 618 bcnt += off; /* Charge for the first page offset as well. */
618 619
619 owning_process = get_pid_task(umem->context->tgid, PIDTYPE_PID); 620 owning_process = get_pid_task(umem->context->tgid, PIDTYPE_PID);
@@ -631,13 +632,13 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
631 if (access_mask & ODP_WRITE_ALLOWED_BIT) 632 if (access_mask & ODP_WRITE_ALLOWED_BIT)
632 flags |= FOLL_WRITE; 633 flags |= FOLL_WRITE;
633 634
634 start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT; 635 start_idx = (user_virt - ib_umem_start(umem)) >> page_shift;
635 k = start_idx; 636 k = start_idx;
636 637
637 while (bcnt > 0) { 638 while (bcnt > 0) {
638 const size_t gup_num_pages = 639 const size_t gup_num_pages = min_t(size_t,
639 min_t(size_t, ALIGN(bcnt, PAGE_SIZE) / PAGE_SIZE, 640 (bcnt + BIT(page_shift) - 1) >> page_shift,
640 PAGE_SIZE / sizeof(struct page *)); 641 PAGE_SIZE / sizeof(struct page *));
641 642
642 down_read(&owning_mm->mmap_sem); 643 down_read(&owning_mm->mmap_sem);
643 /* 644 /*
@@ -656,14 +657,25 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
656 break; 657 break;
657 658
658 bcnt -= min_t(size_t, npages << PAGE_SHIFT, bcnt); 659 bcnt -= min_t(size_t, npages << PAGE_SHIFT, bcnt);
659 user_virt += npages << PAGE_SHIFT;
660 mutex_lock(&umem->odp_data->umem_mutex); 660 mutex_lock(&umem->odp_data->umem_mutex);
661 for (j = 0; j < npages; ++j) { 661 for (j = 0; j < npages; j++, user_virt += PAGE_SIZE) {
662 if (user_virt & ~page_mask) {
663 p += PAGE_SIZE;
664 if (page_to_phys(local_page_list[j]) != p) {
665 ret = -EFAULT;
666 break;
667 }
668 put_page(local_page_list[j]);
669 continue;
670 }
671
662 ret = ib_umem_odp_map_dma_single_page( 672 ret = ib_umem_odp_map_dma_single_page(
663 umem, k, base_virt_addr, local_page_list[j], 673 umem, k, local_page_list[j],
664 access_mask, current_seq); 674 access_mask, current_seq);
665 if (ret < 0) 675 if (ret < 0)
666 break; 676 break;
677
678 p = page_to_phys(local_page_list[j]);
667 k++; 679 k++;
668 } 680 }
669 mutex_unlock(&umem->odp_data->umem_mutex); 681 mutex_unlock(&umem->odp_data->umem_mutex);
@@ -708,7 +720,7 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
708 * once. */ 720 * once. */
709 mutex_lock(&umem->odp_data->umem_mutex); 721 mutex_lock(&umem->odp_data->umem_mutex);
710 for (addr = virt; addr < bound; addr += BIT(umem->page_shift)) { 722 for (addr = virt; addr < bound; addr += BIT(umem->page_shift)) {
711 idx = (addr - ib_umem_start(umem)) / PAGE_SIZE; 723 idx = (addr - ib_umem_start(umem)) >> umem->page_shift;
712 if (umem->odp_data->page_list[idx]) { 724 if (umem->odp_data->page_list[idx]) {
713 struct page *page = umem->odp_data->page_list[idx]; 725 struct page *page = umem->odp_data->page_list[idx];
714 dma_addr_t dma = umem->odp_data->dma_list[idx]; 726 dma_addr_t dma = umem->odp_data->dma_list[idx];
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
index 7f4af1e1ae64..23159dd5be18 100644
--- a/include/rdma/ib_umem.h
+++ b/include/rdma/ib_umem.h
@@ -72,12 +72,12 @@ static inline unsigned long ib_umem_start(struct ib_umem *umem)
72/* Returns the address of the page after the last one of an ODP umem. */ 72/* Returns the address of the page after the last one of an ODP umem. */
73static inline unsigned long ib_umem_end(struct ib_umem *umem) 73static inline unsigned long ib_umem_end(struct ib_umem *umem)
74{ 74{
75 return PAGE_ALIGN(umem->address + umem->length); 75 return ALIGN(umem->address + umem->length, BIT(umem->page_shift));
76} 76}
77 77
78static inline size_t ib_umem_num_pages(struct ib_umem *umem) 78static inline size_t ib_umem_num_pages(struct ib_umem *umem)
79{ 79{
80 return (ib_umem_end(umem) - ib_umem_start(umem)) >> PAGE_SHIFT; 80 return (ib_umem_end(umem) - ib_umem_start(umem)) >> umem->page_shift;
81} 81}
82 82
83#ifdef CONFIG_INFINIBAND_USER_MEM 83#ifdef CONFIG_INFINIBAND_USER_MEM