diff mbox series

[RFC,2/9] bvec: Add bio_vec fields to manage DMA mapping

Message ID 169772914548.5232.12015170784207638561.stgit@klimt.1015granger.net (mailing list archive)
State Not Applicable
Headers show
Series Exploring biovec support in (R)DMA API | expand

Commit Message

Chuck Lever Oct. 19, 2023, 3:25 p.m. UTC
From: Chuck Lever <chuck.lever@oracle.com>

These are roughly equivalent to the fields used for managing
scatterlist DMA mapping.

Cc: Jens Axboe <axboe@kernel.dk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Howells <dhowells@redhat.com>
Cc: iommu@lists.linux.dev
Cc: linux-rdma@vger.kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 include/linux/bvec.h |  143 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)
diff mbox series

Patch

diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index 555aae5448ae..1074f34a4e8f 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -13,6 +13,7 @@ 
 #include <linux/limits.h>
 #include <linux/minmax.h>
 #include <linux/types.h>
+#include <asm/io.h>
 
 struct page;
 
@@ -32,6 +33,13 @@  struct bio_vec {
 	struct page	*bv_page;
 	unsigned int	bv_len;
 	unsigned int	bv_offset;
+	dma_addr_t	bv_dma_address;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+	unsigned int	bv_dma_length;
+#endif
+#ifdef CONFIG_NEED_SG_DMA_FLAGS
+	unsigned int	bv_dma_flags;
+#endif
 };
 
 /**
@@ -74,6 +82,24 @@  static inline void bvec_set_virt(struct bio_vec *bv, void *vaddr,
 	bvec_set_page(bv, virt_to_page(vaddr), len, offset_in_page(vaddr));
 }
 
+/**
+ * bv_phys - return physical address of a bio_vec
+ * @bv:		bio_vec
+ */
+static inline dma_addr_t bv_phys(struct bio_vec *bv)
+{
+	return page_to_phys(bv->bv_page) + bv->bv_offset;
+}
+
+/**
+ * bv_virt - return virtual address of a bio_vec
+ * @bv:		bio_vec
+ */
+static inline void *bv_virt(struct bio_vec *bv)
+{
+	return page_address(bv->bv_page) + bv->bv_offset;
+}
+
 struct bvec_iter {
 	sector_t		bi_sector;	/* device address in 512 byte
 						   sectors */
@@ -280,4 +306,121 @@  static inline void *bvec_virt(struct bio_vec *bvec)
 	return page_address(bvec->bv_page) + bvec->bv_offset;
 }
 
+/*
+ * These macros should be used after a dma_map_bvecs call has been done
+ * to get bus addresses of each of the bio_vec array entries and their
+ * lengths. You should work only with the number of bio_vec array entries
+ * dma_map_bvecs returns, or alternatively stop on the first bv_dma_len(bv)
+ * which is 0.
+ */
+#define bv_dma_address(bv)	((bv)->bv_dma_address)
+
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+#define bv_dma_len(bv)		((bv)->bv_dma_length)
+#else
+#define bv_dma_len(bv)		((bv)->bv_len)
+#endif
+
+/*
+ * On 64-bit architectures there is a 4-byte padding in struct scatterlist
+ * (assuming also CONFIG_NEED_SG_DMA_LENGTH is set). Use this padding for DMA
+ * flags bits to indicate when a specific dma address is a bus address or the
+ * buffer may have been bounced via SWIOTLB.
+ */
+#ifdef CONFIG_NEED_SG_DMA_FLAGS
+
+#define BV_DMA_BUS_ADDRESS	BIT(0)
+#define BV_DMA_SWIOTLB		BIT(1)
+
+/**
+ * bv_dma_is_bus_address - Return whether a given segment was marked
+ *			   as a bus address
+ * @bv:		 bio_vec array entry
+ *
+ * Description:
+ *   Returns true if bv_dma_mark_bus_address() has been called on
+ *   this bio_vec.
+ **/
+static inline bool bv_dma_is_bus_address(struct bio_vec *bv)
+{
+	return bv->bv_dma_flags & BV_DMA_BUS_ADDRESS;
+}
+
+/**
+ * bv_dma_mark_bus_address - Mark the bio_vec entry as a bus address
+ * @bv:		 bio_vec array entry
+ *
+ * Description:
+ *   Marks the passed-in bv entry to indicate that the dma_address is
+ *   a bus address and doesn't need to be unmapped. This should only be
+ *   used by dma_map_bvecs() implementations to mark bus addresses
+ *   so they can be properly cleaned up in dma_unmap_bvecs().
+ **/
+static inline void bv_dma_mark_bus_address(struct bio_vec *bv)
+{
+	bv->bv_dma_flags |= BV_DMA_BUS_ADDRESS;
+}
+
+/**
+ * bv_unmark_bus_address - Unmark the bio_vec entry as a bus address
+ * @bv:		 bio_vec array entry
+ *
+ * Description:
+ *   Clears the bus address mark.
+ **/
+static inline void bv_dma_unmark_bus_address(struct bio_vec *bv)
+{
+	bv->bv_dma_flags &= ~BV_DMA_BUS_ADDRESS;
+}
+
+/**
+ * bv_dma_is_swiotlb - Return whether the bio_vec was marked for SWIOTLB
+ *		       bouncing
+ * @bv:		bio_vec array entry
+ *
+ * Description:
+ *   Returns true if the bio_vec was marked for SWIOTLB bouncing. Not all
+ *   elements may have been bounced, so the caller would have to check
+ *   individual BV entries with is_swiotlb_buffer().
+ */
+static inline bool bv_dma_is_swiotlb(struct bio_vec *bv)
+{
+	return bv->bv_dma_flags & BV_DMA_SWIOTLB;
+}
+
+/**
+ * bv_dma_mark_swiotlb - Mark the bio_vec for SWIOTLB bouncing
+ * @bv:		bio_vec array entry
+ *
+ * Description:
+ *   Marks a a bio_vec for SWIOTLB bounce. Not all bio_vec entries may
+ *   be bounced.
+ */
+static inline void bv_dma_mark_swiotlb(struct bio_vec *bv)
+{
+	bv->bv_dma_flags |= BV_DMA_SWIOTLB;
+}
+
+#else
+
+static inline bool bv_dma_is_bus_address(struct bio_vec *bv)
+{
+	return false;
+}
+static inline void bv_dma_mark_bus_address(struct bio_vec *bv)
+{
+}
+static inline void bv_dma_unmark_bus_address(struct bio_vec *bv)
+{
+}
+static inline bool bv_dma_is_swiotlb(struct bio_vec *bv)
+{
+	return false;
+}
+static inline void bv_dma_mark_swiotlb(struct bio_vec *bv)
+{
+}
+
+#endif	/* CONFIG_NEED_SG_DMA_FLAGS */
+
 #endif /* __LINUX_BVEC_H */