RDMA/verbs: Add a DMA iterator to return aligned contiguous memory blocks
authorShiraz Saleem <shiraz.saleem@intel.com>
Mon, 6 May 2019 13:53:33 +0000 (08:53 -0500)
committerJason Gunthorpe <jgg@mellanox.com>
Mon, 6 May 2019 16:08:11 +0000 (13:08 -0300)
This helper iterates over a DMA-mapped SGL and returns contiguous memory
blocks aligned to a HW supported page size.

Suggested-by: Jason Gunthorpe <jgg@ziepe.ca>
Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/verbs.c
include/rdma/ib_verbs.h

index d607c31..a4e97dd 100644 (file)
@@ -2710,3 +2710,37 @@ int rdma_init_netdev(struct ib_device *device, u8 port_num,
                                             netdev, params.param);
 }
 EXPORT_SYMBOL(rdma_init_netdev);
+
+void __rdma_block_iter_start(struct ib_block_iter *biter,
+                            struct scatterlist *sglist, unsigned int nents,
+                            unsigned long pgsz)
+{
+       memset(biter, 0, sizeof(struct ib_block_iter));
+       biter->__sg = sglist;
+       biter->__sg_nents = nents;
+
+       /* Driver provides best block size to use */
+       biter->__pg_bit = __fls(pgsz);
+}
+EXPORT_SYMBOL(__rdma_block_iter_start);
+
+bool __rdma_block_iter_next(struct ib_block_iter *biter)
+{
+       unsigned int block_offset;
+
+       if (!biter->__sg_nents || !biter->__sg)
+               return false;
+
+       biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
+       block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
+       biter->__sg_advance += BIT_ULL(biter->__pg_bit) - block_offset;
+
+       if (biter->__sg_advance >= sg_dma_len(biter->__sg)) {
+               biter->__sg_advance = 0;
+               biter->__sg = sg_next(biter->__sg);
+               biter->__sg_nents--;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL(__rdma_block_iter_next);
index 03b07ec..deb67b2 100644 (file)
@@ -2726,6 +2726,21 @@ struct ib_client {
        u8 no_kverbs_req:1;
 };
 
+/*
+ * IB block DMA iterator
+ *
+ * Iterates the DMA-mapped SGL in contiguous memory blocks aligned
+ * to a HW supported page size.
+ */
+struct ib_block_iter {
+       /* internal states */
+       struct scatterlist *__sg;       /* sg holding the current aligned block */
+       dma_addr_t __dma_addr;          /* unaligned DMA address of this block */
+       unsigned int __sg_nents;        /* number of SG entries */
+       unsigned int __sg_advance;      /* number of bytes to advance in sg in next step */
+       unsigned int __pg_bit;          /* alignment of current block */
+};
+
 struct ib_device *_ib_alloc_device(size_t size);
 #define ib_alloc_device(drv_struct, member)                                    \
        container_of(_ib_alloc_device(sizeof(struct drv_struct) +              \
@@ -2746,6 +2761,38 @@ void ib_unregister_device_queued(struct ib_device *ib_dev);
 int ib_register_client   (struct ib_client *client);
 void ib_unregister_client(struct ib_client *client);
 
+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);
+
+/**
+ * rdma_block_iter_dma_address - get the aligned dma address of the current
+ * block held by the block iterator.
+ * @biter: block iterator holding the memory block
+ */
+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);
+}
+
+/**
+ * rdma_for_each_block - iterate over contiguous memory blocks of the sg list
+ * @sglist: sglist to iterate over
+ * @biter: block iterator holding the memory block
+ * @nents: maximum number of sg entries to iterate over
+ * @pgsz: best HW supported page size to use
+ *
+ * Callers may use rdma_block_iter_dma_address() to get each
+ * blocks aligned DMA address.
+ */
+#define rdma_for_each_block(sglist, biter, nents, pgsz)                \
+       for (__rdma_block_iter_start(biter, sglist, nents,      \
+                                    pgsz);                     \
+            __rdma_block_iter_next(biter);)
+
 /**
  * ib_get_client_data - Get IB client context
  * @device:Device to get context for