diff mbox series

[for-next,06/17] RDMA/rxe: Add routine to compute the number of frags

Message ID 20221027185510.33808-7-rpearsonhpe@gmail.com (mailing list archive)
State Superseded
Headers show
Series RDMA/rxe: Enable scatter/gather support for skbs | expand

Commit Message

Bob Pearson Oct. 27, 2022, 6:55 p.m. UTC
Add a subroutine named rxe_num_mr_frags() to compute the
number of skb frags needed to hold length bytes in an skb
when sending data from an mr starting at iova.

Signed-off-by: Bob Pearson <rpearsonhpe@gmail.com>
---
 drivers/infiniband/sw/rxe/rxe_loc.h |  1 +
 drivers/infiniband/sw/rxe/rxe_mr.c  | 68 +++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)
diff mbox series

Patch

diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
index 81a611778d44..87fb052c1d0a 100644
--- a/drivers/infiniband/sw/rxe/rxe_loc.h
+++ b/drivers/infiniband/sw/rxe/rxe_loc.h
@@ -70,6 +70,7 @@  int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova,
 int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr);
 int rxe_add_frag(struct sk_buff *skb, struct rxe_phys_buf *buf,
 		 int length, int offset);
+int rxe_num_mr_frags(struct rxe_mr *mr, u64 iova, int length);
 int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
 		enum rxe_mr_copy_op op);
 int copy_data(struct rxe_pd *pd, int access, struct rxe_dma_info *dma,
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index cf39412cac54..dd4dbe117c91 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -320,6 +320,74 @@  int rxe_add_frag(struct sk_buff *skb, struct rxe_phys_buf *buf,
 	return 0;
 }
 
+/**
+ * rxe_num_mr_frags() - Compute the number of skb frags needed to copy
+ *			length bytes from an mr to an skb frag list.
+ * @mr: mr to copy data from
+ * @iova: iova in memory region as starting point
+ * @length: number of bytes to transfer
+ *
+ * Returns: the number of frags needed or a negative error
+ */
+int rxe_num_mr_frags(struct rxe_mr *mr, u64 iova, int length)
+{
+	struct rxe_phys_buf *buf;
+	struct rxe_map **map;
+	size_t buf_offset;
+	int bytes;
+	int m;
+	int i;
+	int num_frags = 0;
+	int err;
+
+	if (length == 0)
+		return 0;
+
+	if (mr->type == IB_MR_TYPE_DMA) {
+		while (length > 0) {
+			buf_offset = iova & ~PAGE_MASK;
+			bytes = PAGE_SIZE - buf_offset;
+			if (bytes > length)
+				bytes = length;
+			length -= bytes;
+			num_frags++;
+		}
+
+		return num_frags;
+	}
+
+	WARN_ON_ONCE(!mr->map);
+
+	err = mr_check_range(mr, iova, length);
+	if (err)
+		return err;
+
+	lookup_iova(mr, iova, &m, &i, &buf_offset);
+
+	map = mr->map + m;
+	buf = map[0]->buf + i;
+
+	while (length > 0) {
+		bytes = buf->size - buf_offset;
+		if (bytes > length)
+			bytes = length;
+		length -= bytes;
+		buf_offset = 0;
+		buf++;
+		i++;
+		num_frags++;
+
+		/* we won't overrun since we checked range above */
+		if (i == RXE_BUF_PER_MAP) {
+			i = 0;
+			map++;
+			buf = map[0]->buf;
+		}
+	}
+
+	return num_frags;
+}
+
 /* copy data from a range (vaddr, vaddr+length-1) to or from
  * a mr object starting at iova.
  */