xref: /linux/include/rdma/iter.h (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*6094ea64SLeon Romanovsky /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2*6094ea64SLeon Romanovsky /* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */
3*6094ea64SLeon Romanovsky 
4*6094ea64SLeon Romanovsky #ifndef _RDMA_ITER_H_
5*6094ea64SLeon Romanovsky #define _RDMA_ITER_H_
6*6094ea64SLeon Romanovsky 
7*6094ea64SLeon Romanovsky #include <linux/scatterlist.h>
8*6094ea64SLeon Romanovsky #include <rdma/ib_umem.h>
9*6094ea64SLeon Romanovsky 
10*6094ea64SLeon Romanovsky /**
11*6094ea64SLeon Romanovsky  * IB block DMA iterator
12*6094ea64SLeon Romanovsky  *
13*6094ea64SLeon Romanovsky  * Iterates the DMA-mapped SGL in contiguous memory blocks aligned
14*6094ea64SLeon Romanovsky  * to a HW supported page size.
15*6094ea64SLeon Romanovsky  */
16*6094ea64SLeon Romanovsky struct ib_block_iter {
17*6094ea64SLeon Romanovsky 	/* internal states */
18*6094ea64SLeon Romanovsky 	struct scatterlist *__sg;	/* sg holding the current aligned block */
19*6094ea64SLeon Romanovsky 	dma_addr_t __dma_addr;		/* unaligned DMA address of this block */
20*6094ea64SLeon Romanovsky 	size_t __sg_numblocks;		/* ib_umem_num_dma_blocks() */
21*6094ea64SLeon Romanovsky 	unsigned int __sg_nents;	/* number of SG entries */
22*6094ea64SLeon Romanovsky 	unsigned int __sg_advance;	/* number of bytes to advance in sg in next step */
23*6094ea64SLeon Romanovsky 	unsigned int __pg_bit;		/* alignment of current block */
24*6094ea64SLeon Romanovsky };
25*6094ea64SLeon Romanovsky 
26*6094ea64SLeon Romanovsky void __rdma_block_iter_start(struct ib_block_iter *biter,
27*6094ea64SLeon Romanovsky 			     struct scatterlist *sglist,
28*6094ea64SLeon Romanovsky 			     unsigned int nents,
29*6094ea64SLeon Romanovsky 			     unsigned long pgsz);
30*6094ea64SLeon Romanovsky bool __rdma_block_iter_next(struct ib_block_iter *biter);
31*6094ea64SLeon Romanovsky 
32*6094ea64SLeon Romanovsky /**
33*6094ea64SLeon Romanovsky  * rdma_block_iter_dma_address - get the aligned dma address of the current
34*6094ea64SLeon Romanovsky  * block held by the block iterator.
35*6094ea64SLeon Romanovsky  * @biter: block iterator holding the memory block
36*6094ea64SLeon Romanovsky  */
37*6094ea64SLeon Romanovsky static inline dma_addr_t
38*6094ea64SLeon Romanovsky rdma_block_iter_dma_address(struct ib_block_iter *biter)
39*6094ea64SLeon Romanovsky {
40*6094ea64SLeon Romanovsky 	return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1);
41*6094ea64SLeon Romanovsky }
42*6094ea64SLeon Romanovsky 
43*6094ea64SLeon Romanovsky /**
44*6094ea64SLeon Romanovsky  * rdma_for_each_block - iterate over contiguous memory blocks of the sg list
45*6094ea64SLeon Romanovsky  * @sglist: sglist to iterate over
46*6094ea64SLeon Romanovsky  * @biter: block iterator holding the memory block
47*6094ea64SLeon Romanovsky  * @nents: maximum number of sg entries to iterate over
48*6094ea64SLeon Romanovsky  * @pgsz: best HW supported page size to use
49*6094ea64SLeon Romanovsky  *
50*6094ea64SLeon Romanovsky  * Callers may use rdma_block_iter_dma_address() to get each
51*6094ea64SLeon Romanovsky  * blocks aligned DMA address.
52*6094ea64SLeon Romanovsky  */
53*6094ea64SLeon Romanovsky #define rdma_for_each_block(sglist, biter, nents, pgsz)		\
54*6094ea64SLeon Romanovsky 	for (__rdma_block_iter_start(biter, sglist, nents,	\
55*6094ea64SLeon Romanovsky 				     pgsz);			\
56*6094ea64SLeon Romanovsky 	     __rdma_block_iter_next(biter);)
57*6094ea64SLeon Romanovsky 
58*6094ea64SLeon Romanovsky static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter,
59*6094ea64SLeon Romanovsky 						struct ib_umem *umem,
60*6094ea64SLeon Romanovsky 						unsigned long pgsz)
61*6094ea64SLeon Romanovsky {
62*6094ea64SLeon Romanovsky 	__rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl,
63*6094ea64SLeon Romanovsky 				umem->sgt_append.sgt.nents, pgsz);
64*6094ea64SLeon Romanovsky 	biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1);
65*6094ea64SLeon Romanovsky 	biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz);
66*6094ea64SLeon Romanovsky }
67*6094ea64SLeon Romanovsky 
68*6094ea64SLeon Romanovsky static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter)
69*6094ea64SLeon Romanovsky {
70*6094ea64SLeon Romanovsky 	return __rdma_block_iter_next(biter) && biter->__sg_numblocks--;
71*6094ea64SLeon Romanovsky }
72*6094ea64SLeon Romanovsky 
73*6094ea64SLeon Romanovsky /**
74*6094ea64SLeon Romanovsky  * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem
75*6094ea64SLeon Romanovsky  * @umem: umem to iterate over
76*6094ea64SLeon Romanovsky  * @pgsz: Page size to split the list into
77*6094ea64SLeon Romanovsky  *
78*6094ea64SLeon Romanovsky  * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The
79*6094ea64SLeon Romanovsky  * returned DMA blocks will be aligned to pgsz and span the range:
80*6094ea64SLeon Romanovsky  * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz)
81*6094ea64SLeon Romanovsky  *
82*6094ea64SLeon Romanovsky  * Performs exactly ib_umem_num_dma_blocks() iterations.
83*6094ea64SLeon Romanovsky  */
84*6094ea64SLeon Romanovsky #define rdma_umem_for_each_dma_block(umem, biter, pgsz)                        \
85*6094ea64SLeon Romanovsky 	for (__rdma_umem_block_iter_start(biter, umem, pgsz);                  \
86*6094ea64SLeon Romanovsky 	     __rdma_umem_block_iter_next(biter);)
87*6094ea64SLeon Romanovsky 
88*6094ea64SLeon Romanovsky #endif /* _RDMA_ITER_H_ */
89