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. Assisted-by: LLM Signed-off-by: Alistair Popple <[email protected]> --- drivers/dma-buf/dma-buf-mapping.c | 75 +++++++++++++++++++++++++++++++ drivers/dma-buf/dma-buf.c | 33 ++++++++++++++ include/linux/dma-buf-mapping.h | 63 ++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-mapping.c index dbcd83b6dcff..7a5a379a372e 100644 --- a/drivers/dma-buf/dma-buf-mapping.c +++ b/drivers/dma-buf/dma-buf-mapping.c @@ -366,6 +366,79 @@ int dma_buf_mapping_select(struct dma_buf_attachment *attach) return 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) +{ + struct dma_buf_mapping *mapping; + int ret; + + might_sleep(); + + if (WARN_ON(!attach || !attach->dmabuf)) + return ERR_PTR(-EINVAL); + + dma_resv_assert_held(attach->dmabuf->resv); + + ret = dma_buf_mapping_select(attach); + if (ret) + return ERR_PTR(ret); + + if (!attach->map_type.type->map) { + ret = -EOPNOTSUPP; + goto err_release; + } + + mapping = attach->map_type.type->map(attach, dir); + if (IS_ERR(mapping)) { + ret = PTR_ERR(mapping); + goto err_release; + } + + return mapping; + +err_release: + /* Nothing was established, so the choice may be made afresh */ + attach->selected = false; + 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 *dmabuf, const struct dma_buf_mapping_match *exp, const struct dma_buf_mapping_match *imp) @@ -427,6 +500,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 03f06c4b957c..90699e85e4c8 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1353,6 +1353,39 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, } EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, "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_sgt_map_attachment(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_attachment(attach, mapping->sgt, dir); + kfree(mapping); +} + /** * dma_buf_map_attachment_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 494bc29910f4..885e0e54b5eb 100644 --- a/include/linux/dma-buf-mapping.h +++ b/include/linux/dma-buf-mapping.h @@ -21,6 +21,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 @@ -82,8 +92,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, which has already been + * selected into @attach->map_type. 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, @@ -122,6 +159,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 * @@ -137,6 +181,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
