[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