diff options
| author | Kalderon, Michal <Michal.Kalderon@cavium.com> | 2018-05-15 08:13:33 -0400 |
|---|---|---|
| committer | Jason Gunthorpe <jgg@mellanox.com> | 2018-05-23 17:12:14 -0400 |
| commit | 30bf066cd9989fef34aeeef9080368867fe42be7 (patch) | |
| tree | 2a5a2a726b03f279d23e10f3837d562cefab8c41 | |
| parent | 8e907ed4882714fd13cfe670681fc6cb5284c780 (diff) | |
RDMA/qedr: Fix doorbell bar mapping for dpi > 1
Each user_context receives a separate dpi value and thus a different
address on the doorbell bar. The qedr_mmap function needs to validate
the address and map the doorbell bar accordingly.
The current implementation always checked against dpi=0 doorbell range
leading to a wrong mapping for doorbell bar. (It entered an else case
that mapped the address differently). qedr_mmap should only be used
for doorbells, so the else was actually wrong in the first place.
This only has an affect on arm architecture and not an issue on a
x86 based architecture.
This lead to doorbells not occurring on arm based systems and left
applications that use more than one dpi (or several applications
run simultaneously ) to hang.
Fixes: ac1b36e55a51 ("qedr: Add support for user context verbs")
Signed-off-by: Ariel Elior <Ariel.Elior@cavium.com>
Signed-off-by: Michal Kalderon <Michal.Kalderon@cavium.com>
Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
| -rw-r--r-- | drivers/infiniband/hw/qedr/verbs.c | 60 |
1 files changed, 29 insertions, 31 deletions
diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 7d3763b2e01c..3f9afc02d166 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c | |||
| @@ -401,49 +401,47 @@ int qedr_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | |||
| 401 | { | 401 | { |
| 402 | struct qedr_ucontext *ucontext = get_qedr_ucontext(context); | 402 | struct qedr_ucontext *ucontext = get_qedr_ucontext(context); |
| 403 | struct qedr_dev *dev = get_qedr_dev(context->device); | 403 | struct qedr_dev *dev = get_qedr_dev(context->device); |
| 404 | unsigned long vm_page = vma->vm_pgoff << PAGE_SHIFT; | 404 | unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT; |
| 405 | u64 unmapped_db = dev->db_phys_addr; | ||
| 406 | unsigned long len = (vma->vm_end - vma->vm_start); | 405 | unsigned long len = (vma->vm_end - vma->vm_start); |
| 407 | int rc = 0; | 406 | unsigned long dpi_start; |
| 408 | bool found; | 407 | |
| 408 | dpi_start = dev->db_phys_addr + (ucontext->dpi * ucontext->dpi_size); | ||
| 409 | 409 | ||
| 410 | DP_DEBUG(dev, QEDR_MSG_INIT, | 410 | DP_DEBUG(dev, QEDR_MSG_INIT, |
| 411 | "qedr_mmap called vm_page=0x%lx vm_pgoff=0x%lx unmapped_db=0x%llx db_size=%x, len=%lx\n", | 411 | "mmap invoked with vm_start=0x%pK, vm_end=0x%pK,vm_pgoff=0x%pK; dpi_start=0x%pK dpi_size=0x%x\n", |
| 412 | vm_page, vma->vm_pgoff, unmapped_db, dev->db_size, len); | 412 | (void *)vma->vm_start, (void *)vma->vm_end, |
| 413 | if (vma->vm_start & (PAGE_SIZE - 1)) { | 413 | (void *)vma->vm_pgoff, (void *)dpi_start, ucontext->dpi_size); |
| 414 | DP_ERR(dev, "Vma_start not page aligned = %ld\n", | 414 | |
| 415 | vma->vm_start); | 415 | if ((vma->vm_start & (PAGE_SIZE - 1)) || (len & (PAGE_SIZE - 1))) { |
| 416 | DP_ERR(dev, | ||
| 417 | "failed mmap, adrresses must be page aligned: start=0x%pK, end=0x%pK\n", | ||
| 418 | (void *)vma->vm_start, (void *)vma->vm_end); | ||
| 416 | return -EINVAL; | 419 | return -EINVAL; |
| 417 | } | 420 | } |
| 418 | 421 | ||
| 419 | found = qedr_search_mmap(ucontext, vm_page, len); | 422 | if (!qedr_search_mmap(ucontext, phys_addr, len)) { |
| 420 | if (!found) { | 423 | DP_ERR(dev, "failed mmap, vm_pgoff=0x%lx is not authorized\n", |
| 421 | DP_ERR(dev, "Vma_pgoff not found in mapped array = %ld\n", | ||
| 422 | vma->vm_pgoff); | 424 | vma->vm_pgoff); |
| 423 | return -EINVAL; | 425 | return -EINVAL; |
| 424 | } | 426 | } |
| 425 | 427 | ||
| 426 | DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping doorbell bar\n"); | 428 | if (phys_addr < dpi_start || |
| 427 | 429 | ((phys_addr + len) > (dpi_start + ucontext->dpi_size))) { | |
| 428 | if ((vm_page >= unmapped_db) && (vm_page <= (unmapped_db + | 430 | DP_ERR(dev, |
| 429 | dev->db_size))) { | 431 | "failed mmap, pages are outside of dpi; page address=0x%pK, dpi_start=0x%pK, dpi_size=0x%x\n", |
| 430 | DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping doorbell bar\n"); | 432 | (void *)phys_addr, (void *)dpi_start, |
| 431 | if (vma->vm_flags & VM_READ) { | 433 | ucontext->dpi_size); |
| 432 | DP_ERR(dev, "Trying to map doorbell bar for read\n"); | 434 | return -EINVAL; |
| 433 | return -EPERM; | 435 | } |
| 434 | } | ||
| 435 | |||
| 436 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
| 437 | 436 | ||
| 438 | rc = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, | 437 | if (vma->vm_flags & VM_READ) { |
| 439 | PAGE_SIZE, vma->vm_page_prot); | 438 | DP_ERR(dev, "failed mmap, cannot map doorbell bar for read\n"); |
| 440 | } else { | 439 | return -EINVAL; |
| 441 | DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping chains\n"); | ||
| 442 | rc = remap_pfn_range(vma, vma->vm_start, | ||
| 443 | vma->vm_pgoff, len, vma->vm_page_prot); | ||
| 444 | } | 440 | } |
| 445 | DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_mmap return code: %d\n", rc); | 441 | |
| 446 | return rc; | 442 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); |
| 443 | return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, len, | ||
| 444 | vma->vm_page_prot); | ||
| 447 | } | 445 | } |
| 448 | 446 | ||
| 449 | struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, | 447 | struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, |
