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 <[email protected]> --- 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
