DMA-buf mapping types allow the importer and exporter to negotiate the format of the map/unmap to be used during the attachment.
Currently DMA-buf only supports struct scatterlist as the attachment map operation. This is not sufficient for all use cases as dma_addr_t is a very specific and limited type.
With mapping types the importing driver can declare what it supports. For example:
struct dma_buf_mapping_match imp_match[] = { DMA_BUF_IMAPPING_MY_DRIVER(dev, ...), DMA_BUF_IMAPPING_SGT(dev, false), }; attach = dma_buf_mapping_attach(dmabuf, imp_match, ...)
And the exporting driver can declare what it supports:
int exporter_match_mapping(struct dma_buf_match_args *args) { struct dma_buf_mapping_match exp_match[] = { DMA_BUF_EMAPPING_MY_DRIVER(my_ops, dev, ...), DMA_BUF_EMAPPING_SGT(sgt_ops, dev, false), DMA_BUF_EMAPPING_PAL(PAL_ops), }; return dma_buf_match_mapping(args, exp_match, ...); }
During dma_buf_mapping_attach() the core code will select a mutual match between the importer and exporter and record it in the attach->map_type.
Add the basic types:
struct dma_buf_mapping_type Type tag and ops for each mapping type.
struct dma_buf_mapping_match Entry in a list of importer or exporter match specifications. The match specification can be extended by the mapping type with unique data.
dma_buf_match_mapping() / struct dma_buf_match_args Helper to do the matching. Called by the exporting driver via a dma_buf_ops callback.
struct dma_buf_mapping_exp_ops Base type for the per-mapping type exporter provided functions. This would be the map/unmap callbacks. Each mapping type can provide its own functions for map/unmap type operations with optimal type signatures.
Signed-off-by: Jason Gunthorpe jgg@nvidia.com --- drivers/dma-buf/dma-buf-mapping.c | 46 +++++++++++++++++++ include/linux/dma-buf-mapping.h | 76 +++++++++++++++++++++++++++++++ include/linux/dma-buf.h | 18 ++++++++ 3 files changed, 140 insertions(+)
diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-mapping.c index b7352e609fbdfa..459c204cabb803 100644 --- a/drivers/dma-buf/dma-buf-mapping.c +++ b/drivers/dma-buf/dma-buf-mapping.c @@ -5,6 +5,7 @@ */ #include <linux/dma-buf-mapping.h> #include <linux/dma-resv.h> +#include <linux/dma-buf.h>
static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length, dma_addr_t addr) @@ -246,3 +247,48 @@ void dma_buf_free_sgt(struct dma_buf_attachment *attach, struct sg_table *sgt,
} EXPORT_SYMBOL_NS_GPL(dma_buf_free_sgt, "DMA_BUF"); + +/** + * dma_buf_match_mapping - Select a mapping type agreed upon by exporter and + * importer + * @args: Match arguments from attach. On success this is updated with the + * matched exporter and importer entries. + * @exp: Array of mapping types supported by the exporter, in priority order + * @exp_len: Number of entries in @exp + * + * Iterate over the exporter's supported mapping types and for each one search + * the importer's list for a compatible matching type. args and args->attach are + * populated with the resulting match. + * + * Because the exporter list is walked in order, the exporter controls the + * priority of mapping types. + */ +int dma_buf_match_mapping(struct dma_buf_match_args *args, + const struct dma_buf_mapping_match *exp, + size_t exp_len) +{ + const struct dma_buf_mapping_match *exp_end = exp + exp_len; + const struct dma_buf_mapping_match *imp_end = + args->imp_matches + args->imp_len; + int ret; + + for (; exp != exp_end; exp++) { + const struct dma_buf_mapping_match *imp = args->imp_matches; + + for (; imp != imp_end; imp++) { + if (exp->type != imp->type) + continue; + if (exp->type->match) { + ret = exp->type->match(args->dmabuf, exp, imp); + if (ret == -EOPNOTSUPP) + continue; + if (ret != 0) + return ret; + } + exp->type->finish_match(args, exp, imp); + return 0; + } + } + return -EINVAL; +} +EXPORT_SYMBOL_NS_GPL(dma_buf_match_mapping, "DMA_BUF"); diff --git a/include/linux/dma-buf-mapping.h b/include/linux/dma-buf-mapping.h index a3c0ce2d3a42fe..080ccbf3a3f8b8 100644 --- a/include/linux/dma-buf-mapping.h +++ b/include/linux/dma-buf-mapping.h @@ -7,6 +7,77 @@ #define __DMA_BUF_MAPPING_H__ #include <linux/dma-buf.h>
+struct device; +struct dma_buf; +struct dma_buf_attachment; +struct dma_buf_mapping_exp_ops; + +/* Type tag for all mapping operations */ +struct dma_buf_mapping_exp_ops {}; + +/* + * Internal struct to pass arguments from the attach function to the matching + * function + */ +struct dma_buf_match_args { + struct dma_buf *dmabuf; + struct dma_buf_attachment *attach; + const struct dma_buf_mapping_match *imp_matches; + size_t imp_len; +}; + +/** + * struct dma_buf_mapping_type - Operations for a DMA-buf mapping type + * + * Each mapping type provides a singleton instance of this struct to describe + * the mapping type and its operations. + */ +struct dma_buf_mapping_type { + /** + * @name: Human-readable name for this mapping type, used in debugfs + * output + */ + const char *name; + + /** + * @match: + * + * Called during attach from dma_buf_match_mapping(). &exp and &imp are + * single items from the importer and exporter mapping match lists. + * Both will have the same instance of this struct as their type member. + * + * It determines if the exporter/importer are compatible. + * + * Returns: 0 on success + * -EOPNOTSUPP means ignore the failure and continue + * Everything else aborts the search and returns the -errno + */ + int (*match)(struct dma_buf *dmabuf, + const struct dma_buf_mapping_match *exp, + const struct dma_buf_mapping_match *imp); + + /** + * @finish_match: + * + * Called by dma_buf_match_mapping() after a successful match to store + * the negotiated result in @args->attach. The matched @exp and @imp + * entries are provided so the callback can copy type-specific data into + * the attachment. + */ + void (*finish_match)(struct dma_buf_match_args *args, + const struct dma_buf_mapping_match *exp, + const struct dma_buf_mapping_match *imp); + + /** + * @debugfs_dump: + * + * Optional callback to write mapping-type-specific diagnostic + * information about @attach to the debugfs seq_file @s. + */ + void (*debugfs_dump)(struct seq_file *s, + struct dma_buf_attachment *attach); +}; + struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach, struct p2pdma_provider *provider, struct dma_buf_phys_vec *phys_vec, @@ -14,4 +85,9 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach, enum dma_data_direction dir); void dma_buf_free_sgt(struct dma_buf_attachment *attach, struct sg_table *sgt, enum dma_data_direction dir); + +int dma_buf_match_mapping(struct dma_buf_match_args *args, + const struct dma_buf_mapping_match *exp_mappings, + size_t exp_len); + #endif diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 0bc492090237ed..a2b01b13026810 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -27,6 +27,21 @@ struct device; struct dma_buf; struct dma_buf_attachment; +struct dma_buf_mapping_type; +struct dma_buf_mapping_exp_ops; + +/* + * Match items are generated by the importer using the DMA_BUF_IMAPPING_*() and + * the exporter using the DMA_BUF_EMAPPING_*() functions. Each mapping type + * defines its own signature with its own data to make the match and attachment. + */ +struct dma_buf_mapping_match { + const struct dma_buf_mapping_type *type; + const struct dma_buf_mapping_exp_ops *exp_ops; + union { + /* Each mapping_type has unique match parameters here */ + }; +};
/** * struct dma_buf_ops - operations possible on struct dma_buf @@ -488,6 +503,8 @@ struct dma_buf_attach_ops { * @importer_ops: importer operations for this attachment, if provided * dma_buf_map/unmap_attachment() must be called with the dma_resv lock held. * @importer_priv: importer specific attachment data. + * @map_type: The match that defines the mutually compatible mapping type to use + * for this attachment. * * This structure holds the attachment information between the dma_buf buffer * and its user device(s). The list contains one attachment struct per device @@ -506,6 +523,7 @@ struct dma_buf_attachment { const struct dma_buf_attach_ops *importer_ops; void *importer_priv; void *priv; + struct dma_buf_mapping_match map_type; };
/**