/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */


#ifndef _RDMA_ITER_H_
#define _RDMA_ITER_H_

#include <linux/scatterlist.h>
#include <rdma/ib_umem.h>


struct ib_block_iter {
	
	struct scatterlist *__sg;	
	dma_addr_t __dma_addr;		
	size_t __sg_numblocks;		
	unsigned int __sg_nents;	
	unsigned int __sg_advance;	
	unsigned int __pg_bit;		
};

void __rdma_block_iter_start(struct ib_block_iter *biter,
			     struct scatterlist *sglist,
			     unsigned int nents,
			     unsigned long pgsz);
bool __rdma_block_iter_next(struct ib_block_iter *biter);


static inline dma_addr_t
rdma_block_iter_dma_address(struct ib_block_iter *biter)
{
	return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1);
}


#define rdma_for_each_block(sglist, biter, nents, pgsz)		\
	for (__rdma_block_iter_start(biter, sglist, nents,	\
				     pgsz);			\
	     __rdma_block_iter_next(biter);)

static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter,
						struct ib_umem *umem,
						unsigned long pgsz)
{
	__rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl,
				umem->sgt_append.sgt.nents, pgsz);
	biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1);
	biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz);
}

static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter)
{
	return __rdma_block_iter_next(biter) && biter->__sg_numblocks--;
}


#define rdma_umem_for_each_dma_block(umem, biter, pgsz)                        \
	for (__rdma_umem_block_iter_start(biter, umem, pgsz);                  \
	     __rdma_umem_block_iter_next(biter);)

#endif 
