diff mbox series

[RFC,7/9] DMA: Add dma_map_bvecs_attrs()

Message ID 169772917833.5232.13488378553385610086.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:26 p.m. UTC
From: Chuck Lever <chuck.lever@oracle.com>

Cc: iommu@lists.linux.dev
Cc: linux-rdma@vger.kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 include/linux/dma-map-ops.h |    4 +++
 include/linux/dma-mapping.h |    4 +++
 kernel/dma/mapping.c        |   65 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+)
diff mbox series

Patch

diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index de2a50d9207a..69ecfd403249 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -60,6 +60,10 @@  struct dma_map_ops {
 			enum dma_data_direction dir, unsigned long attrs);
 	void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nents,
 			enum dma_data_direction dir, unsigned long attrs);
+	int (*map_bvecs)(struct device *dev, struct bio_vec *bvecs, int nents,
+			enum dma_data_direction dir, unsigned long attrs);
+	void (*unmap_bvecs)(struct device *dev, struct bio_vec *bvecs, int nents,
+			enum dma_data_direction dir, unsigned long attrs);
 	dma_addr_t (*map_resource)(struct device *dev, phys_addr_t phys_addr,
 			size_t size, enum dma_data_direction dir,
 			unsigned long attrs);
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 9fb422f376b6..6f522a82cfe3 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -114,6 +114,10 @@  void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
 				      unsigned long attrs);
 int dma_map_sgtable(struct device *dev, struct sg_table *sgt,
 		enum dma_data_direction dir, unsigned long attrs);
+unsigned int dma_map_bvecs_attrs(struct device *dev, struct bio_vec *bvecs,
+		int nents, enum dma_data_direction dir, unsigned long attrs);
+void dma_unmap_bvecs_attrs(struct device *dev, struct bio_vec *bvecs,
+		int nents, enum dma_data_direction dir, unsigned long attrs);
 dma_addr_t dma_map_resource(struct device *dev, phys_addr_t phys_addr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs);
 void dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index 94cffc9b45a5..f53cc4da2797 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -296,6 +296,71 @@  void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
 }
 EXPORT_SYMBOL(dma_unmap_sg_attrs);
 
+/**
+ * dma_map_sg_attrs - Map the given buffer for DMA
+ * @dev:	The device for which to perform the DMA operation
+ * @bvecs:	The bio_vec array describing the buffer
+ * @nents:	Number of bio_vecs to map
+ * @dir:	DMA direction
+ * @attrs:	Optional DMA attributes for the map operation
+ *
+ * Maps a buffer described by a bio_vec array passed in the bvecs
+ * argument with nents segments for the @dir DMA operation by the
+ * @dev device.
+ *
+ * Returns the number of mapped entries (which can be less than nents)
+ * on success. Zero is returned for any error.
+ *
+ * dma_unmap_bvecs_attrs() should be used to unmap the buffer with the
+ * original bvecs and original nents (not the value returned by this
+ * function).
+ */
+unsigned int dma_map_bvecs_attrs(struct device *dev, struct bio_vec *bvecs,
+				 int nents, enum dma_data_direction dir,
+				 unsigned long attrs)
+{
+	const struct dma_map_ops *ops = get_dma_ops(dev);
+	int ents;
+
+	BUG_ON(!valid_dma_direction(dir));
+
+	if (WARN_ON_ONCE(!dev->dma_mask))
+		return 0;
+
+	if (dma_map_direct(dev, ops))
+		ents = dma_direct_map_bvecs(dev, bvecs, nents, dir, attrs);
+	else
+		ents = ops->map_bvecs(dev, bvecs, nents, dir, attrs);
+
+	if (ents > 0) {
+		kmsan_handle_dma_bvecs(bvecs, nents, dir);
+		debug_dma_map_bvecs(dev, bvecs, nents, ents, dir, attrs);
+	} else if (WARN_ON_ONCE(ents != -EINVAL && ents != -ENOMEM &&
+				ents != -EIO && ents != -EREMOTEIO)) {
+		return -EIO;
+	}
+
+	return ents;
+}
+EXPORT_SYMBOL_GPL(dma_map_bvecs_attrs);
+
+void dma_unmap_bvecs_attrs(struct device *dev, struct bio_vec *bvecs,
+			   int nents, enum dma_data_direction dir,
+			   unsigned long attrs)
+{
+	const struct dma_map_ops *ops = get_dma_ops(dev);
+
+	BUG_ON(!valid_dma_direction(dir));
+
+	debug_dma_unmap_bvecs(dev, bvecs, nents, dir);
+
+	if (dma_map_direct(dev, ops))
+		dma_direct_unmap_bvecs(dev, bvecs, nents, dir, attrs);
+	else if (ops->unmap_bvecs)
+		ops->unmap_bvecs(dev, bvecs, nents, dir, attrs);
+}
+EXPORT_SYMBOL(dma_unmap_bvecs_attrs);
+
 dma_addr_t dma_map_resource(struct device *dev, phys_addr_t phys_addr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {