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