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