[PATCH v2 08/23] dma-buf: Add dma_buf_mapping_map() returning a type-tagged mapping

Alistair Popple apopple at nvidia.com
Wed Nov 4 22:40:43 PST 2026


An importer that lists more than one mapping type cannot know which
type-specific map function to call, because the exporter selects the
type at map time. Create a generic entry point to determine the correct
type.

dma_buf_mapping_map() selects via dma_buf_mapping_select() and dispatches
to a map op on struct dma_buf_mapping_type. That returns a struct
dma_buf_mapping carrying the type, embedded in the type's own
result struct. dma_buf_mapping_unmap() hands it back through the type's
unmap op.

To support existing SGT importers the SGT type implements both. Its
result is struct dma_buf_sgt_mapping with the sg_table reachable through
dma_buf_sgt_mapping_table(). The sgt map body is shared with the SGT
type's map function which remains the entry point for importers listing
only SGT.

Signed-off-by: Alistair Popple <apopple at nvidia.com>
---
 drivers/dma-buf/dma-buf-mapping.c | 78 +++++++++++++++++++++++++++++++++++++++
 drivers/dma-buf/dma-buf.c         | 33 +++++++++++++++++
 include/linux/dma-buf-mapping.h   | 63 +++++++++++++++++++++++++++++++
 3 files changed, 174 insertions(+)

diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-mapping.c
index ff2dbcca23d9..264c9293438f 100644
--- a/drivers/dma-buf/dma-buf-mapping.c
+++ b/drivers/dma-buf/dma-buf-mapping.c
@@ -388,6 +388,82 @@ void dma_buf_mapping_unselect(struct dma_buf_attachment *attach,
 	attach->selected_idx = 0;
 }
 
+/**
+ * dma_buf_mapping_map - Map an attachment with whichever type the exporter
+ *                       selects
+ * @attach: the attachment
+ * @dir: DMA direction
+ *
+ * For importers that listed more than one mapping type. The exporter picks the
+ * type from the possible matches and the result's &dma_buf_mapping.type records
+ * which was used. Must be called with the dma_resv lock held, and the lock must
+ * be held until the result has been acted on. Importers that listed a single
+ * type keep using that type's map function.
+ *
+ * Returns: a &struct dma_buf_mapping to pass to dma_buf_mapping_unmap(), or
+ * an ERR_PTR.
+ */
+struct dma_buf_mapping *dma_buf_mapping_map(struct dma_buf_attachment *attach,
+					    enum dma_data_direction dir)
+{
+	const struct dma_buf_mapping_type *type;
+	struct dma_buf_mapping *mapping;
+	bool selected;
+	int ret;
+
+	might_sleep();
+
+	if (WARN_ON(!attach || !attach->dmabuf))
+		return ERR_PTR(-EINVAL);
+
+	dma_resv_assert_held(attach->dmabuf->resv);
+
+	selected = attach->selected;
+	ret = dma_buf_mapping_select(attach);
+	if (ret)
+		return ERR_PTR(ret);
+
+	type = dma_buf_attach_map_type(attach)->type;
+	if (!type->map) {
+		ret = -EOPNOTSUPP;
+		goto err_release;
+	}
+
+	mapping = type->map(attach, dir);
+	if (IS_ERR(mapping)) {
+		ret = PTR_ERR(mapping);
+		goto err_release;
+	}
+
+	return mapping;
+
+err_release:
+	dma_buf_mapping_unselect(attach, selected);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_mapping_map, "DMA_BUF");
+
+/**
+ * dma_buf_mapping_unmap - Release a mapping from dma_buf_mapping_map()
+ * @attach: the attachment
+ * @mapping: what dma_buf_mapping_map() returned
+ * @dir: DMA direction used for the map
+ */
+void dma_buf_mapping_unmap(struct dma_buf_attachment *attach,
+			   struct dma_buf_mapping *mapping,
+			   enum dma_data_direction dir)
+{
+	might_sleep();
+
+	if (WARN_ON(!attach || !attach->dmabuf || !mapping))
+		return;
+
+	dma_resv_assert_held(attach->dmabuf->resv);
+
+	mapping->type->unmap(attach, mapping, dir);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_mapping_unmap, "DMA_BUF");
+
 static int dma_buf_sgt_match(struct dma_buf_match_args *args,
 			     const struct dma_buf_mapping_match *exp,
 			     const struct dma_buf_mapping_match *imp)
@@ -458,6 +534,8 @@ struct dma_buf_mapping_type dma_buf_mapping_sgt_type = {
 	.match = dma_buf_sgt_match,
 	.finish_match = dma_buf_sgt_finish_match,
 	.debugfs_dump = dma_buf_sgt_debugfs_dump,
+	.map = dma_buf_sgt_type_map,
+	.unmap = dma_buf_sgt_type_unmap,
 };
 EXPORT_SYMBOL_NS_GPL(dma_buf_mapping_sgt_type, "DMA_BUF");
 
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index f052184da5ed..fc1e62a0b388 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1345,6 +1345,39 @@ struct sg_table *dma_buf_map_sgt(struct dma_buf_attachment *attach,
 }
 EXPORT_SYMBOL_NS_GPL(dma_buf_map_sgt, "DMA_BUF");
 
+/* &dma_buf_mapping_type.map / .unmap for the SGT type */
+struct dma_buf_mapping *dma_buf_sgt_type_map(struct dma_buf_attachment *attach,
+					     enum dma_data_direction dir)
+{
+	struct dma_buf_sgt_mapping *mapping;
+	int ret;
+
+	mapping = kzalloc_obj(*mapping);
+	if (!mapping)
+		return ERR_PTR(-ENOMEM);
+
+	mapping->base.type = &dma_buf_mapping_sgt_type;
+	mapping->sgt = __dma_buf_map_sgt(attach, dir);
+	if (IS_ERR(mapping->sgt)) {
+		ret = PTR_ERR(mapping->sgt);
+		kfree(mapping);
+		return ERR_PTR(ret);
+	}
+
+	return &mapping->base;
+}
+
+void dma_buf_sgt_type_unmap(struct dma_buf_attachment *attach,
+			    struct dma_buf_mapping *base,
+			    enum dma_data_direction dir)
+{
+	struct dma_buf_sgt_mapping *mapping =
+		container_of(base, struct dma_buf_sgt_mapping, base);
+
+	dma_buf_unmap_sgt(attach, mapping->sgt, dir);
+	kfree(mapping);
+}
+
 /**
  * dma_buf_map_sgt_unlocked - Returns the scatterlist table of the attachment;
  * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the
diff --git a/include/linux/dma-buf-mapping.h b/include/linux/dma-buf-mapping.h
index 7140fc13dd00..a961314dbd99 100644
--- a/include/linux/dma-buf-mapping.h
+++ b/include/linux/dma-buf-mapping.h
@@ -33,6 +33,16 @@ enum dma_sgt_requires_p2p {
 /* Type tag for all mapping operations */
 struct dma_buf_mapping_exp_ops {};
 
+/**
+ * struct dma_buf_mapping - header of a mapping made with dma_buf_mapping_map()
+ * @type: The mapping type the exporter selected. Importers that listed more
+ *        than one type switch on this and use the type's accessor to get at
+ *        the type-specific result embedding this header.
+ */
+struct dma_buf_mapping {
+	const struct dma_buf_mapping_type *type;
+};
+
 /*
  * Internal struct to pass arguments from the attach function to the matching
  * function
@@ -100,8 +110,35 @@ struct dma_buf_mapping_type {
 	 */
 	void (*debugfs_dump)(struct seq_file *s,
 			     struct dma_buf_attachment *attach);
+
+	/**
+	 * @map:
+	 *
+	 * Produce a mapping of this type for @attach, for which this type has
+	 * already been selected. Called by dma_buf_mapping_map()
+	 * with the dma_resv lock held. Responsible for pin-on-map of static
+	 * importers if the type supports them. Optional; a type without it
+	 * can only be used through its own map functions.
+	 */
+	struct dma_buf_mapping *(*map)(struct dma_buf_attachment *attach,
+				       enum dma_data_direction dir);
+
+	/**
+	 * @unmap:
+	 *
+	 * Release a mapping returned by @map.
+	 */
+	void (*unmap)(struct dma_buf_attachment *attach,
+		      struct dma_buf_mapping *mapping,
+		      enum dma_data_direction dir);
 };
 
+struct dma_buf_mapping *dma_buf_mapping_map(struct dma_buf_attachment *attach,
+					    enum dma_data_direction dir);
+void dma_buf_mapping_unmap(struct dma_buf_attachment *attach,
+			   struct dma_buf_mapping *mapping,
+			   enum dma_data_direction dir);
+
 struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach,
 					 struct p2pdma_provider *provider,
 					 struct phys_vec *phys_vec,
@@ -158,6 +195,13 @@ dma_buf_attach_accepts(const struct dma_buf_attachment *attach,
 	return false;
 }
 
+/* Internal: &dma_buf_mapping_sgt_type.map / .unmap, implemented in dma-buf.c */
+struct dma_buf_mapping *dma_buf_sgt_type_map(struct dma_buf_attachment *attach,
+					     enum dma_data_direction dir);
+void dma_buf_sgt_type_unmap(struct dma_buf_attachment *attach,
+			    struct dma_buf_mapping *mapping,
+			    enum dma_data_direction dir);
+
 /*
  * DMA Mapped Scatterlist Type
  *
@@ -175,6 +219,25 @@ dma_buf_attach_accepts(const struct dma_buf_attachment *attach,
  */
 extern struct dma_buf_mapping_type dma_buf_mapping_sgt_type;
 
+/**
+ * struct dma_buf_sgt_mapping - dma_buf_mapping_map() result for the SGT type
+ * @base: common header, @base.type == &dma_buf_mapping_sgt_type
+ * @sgt: the DMA mapped scatterlist, as the SGT type's own map function
+ *       returns it
+ */
+struct dma_buf_sgt_mapping {
+	struct dma_buf_mapping base;
+	struct sg_table *sgt;
+};
+
+static inline struct sg_table *
+dma_buf_sgt_mapping_table(struct dma_buf_mapping *mapping)
+{
+	if (WARN_ON(mapping->type != &dma_buf_mapping_sgt_type))
+		return NULL;
+	return container_of(mapping, struct dma_buf_sgt_mapping, base)->sgt;
+}
+
 struct dma_buf_mapping_sgt_exp_ops {
 	struct dma_buf_mapping_exp_ops ops;
 	struct sg_table *(*map_dma_buf)(struct dma_buf_attachment *attach,

-- 
2.54.0




More information about the Linux-nvme mailing list