Whenever the IB_MR_TYPE_DMA flag is set in imbr.type, the "iova" (I/O virtual address) is not really a virtual address but a physical address. This means that the use of virt_to_page() on these addresses is also incorrect, this needs to be treated and converted to a page using the page frame number and pfn_to_page(). Fix up all users in this file. Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray") Cc: Bob Pearson <rpearsonhpe@xxxxxxxxx> Reported-by: Jason Gunthorpe <jgg@xxxxxxxxxx> Link: https://lore.kernel.org/linux-rdma/ZB2s3GeaN%2FFBpR5K@xxxxxxxxxx/ Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> --- ChangeLog v1->v2: - New patch prepended to patch set. --- drivers/infiniband/sw/rxe/rxe_mr.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index b10aa1580a64..8e8250652f9d 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -279,16 +279,20 @@ static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr, return 0; } -static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr, +/* + * This function is always called with a physical address as parameter, + * since DMA only operates on physical addresses. + */ +static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 phys, void *addr, unsigned int length, enum rxe_mr_copy_dir dir) { - unsigned int page_offset = iova & (PAGE_SIZE - 1); + unsigned int page_offset = phys & (PAGE_SIZE - 1); unsigned int bytes; struct page *page; u8 *va; while (length) { - page = virt_to_page(iova & mr->page_mask); + page = pfn_to_page(phys >> PAGE_SHIFT); bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); va = kmap_local_page(page); @@ -300,7 +304,7 @@ static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr, kunmap_local(va); page_offset = 0; - iova += bytes; + phys += bytes; addr += bytes; length -= bytes; } @@ -487,8 +491,11 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, } if (mr->ibmr.type == IB_MR_TYPE_DMA) { - page_offset = iova & (PAGE_SIZE - 1); - page = virt_to_page(iova & PAGE_MASK); + /* In this case iova is a physical address */ + u64 phys = iova; + + page_offset = phys & (PAGE_SIZE - 1); + page = pfn_to_page(phys >> PAGE_SHIFT); } else { unsigned long index; int err; @@ -544,8 +551,11 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) } if (mr->ibmr.type == IB_MR_TYPE_DMA) { - page_offset = iova & (PAGE_SIZE - 1); - page = virt_to_page(iova & PAGE_MASK); + /* In this case iova is a physical address */ + u64 phys = iova; + + page_offset = phys & (PAGE_SIZE - 1); + page = pfn_to_page(phys >> PAGE_SHIFT); } else { unsigned long index; int err; -- 2.34.1