Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
* [PATCH rdma-next 0/2] RDMA/irdma: Fix FRWR and PBLE handling for PAGE_SIZE > 4K
@ 2026-10-22 21:06 Jacob Moroni
  2026-10-22 21:06 ` [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic " Jacob Moroni
  2026-10-22 21:06 ` [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ " Jacob Moroni
  0 siblings, 2 replies; 7+ messages in thread
From: Jacob Moroni @ 2026-10-22 21:06 UTC (permalink / raw)
  To: tatyana.e.nikolova, jgg, leon; +Cc: linux-rdma, Jacob Moroni

The irdma HW only supports 4K and 2M pages (plus 1G on newer HW), but
parts of the driver assumed PAGE_SIZE == 4K. On kernels with a larger
PAGE_SIZE (like arm64 with 64K pages), this resulted in a few issues:

  - FRWRs from ULPs that pass PAGE_SIZE to ib_map_mr_sg() end up
    getting mistranslated by the HW (discovered by observing SMMU
    faults).
  - Paged PBLE chunks and the virtual AEQ PBL point to the wrong
    offsets compared to what the driver assumed.

The first issue is fixed by building the FRWR page list from 4K pages
when the requested page size isn't supported (and scaling the PBL
allocation accordingly) and the second issue is fixed by accounting
for the potential difference between PAGE_SIZE and the HW's expected
4K page size (so a single page may end up populating multiple HW page
descriptors). Patch 2 depends on IRDMA_HW_PAGES_PER_PAGE, which is
added by patch 1.

Tested by running the same NFS/RDMA test that previously resulted
in SMMU errors on an arm64 system with a 64K kernel.

Jacob Moroni (2):
  RDMA/irdma: Fix FRWR logic for PAGE_SIZE > 4K
  RDMA/irdma: Fix paged PBLE and virtual AEQ for PAGE_SIZE > 4K

 drivers/infiniband/hw/irdma/ctrl.c  |  4 +++-
 drivers/infiniband/hw/irdma/defs.h  |  1 +
 drivers/infiniband/hw/irdma/hw.c    |  4 ++--
 drivers/infiniband/hw/irdma/utils.c | 22 ++++++++++--------
 drivers/infiniband/hw/irdma/verbs.c | 36 +++++++++++++++++++++++++++--
 5 files changed, 53 insertions(+), 14 deletions(-)


base-commit: c3e8e9451e6f1b69f685b75e0fbf14f3d0fb2539
-- 
2.56.0.218.g1ec904b173-goog


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic for PAGE_SIZE > 4K
  2026-10-22 21:06 [PATCH rdma-next 0/2] RDMA/irdma: Fix FRWR and PBLE handling for PAGE_SIZE > 4K Jacob Moroni
@ 2026-10-22 21:06 ` Jacob Moroni
  2026-10-22 21:13   ` sashiko-bot
  2026-10-28 19:59   ` Nikolova, Tatyana E
  2026-10-22 21:06 ` [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ " Jacob Moroni
  1 sibling, 2 replies; 7+ messages in thread
From: Jacob Moroni @ 2026-10-22 21:06 UTC (permalink / raw)
  To: tatyana.e.nikolova, jgg, leon; +Cc: linux-rdma, Jacob Moroni, Leah Li

The HW only supports 1G, 2M, and 4K page sizes, but some ULPs
pass PAGE_SIZE to ib_map_mr_sg(), and PAGE_SIZE can be some
multiple of 4K (64K arm kernels, etc.). The HW can still support
these scenarios, but we must force it to use 4K pages. The
max_fast_reg_page_list_len and page_cnt during MR allocation
must also be scaled to accommodate for the additional PBLEs
that will be used when ib_sg_to_pages() ends up producing
more pages than what would have otherwise been required with
the original page size. It is worth noting that this change
avoids this over-allocation/cracking in the off chance that
a 1G or 2M PAGE_SIZE is ever used; it's only applicable when
PAGE_SIZE is some power of 2 multiple of 4K that is not
currently supported by HW.

This was discovered by encountering SMMU faults when running
kernel NFS/RDMA on a 64K kernel, which was due to the page
list holding PAGE_SIZE entries while the WQE was indicating
4K, so HW was translating every access after the first 4K
incorrectly.

Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs")
Tested-by: Leah Li <leahlijuan@google.com>
Signed-off-by: Jacob Moroni <jmoroni@google.com>
---
 drivers/infiniband/hw/irdma/ctrl.c  |  4 +++-
 drivers/infiniband/hw/irdma/defs.h  |  1 +
 drivers/infiniband/hw/irdma/verbs.c | 36 +++++++++++++++++++++++++++--
 3 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c
index 1c2ad5773b9f..ef8627f070ce 100644
--- a/drivers/infiniband/hw/irdma/ctrl.c
+++ b/drivers/infiniband/hw/irdma/ctrl.c
@@ -1703,8 +1703,10 @@ int irdma_sc_mr_fast_register(struct irdma_sc_qp *qp,
 		page_size = IRDMA_PAGE_SIZE_1G;
 	else if (info->page_size == 0x200000)
 		page_size = IRDMA_PAGE_SIZE_2M;
-	else
+	else if (info->page_size == 0x1000)
 		page_size = IRDMA_PAGE_SIZE_4K;
+	else
+		return -EINVAL;
 
 	sq_info.wr_id = info->wr_id;
 	sq_info.signaled = info->signaled;
diff --git a/drivers/infiniband/hw/irdma/defs.h b/drivers/infiniband/hw/irdma/defs.h
index d6a3152959dd..eb9179664884 100644
--- a/drivers/infiniband/hw/irdma/defs.h
+++ b/drivers/infiniband/hw/irdma/defs.h
@@ -159,6 +159,7 @@ enum irdma_protocol_used {
 
 #define IRDMA_HW_PAGE_SIZE	4096
 #define IRDMA_HW_PAGE_SHIFT	12
+#define IRDMA_HW_PAGES_PER_PAGE	(PAGE_SIZE >> IRDMA_HW_PAGE_SHIFT)
 #define IRDMA_CQE_QTYPE_RQ	0
 #define IRDMA_CQE_QTYPE_SQ	1
 
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index c91c55917de9..9443e9732c4a 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -2,6 +2,21 @@
 /* Copyright (c) 2015 - 2021 Intel Corporation */
 #include "main.h"
 
+/**
+ * irdma_fmr_pages_per_page() - HW pages needed per PAGE_SIZE page in an FRWR.
+ * @dev: sc device
+ *
+ * If PAGE_SIZE is one of the HW supported page sizes, then it can be directly
+ * used. Otherwise, we need to break PAGE_SIZE into multiple HW (4K) pages.
+ */
+static u32 irdma_fmr_pages_per_page(struct irdma_sc_dev *dev)
+{
+	if (PAGE_SIZE & dev->hw_attrs.page_size_cap)
+		return 1;
+
+	return IRDMA_HW_PAGES_PER_PAGE;
+}
+
 /**
  * irdma_query_device - get device attributes
  * @ibdev: device pointer from stack
@@ -58,7 +73,8 @@ static int irdma_query_device(struct ib_device *ibdev,
 	props->max_mcast_grp = rf->max_mcg;
 	props->max_mcast_qp_attach = IRDMA_MAX_MGS_PER_CTX;
 	props->max_total_mcast_qp_attach = rf->max_qp * IRDMA_MAX_MGS_PER_CTX;
-	props->max_fast_reg_page_list_len = IRDMA_MAX_PAGES_PER_FMR;
+	props->max_fast_reg_page_list_len =
+		IRDMA_MAX_PAGES_PER_FMR / irdma_fmr_pages_per_page(&rf->sc_dev);
 	props->max_srq = rf->max_srq - rf->used_srqs;
 	props->max_srq_wr = IRDMA_MAX_SRQ_WRS;
 	props->max_srq_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
@@ -3208,12 +3224,16 @@ static struct ib_mr *irdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
 				    u32 max_num_sg)
 {
 	struct irdma_device *iwdev = to_iwdev(pd->device);
+	u32 pages_per_page = irdma_fmr_pages_per_page(&iwdev->rf->sc_dev);
 	struct irdma_pble_alloc *palloc;
 	struct irdma_pbl *iwpbl;
 	struct irdma_mr *iwmr;
 	u32 stag;
 	int err_code;
 
+	if (max_num_sg > IRDMA_MAX_PAGES_PER_FMR / pages_per_page)
+		return ERR_PTR(-EINVAL);
+
 	iwmr = kzalloc_obj(*iwmr);
 	if (!iwmr)
 		return ERR_PTR(-ENOMEM);
@@ -3233,7 +3253,12 @@ static struct ib_mr *irdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
 	iwpbl->iwmr = iwmr;
 	iwmr->type = IRDMA_MEMREG_TYPE_MEM;
 	palloc = &iwpbl->pble_alloc;
-	iwmr->page_cnt = max_num_sg;
+	/* Some ULPs pass PAGE_SIZE to ib_map_mr_sg() but PAGE_SIZE can be some
+	 * multiple of 4K that the HW does not natively support. We can work
+	 * around this by cracking the larger page into multiple 4K pages, but
+	 * page_cnt needs to be scaled.
+	 */
+	iwmr->page_cnt = max_num_sg * pages_per_page;
 	/* Use system PAGE_SIZE as the sg page sizes are unknown at this point */
 	iwmr->len = max_num_sg * PAGE_SIZE;
 	err_code = irdma_get_pble(iwdev->rf->pble_rsrc, palloc, iwmr->page_cnt,
@@ -3297,8 +3322,15 @@ static int irdma_set_page(struct ib_mr *ibmr, u64 addr)
 static int irdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
 			   int sg_nents, unsigned int *sg_offset)
 {
+	struct irdma_device *iwdev = to_iwdev(ibmr->device);
 	struct irdma_mr *iwmr = to_iwmr(ibmr);
 
+	/* HW only supports 4K, 2M and 1G pages, but some ULPs pass PAGE_SIZE
+	 * which can be some multiple of 4K that we do not support, so force 4K.
+	 */
+	if (!(ibmr->page_size & iwdev->rf->sc_dev.hw_attrs.page_size_cap))
+		ibmr->page_size = SZ_4K;
+
 	iwmr->npages = 0;
 
 	return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, irdma_set_page);
-- 
2.56.0.218.g1ec904b173-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ for PAGE_SIZE > 4K
  2026-10-22 21:06 [PATCH rdma-next 0/2] RDMA/irdma: Fix FRWR and PBLE handling for PAGE_SIZE > 4K Jacob Moroni
  2026-10-22 21:06 ` [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic " Jacob Moroni
@ 2026-10-22 21:06 ` Jacob Moroni
  2026-10-22 21:12   ` sashiko-bot
  2026-10-28 19:59   ` Nikolova, Tatyana E
  1 sibling, 2 replies; 7+ messages in thread
From: Jacob Moroni @ 2026-10-22 21:06 UTC (permalink / raw)
  To: tatyana.e.nikolova, jgg, leon; +Cc: linux-rdma, Jacob Moroni, Leah Li

HMC page descriptors and the virtual AEQ PBL always assume 4K
HW pages, but irdma_map_vm_page_list() returns one DMA address
per PAGE_SIZE page and irdma_pble_get_paged_mem() sizes the chunk
as PAGE_SIZE * pg_cnt.

This breaks when PAGE_SIZE is greater than 4K. For example, with
a 64K PAGE_SIZE, the second HW page points to vaddr+64K whereas
the driver assumes it to be at vaddr+4096, etc.

It also ends up using an incorrect chunk size which causes each
paged chunk to claim 16x more PBL entries than what actually exist.

Fix these issues by taking into account the potential difference
between the HW page size (4K) and the system PAGE_SIZE during
allocation and mapping (so on a 64K kernel, each page ends up
populating 16 PDs, etc.).

Fixes: 44d9e52977a1 ("RDMA/irdma: Implement device initialization definitions")
Fixes: 915cc7ac0f8e ("RDMA/irdma: Add miscellaneous utility definitions")
Tested-by: Leah Li <leahlijuan@google.com>
Signed-off-by: Jacob Moroni <jmoroni@google.com>
---
 drivers/infiniband/hw/irdma/hw.c    |  4 ++--
 drivers/infiniband/hw/irdma/utils.c | 22 +++++++++++++---------
 2 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c
index fbb8fb47d0d1..1d57b3c9f490 100644
--- a/drivers/infiniband/hw/irdma/hw.c
+++ b/drivers/infiniband/hw/irdma/hw.c
@@ -700,7 +700,7 @@ static void irdma_destroy_cqp(struct irdma_pci_f *rf)
 static void irdma_destroy_virt_aeq(struct irdma_pci_f *rf)
 {
 	struct irdma_aeq *aeq = &rf->aeq;
-	u32 pg_cnt = DIV_ROUND_UP(aeq->mem.size, PAGE_SIZE);
+	u32 pg_cnt = DIV_ROUND_UP(aeq->mem.size, IRDMA_HW_PAGE_SIZE);
 	dma_addr_t *pg_arr = (dma_addr_t *)aeq->palloc.level1.addr;
 
 	irdma_unmap_vm_page_list(&rf->hw, pg_arr, pg_cnt);
@@ -1479,7 +1479,7 @@ static int irdma_create_virt_aeq(struct irdma_pci_f *rf, u32 size)
 	if (!aeq->mem.va)
 		return -ENOMEM;
 
-	pg_cnt = DIV_ROUND_UP(aeq->mem.size, PAGE_SIZE);
+	pg_cnt = DIV_ROUND_UP(aeq->mem.size, IRDMA_HW_PAGE_SIZE);
 	status = irdma_get_pble(rf->pble_rsrc, &aeq->palloc, pg_cnt, true);
 	if (status) {
 		vfree(aeq->mem.va);
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index 290ad02ed657..3efc4125bb59 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -2199,20 +2199,24 @@ int irdma_map_vm_page_list(struct irdma_hw *hw, void *va, dma_addr_t *pg_dma,
 			   u32 pg_cnt)
 {
 	struct page *vm_page;
-	int i;
+	dma_addr_t dma;
+	u32 i, j;
 	u8 *addr;
 
 	addr = (u8 *)(uintptr_t)va;
-	for (i = 0; i < pg_cnt; i++) {
+	for (i = 0; i < pg_cnt; i += IRDMA_HW_PAGES_PER_PAGE) {
 		vm_page = vmalloc_to_page(addr);
 		if (!vm_page)
 			goto err;
 
-		pg_dma[i] = dma_map_page(hw->device, vm_page, 0, PAGE_SIZE,
-					 DMA_BIDIRECTIONAL);
-		if (dma_mapping_error(hw->device, pg_dma[i]))
+		dma = dma_map_page(hw->device, vm_page, 0, PAGE_SIZE,
+				   DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(hw->device, dma))
 			goto err;
 
+		for (j = 0; j < IRDMA_HW_PAGES_PER_PAGE && i + j < pg_cnt; j++)
+			pg_dma[i + j] = dma + j * IRDMA_HW_PAGE_SIZE;
+
 		addr += PAGE_SIZE;
 	}
 
@@ -2225,9 +2229,9 @@ int irdma_map_vm_page_list(struct irdma_hw *hw, void *va, dma_addr_t *pg_dma,
 
 void irdma_unmap_vm_page_list(struct irdma_hw *hw, dma_addr_t *pg_dma, u32 pg_cnt)
 {
-	int i;
+	u32 i;
 
-	for (i = 0; i < pg_cnt; i++)
+	for (i = 0; i < pg_cnt; i += IRDMA_HW_PAGES_PER_PAGE)
 		dma_unmap_page(hw->device, pg_dma[i], PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
@@ -2254,7 +2258,7 @@ void irdma_pble_free_paged_mem(struct irdma_chunk *chunk)
 /**
  * irdma_pble_get_paged_mem -allocate paged memory for pbles
  * @chunk: chunk to add for paged memory
- * @pg_cnt: number of pages needed
+ * @pg_cnt: number of HW (4K) pages needed
  */
 int irdma_pble_get_paged_mem(struct irdma_chunk *chunk, u32 pg_cnt)
 {
@@ -2265,7 +2269,7 @@ int irdma_pble_get_paged_mem(struct irdma_chunk *chunk, u32 pg_cnt)
 	if (!chunk->dmainfo.dmaaddrs)
 		return -ENOMEM;
 
-	size = PAGE_SIZE * pg_cnt;
+	size = pg_cnt * IRDMA_HW_PAGE_SIZE;
 	va = vmalloc(size);
 	if (!va)
 		goto err;
-- 
2.56.0.218.g1ec904b173-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ for PAGE_SIZE > 4K
  2026-10-22 21:06 ` [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ " Jacob Moroni
@ 2026-10-22 21:12   ` sashiko-bot
  2026-10-28 19:59   ` Nikolova, Tatyana E
  1 sibling, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-10-22 21:12 UTC (permalink / raw)
  To: Jacob Moroni; +Cc: linux-rdma

> HMC page descriptors and the virtual AEQ PBL always assume 4K
> HW pages, but irdma_map_vm_page_list() returns one DMA address
> per PAGE_SIZE page and irdma_pble_get_paged_mem() sizes the chunk
> as PAGE_SIZE * pg_cnt.
> 
> This breaks when PAGE_SIZE is greater than 4K. For example, with
> a 64K PAGE_SIZE, the second HW page points to vaddr+64K whereas
> the driver assumes it to be at vaddr+4096, etc.
> 
> It also ends up using an incorrect chunk size which causes each
> paged chunk to claim 16x more PBL entries than what actually exist.
> 
> Fix these issues by taking into account the potential difference
> between the HW page size (4K) and the system PAGE_SIZE during
> allocation and mapping (so on a 64K kernel, each page ends up
> populating 16 PDs, etc.).
> 
> Fixes: 44d9e52977a1 ("RDMA/irdma: Implement device initialization definitions")
> Fixes: 915cc7ac0f8e ("RDMA/irdma: Add miscellaneous utility definitions")
> Tested-by: Leah Li <leahlijuan@google.com>
> Signed-off-by: Jacob Moroni <jmoroni@google.com>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261022210650.1182000-1-jmoroni@google.com?part=2


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic for PAGE_SIZE > 4K
  2026-10-22 21:06 ` [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic " Jacob Moroni
@ 2026-10-22 21:13   ` sashiko-bot
  2026-10-28 19:59   ` Nikolova, Tatyana E
  1 sibling, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-10-22 21:13 UTC (permalink / raw)
  To: Jacob Moroni; +Cc: linux-rdma

> The HW only supports 1G, 2M, and 4K page sizes, but some ULPs
> pass PAGE_SIZE to ib_map_mr_sg(), and PAGE_SIZE can be some
> multiple of 4K (64K arm kernels, etc.). The HW can still support
> these scenarios, but we must force it to use 4K pages. The
> max_fast_reg_page_list_len and page_cnt during MR allocation
> must also be scaled to accommodate for the additional PBLEs
> that will be used when ib_sg_to_pages() ends up producing
> more pages than what would have otherwise been required with
> the original page size. It is worth noting that this change
> avoids this over-allocation/cracking in the off chance that
> a 1G or 2M PAGE_SIZE is ever used; it's only applicable when
> PAGE_SIZE is some power of 2 multiple of 4K that is not
> currently supported by HW.
> 
> This was discovered by encountering SMMU faults when running
> kernel NFS/RDMA on a 64K kernel, which was due to the page
> list holding PAGE_SIZE entries while the WQE was indicating
> 4K, so HW was translating every access after the first 4K
> incorrectly.
> 
> Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs")
> Tested-by: Leah Li <leahlijuan@google.com>
> Signed-off-by: Jacob Moroni <jmoroni@google.com>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261022210650.1182000-1-jmoroni@google.com?part=1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic for PAGE_SIZE > 4K
  2026-10-22 21:06 ` [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic " Jacob Moroni
  2026-10-22 21:13   ` sashiko-bot
@ 2026-10-28 19:59   ` Nikolova, Tatyana E
  1 sibling, 0 replies; 7+ messages in thread
From: Nikolova, Tatyana E @ 2026-10-28 19:59 UTC (permalink / raw)
  To: Jacob Moroni, jgg@ziepe.ca, leon@kernel.org
  Cc: linux-rdma@vger.kernel.org, Leah Li



> -----Original Message-----
> From: Jacob Moroni <jmoroni@google.com>
> Sent: Thursday, October 22, 2026 4:07 PM
> To: Nikolova, Tatyana E <tatyana.e.nikolova@intel.com>; jgg@ziepe.ca;
> leon@kernel.org
> Cc: linux-rdma@vger.kernel.org; Jacob Moroni <jmoroni@google.com>; Leah
> Li <leahlijuan@google.com>
> Subject: [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic for PAGE_SIZE >
> 4K
> 
> The HW only supports 1G, 2M, and 4K page sizes, but some ULPs
> pass PAGE_SIZE to ib_map_mr_sg(), and PAGE_SIZE can be some
> multiple of 4K (64K arm kernels, etc.). The HW can still support
> these scenarios, but we must force it to use 4K pages. The
> max_fast_reg_page_list_len and page_cnt during MR allocation
> must also be scaled to accommodate for the additional PBLEs
> that will be used when ib_sg_to_pages() ends up producing
> more pages than what would have otherwise been required with
> the original page size. It is worth noting that this change
> avoids this over-allocation/cracking in the off chance that
> a 1G or 2M PAGE_SIZE is ever used; it's only applicable when
> PAGE_SIZE is some power of 2 multiple of 4K that is not
> currently supported by HW.
> 
> This was discovered by encountering SMMU faults when running
> kernel NFS/RDMA on a 64K kernel, which was due to the page
> list holding PAGE_SIZE entries while the WQE was indicating
> 4K, so HW was translating every access after the first 4K
> incorrectly.
> 
> Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb
> APIs")
> Tested-by: Leah Li <leahlijuan@google.com>
> Signed-off-by: Jacob Moroni <jmoroni@google.com>
> ---
>  drivers/infiniband/hw/irdma/ctrl.c  |  4 +++-
>  drivers/infiniband/hw/irdma/defs.h  |  1 +
>  drivers/infiniband/hw/irdma/verbs.c | 36
> +++++++++++++++++++++++++++--
>  3 files changed, 38 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/irdma/ctrl.c
> b/drivers/infiniband/hw/irdma/ctrl.c
> index 1c2ad5773b9f..ef8627f070ce 100644
> --- a/drivers/infiniband/hw/irdma/ctrl.c
> +++ b/drivers/infiniband/hw/irdma/ctrl.c
> @@ -1703,8 +1703,10 @@ int irdma_sc_mr_fast_register(struct irdma_sc_qp
> *qp,
>  		page_size = IRDMA_PAGE_SIZE_1G;
>  	else if (info->page_size == 0x200000)
>  		page_size = IRDMA_PAGE_SIZE_2M;
> -	else
> +	else if (info->page_size == 0x1000)
>  		page_size = IRDMA_PAGE_SIZE_4K;
> +	else
> +		return -EINVAL;
> 
>  	sq_info.wr_id = info->wr_id;
>  	sq_info.signaled = info->signaled;
> diff --git a/drivers/infiniband/hw/irdma/defs.h
> b/drivers/infiniband/hw/irdma/defs.h
> index d6a3152959dd..eb9179664884 100644
> --- a/drivers/infiniband/hw/irdma/defs.h
> +++ b/drivers/infiniband/hw/irdma/defs.h
> @@ -159,6 +159,7 @@ enum irdma_protocol_used {
> 
>  #define IRDMA_HW_PAGE_SIZE	4096
>  #define IRDMA_HW_PAGE_SHIFT	12
> +#define IRDMA_HW_PAGES_PER_PAGE	(PAGE_SIZE >>
> IRDMA_HW_PAGE_SHIFT)
>  #define IRDMA_CQE_QTYPE_RQ	0
>  #define IRDMA_CQE_QTYPE_SQ	1
> 
> diff --git a/drivers/infiniband/hw/irdma/verbs.c
> b/drivers/infiniband/hw/irdma/verbs.c
> index c91c55917de9..9443e9732c4a 100644
> --- a/drivers/infiniband/hw/irdma/verbs.c
> +++ b/drivers/infiniband/hw/irdma/verbs.c
> @@ -2,6 +2,21 @@
>  /* Copyright (c) 2015 - 2021 Intel Corporation */
>  #include "main.h"
> 
> +/**
> + * irdma_fmr_pages_per_page() - HW pages needed per PAGE_SIZE page in
> an FRWR.
> + * @dev: sc device
> + *
> + * If PAGE_SIZE is one of the HW supported page sizes, then it can be directly
> + * used. Otherwise, we need to break PAGE_SIZE into multiple HW (4K)
> pages.
> + */
> +static u32 irdma_fmr_pages_per_page(struct irdma_sc_dev *dev)
> +{
> +	if (PAGE_SIZE & dev->hw_attrs.page_size_cap)
> +		return 1;
> +
> +	return IRDMA_HW_PAGES_PER_PAGE;
> +}
> +
>  /**
>   * irdma_query_device - get device attributes
>   * @ibdev: device pointer from stack
> @@ -58,7 +73,8 @@ static int irdma_query_device(struct ib_device *ibdev,
>  	props->max_mcast_grp = rf->max_mcg;
>  	props->max_mcast_qp_attach = IRDMA_MAX_MGS_PER_CTX;
>  	props->max_total_mcast_qp_attach = rf->max_qp *
> IRDMA_MAX_MGS_PER_CTX;
> -	props->max_fast_reg_page_list_len = IRDMA_MAX_PAGES_PER_FMR;
> +	props->max_fast_reg_page_list_len =
> +		IRDMA_MAX_PAGES_PER_FMR /
> irdma_fmr_pages_per_page(&rf->sc_dev);
>  	props->max_srq = rf->max_srq - rf->used_srqs;
>  	props->max_srq_wr = IRDMA_MAX_SRQ_WRS;
>  	props->max_srq_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
> @@ -3208,12 +3224,16 @@ static struct ib_mr *irdma_alloc_mr(struct ib_pd
> *pd, enum ib_mr_type mr_type,
>  				    u32 max_num_sg)
>  {
>  	struct irdma_device *iwdev = to_iwdev(pd->device);
> +	u32 pages_per_page = irdma_fmr_pages_per_page(&iwdev->rf-
> >sc_dev);
>  	struct irdma_pble_alloc *palloc;
>  	struct irdma_pbl *iwpbl;
>  	struct irdma_mr *iwmr;
>  	u32 stag;
>  	int err_code;
> 
> +	if (max_num_sg > IRDMA_MAX_PAGES_PER_FMR / pages_per_page)
> +		return ERR_PTR(-EINVAL);
> +
>  	iwmr = kzalloc_obj(*iwmr);
>  	if (!iwmr)
>  		return ERR_PTR(-ENOMEM);
> @@ -3233,7 +3253,12 @@ static struct ib_mr *irdma_alloc_mr(struct ib_pd
> *pd, enum ib_mr_type mr_type,
>  	iwpbl->iwmr = iwmr;
>  	iwmr->type = IRDMA_MEMREG_TYPE_MEM;
>  	palloc = &iwpbl->pble_alloc;
> -	iwmr->page_cnt = max_num_sg;
> +	/* Some ULPs pass PAGE_SIZE to ib_map_mr_sg() but PAGE_SIZE can
> be some
> +	 * multiple of 4K that the HW does not natively support. We can work
> +	 * around this by cracking the larger page into multiple 4K pages, but
> +	 * page_cnt needs to be scaled.
> +	 */
> +	iwmr->page_cnt = max_num_sg * pages_per_page;
>  	/* Use system PAGE_SIZE as the sg page sizes are unknown at this
> point */
>  	iwmr->len = max_num_sg * PAGE_SIZE;
>  	err_code = irdma_get_pble(iwdev->rf->pble_rsrc, palloc, iwmr-
> >page_cnt,
> @@ -3297,8 +3322,15 @@ static int irdma_set_page(struct ib_mr *ibmr, u64
> addr)
>  static int irdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
>  			   int sg_nents, unsigned int *sg_offset)
>  {
> +	struct irdma_device *iwdev = to_iwdev(ibmr->device);
>  	struct irdma_mr *iwmr = to_iwmr(ibmr);
> 
> +	/* HW only supports 4K, 2M and 1G pages, but some ULPs pass
> PAGE_SIZE
> +	 * which can be some multiple of 4K that we do not support, so force
> 4K.
> +	 */
> +	if (!(ibmr->page_size & iwdev->rf->sc_dev.hw_attrs.page_size_cap))
> +		ibmr->page_size = SZ_4K;
> +
>  	iwmr->npages = 0;
> 
>  	return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, irdma_set_page);
> --
> 2.56.0.218.g1ec904b173-goog
> 

Acked-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ for PAGE_SIZE > 4K
  2026-10-22 21:06 ` [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ " Jacob Moroni
  2026-10-22 21:12   ` sashiko-bot
@ 2026-10-28 19:59   ` Nikolova, Tatyana E
  1 sibling, 0 replies; 7+ messages in thread
From: Nikolova, Tatyana E @ 2026-10-28 19:59 UTC (permalink / raw)
  To: Jacob Moroni, jgg@ziepe.ca, leon@kernel.org
  Cc: linux-rdma@vger.kernel.org, Leah Li



> -----Original Message-----
> From: Jacob Moroni <jmoroni@google.com>
> Sent: Thursday, October 22, 2026 4:07 PM
> To: Nikolova, Tatyana E <tatyana.e.nikolova@intel.com>; jgg@ziepe.ca;
> leon@kernel.org
> Cc: linux-rdma@vger.kernel.org; Jacob Moroni <jmoroni@google.com>; Leah
> Li <leahlijuan@google.com>
> Subject: [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ
> for PAGE_SIZE > 4K
> 
> HMC page descriptors and the virtual AEQ PBL always assume 4K
> HW pages, but irdma_map_vm_page_list() returns one DMA address
> per PAGE_SIZE page and irdma_pble_get_paged_mem() sizes the chunk
> as PAGE_SIZE * pg_cnt.
> 
> This breaks when PAGE_SIZE is greater than 4K. For example, with
> a 64K PAGE_SIZE, the second HW page points to vaddr+64K whereas
> the driver assumes it to be at vaddr+4096, etc.
> 
> It also ends up using an incorrect chunk size which causes each
> paged chunk to claim 16x more PBL entries than what actually exist.
> 
> Fix these issues by taking into account the potential difference
> between the HW page size (4K) and the system PAGE_SIZE during
> allocation and mapping (so on a 64K kernel, each page ends up
> populating 16 PDs, etc.).
> 
> Fixes: 44d9e52977a1 ("RDMA/irdma: Implement device initialization
> definitions")
> Fixes: 915cc7ac0f8e ("RDMA/irdma: Add miscellaneous utility definitions")
> Tested-by: Leah Li <leahlijuan@google.com>
> Signed-off-by: Jacob Moroni <jmoroni@google.com>
> ---
>  drivers/infiniband/hw/irdma/hw.c    |  4 ++--
>  drivers/infiniband/hw/irdma/utils.c | 22 +++++++++++++---------
>  2 files changed, 15 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/irdma/hw.c
> b/drivers/infiniband/hw/irdma/hw.c
> index fbb8fb47d0d1..1d57b3c9f490 100644
> --- a/drivers/infiniband/hw/irdma/hw.c
> +++ b/drivers/infiniband/hw/irdma/hw.c
> @@ -700,7 +700,7 @@ static void irdma_destroy_cqp(struct irdma_pci_f *rf)
>  static void irdma_destroy_virt_aeq(struct irdma_pci_f *rf)
>  {
>  	struct irdma_aeq *aeq = &rf->aeq;
> -	u32 pg_cnt = DIV_ROUND_UP(aeq->mem.size, PAGE_SIZE);
> +	u32 pg_cnt = DIV_ROUND_UP(aeq->mem.size,
> IRDMA_HW_PAGE_SIZE);
>  	dma_addr_t *pg_arr = (dma_addr_t *)aeq->palloc.level1.addr;
> 
>  	irdma_unmap_vm_page_list(&rf->hw, pg_arr, pg_cnt);
> @@ -1479,7 +1479,7 @@ static int irdma_create_virt_aeq(struct irdma_pci_f
> *rf, u32 size)
>  	if (!aeq->mem.va)
>  		return -ENOMEM;
> 
> -	pg_cnt = DIV_ROUND_UP(aeq->mem.size, PAGE_SIZE);
> +	pg_cnt = DIV_ROUND_UP(aeq->mem.size, IRDMA_HW_PAGE_SIZE);
>  	status = irdma_get_pble(rf->pble_rsrc, &aeq->palloc, pg_cnt, true);
>  	if (status) {
>  		vfree(aeq->mem.va);
> diff --git a/drivers/infiniband/hw/irdma/utils.c
> b/drivers/infiniband/hw/irdma/utils.c
> index 290ad02ed657..3efc4125bb59 100644
> --- a/drivers/infiniband/hw/irdma/utils.c
> +++ b/drivers/infiniband/hw/irdma/utils.c
> @@ -2199,20 +2199,24 @@ int irdma_map_vm_page_list(struct irdma_hw
> *hw, void *va, dma_addr_t *pg_dma,
>  			   u32 pg_cnt)
>  {
>  	struct page *vm_page;
> -	int i;
> +	dma_addr_t dma;
> +	u32 i, j;
>  	u8 *addr;
> 
>  	addr = (u8 *)(uintptr_t)va;
> -	for (i = 0; i < pg_cnt; i++) {
> +	for (i = 0; i < pg_cnt; i += IRDMA_HW_PAGES_PER_PAGE) {
>  		vm_page = vmalloc_to_page(addr);
>  		if (!vm_page)
>  			goto err;
> 
> -		pg_dma[i] = dma_map_page(hw->device, vm_page, 0,
> PAGE_SIZE,
> -					 DMA_BIDIRECTIONAL);
> -		if (dma_mapping_error(hw->device, pg_dma[i]))
> +		dma = dma_map_page(hw->device, vm_page, 0, PAGE_SIZE,
> +				   DMA_BIDIRECTIONAL);
> +		if (dma_mapping_error(hw->device, dma))
>  			goto err;
> 
> +		for (j = 0; j < IRDMA_HW_PAGES_PER_PAGE && i + j < pg_cnt;
> j++)
> +			pg_dma[i + j] = dma + j * IRDMA_HW_PAGE_SIZE;
> +
>  		addr += PAGE_SIZE;
>  	}
> 
> @@ -2225,9 +2229,9 @@ int irdma_map_vm_page_list(struct irdma_hw
> *hw, void *va, dma_addr_t *pg_dma,
> 
>  void irdma_unmap_vm_page_list(struct irdma_hw *hw, dma_addr_t
> *pg_dma, u32 pg_cnt)
>  {
> -	int i;
> +	u32 i;
> 
> -	for (i = 0; i < pg_cnt; i++)
> +	for (i = 0; i < pg_cnt; i += IRDMA_HW_PAGES_PER_PAGE)
>  		dma_unmap_page(hw->device, pg_dma[i], PAGE_SIZE,
> DMA_BIDIRECTIONAL);
>  }
> 
> @@ -2254,7 +2258,7 @@ void irdma_pble_free_paged_mem(struct
> irdma_chunk *chunk)
>  /**
>   * irdma_pble_get_paged_mem -allocate paged memory for pbles
>   * @chunk: chunk to add for paged memory
> - * @pg_cnt: number of pages needed
> + * @pg_cnt: number of HW (4K) pages needed
>   */
>  int irdma_pble_get_paged_mem(struct irdma_chunk *chunk, u32 pg_cnt)
>  {
> @@ -2265,7 +2269,7 @@ int irdma_pble_get_paged_mem(struct
> irdma_chunk *chunk, u32 pg_cnt)
>  	if (!chunk->dmainfo.dmaaddrs)
>  		return -ENOMEM;
> 
> -	size = PAGE_SIZE * pg_cnt;
> +	size = pg_cnt * IRDMA_HW_PAGE_SIZE;
>  	va = vmalloc(size);
>  	if (!va)
>  		goto err;
> --
> 2.56.0.218.g1ec904b173-goog

Acked-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-10-28 20:00 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22 21:06 [PATCH rdma-next 0/2] RDMA/irdma: Fix FRWR and PBLE handling for PAGE_SIZE > 4K Jacob Moroni
2026-10-22 21:06 ` [PATCH rdma-next 1/2] RDMA/irdma: Fix FRWR logic " Jacob Moroni
2026-10-22 21:13   ` sashiko-bot
2026-10-28 19:59   ` Nikolova, Tatyana E
2026-10-22 21:06 ` [PATCH rdma-next 2/2] RDMA/irdma: Fix paged PBLE and virtual AEQ " Jacob Moroni
2026-10-22 21:12   ` sashiko-bot
2026-10-28 19:59   ` Nikolova, Tatyana E

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox