scatterlist: add sg_alloc_table_from_pages function
Subsystems (2)
PATCH v2 1/1 scatterlist: add sg_alloc_table_from_pages function
This patch adds a new constructor for an sg table. The table is constructed from an array of struct pages. All contiguous chunks of the pages are merged into a single sg nodes. A user may provide an offset and a size of a buffer if the buffer is not page-aligned.
The function is dedicated for DMABUF exporters which often perform conversion from an page array to a scatterlist. Moreover the scatterlist should be squashed in order to save memory and to speed-up the process of DMA mapping using dma_map_sg.
The code is based on the patch 'v4l: vb2-dma-contig: add support for scatterlist in userptr mode' and hints from Laurent Pinchart.
--- include/linux/scatterlist.h | 4 +++ lib/scatterlist.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 0 deletions(-)
include/linux/scatterlist.h +4 -0
@@ -214,6 +214,10 @@ void sg_free_table(struct sg_table *);int __sg_alloc_table (struct sg_table *,unsigned int ,unsigned int ,gfp_t ,sg_alloc_fn *);int sg_alloc_table (struct sg_table *,unsigned int ,gfp_t ); +int sg_alloc_table_from_pages (struct sg_table *sgt, +struct page **pages,unsigned int n_pages, +unsigned long offset,unsigned long size, +gfp_t gfp_mask);size_t sg_copy_from_buffer (struct scatterlist *sgl,unsigned int nents,void *buf,size_t buflen);
lib/scatterlist.c +63 -0
69 lines not on this page · raw message
Signature · 1 line
1.7.5.4
Quoted 10 lines · Tomasz Stanislawski
This patch adds a new constructor for an sg table. The table is constructed from an array of struct pages. All contiguous chunks of the pages are merged into a single sg nodes. A user may provide an offset and a size of a buffer if the buffer is not page-aligned.
The function is dedicated for DMABUF exporters which often perform conversion from an page array to a scatterlist. Moreover the scatterlist should be squashed in order to save memory and to speed-up the process of DMA mapping using
dma_map_sg.
Quoted 5 lines
The code is based on the patch 'v4l: vb2-dma-contig: add support for scatterlist in userptr mode' and hints from Laurent Pinchart.
Signed-off-by Tomasz Stanislawski <[email protected]>Signed-off-by Kyungmin Park <[email protected]>
I like this and we could replace the drm helper function in drm prime with this one. One comment below.
-Daniel
Quoted 53 lines
--- include/linux/scatterlist.h | 4 +++ lib/scatterlist.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 0 deletions(-)include/linux/scatterlist.h +4
-0@@ -214,6 +214,10 @@ void sg_free_table(struct sg_table *);int __sg_alloc_table (struct sg_table *,unsigned int ,unsigned int ,gfp_t ,sg_alloc_fn *);int sg_alloc_table (struct sg_table *,unsigned int ,gfp_t ); +int sg_alloc_table_from_pages (struct sg_table *sgt, +struct page **pages,unsigned int n_pages, +unsigned long offset,unsigned long size, +gfp_t gfp_mask);size_t sg_copy_from_buffer (struct scatterlist *sgl,unsigned int nents,void *buf,size_t buflen);lib/scatterlist.c +25
-0@@ -319,6 +319,69 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)EXPORT_SYMBOL (sg_alloc_table);/** +* sg_alloc_table_from_pages - Allocate and initialize an sg table from +* an array of pages +* @sgt: The sg table header to use +* @pages: Pointer to an array of page pointers +* @n_pages: Number of pages in the pages array +* @offset: Offset from a start of the first page to a start of a buffer +* @size: Number of valid bytes in the buffer (after offset) +* @gfp_mask: GFP allocation mask +* +* Description: +* Allocate and initialize an sg table from a list of pages. Continuous +* ranges of the pages are squashed into a single scatterlist node. A user +* may provide an offset at a start and a size of valid data in a buffer +* specified by the page array. The returned sg table is released by +* sg_free_table. +* +* Returns: +* 0 on success, negative error on failure +**/ +int sg_alloc_table_from_pages (struct sg_table *sgt, +struct page **pages,unsigned int n_pages, +unsigned long offset,unsigned long size, +gfp_t gfp_mask) +{ +unsigned int chunks;
lib/scatterlist.c int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) · line 356
Quoted 10 lines
lib/scatterlist.c +10
-0+unsigned int i; +unsigned int cur_page; +int ret; +struct scatterlist *s; + +/* compute number of contiguous chunks */ + chunks =1 ; +for (i =1 ; i < n_pages; ++i) +if (pages[i] != pages[i -1 ] +1 ) + ++chunks;
I'm not aware of the details (and didn't bother to do a full audit), but I guess this could blow up on funky discontig-mem setups. Imo would be safer to compare the pfn or phys address. And also slightly more readable. Imo sg table creation is not a fastpath, the exporter should cache these anyway, so we can waste some cpu cycles here.
Quoted 37 lines
lib/scatterlist.c +27
-0+ ret =sg_alloc_table (sgt, chunks, gfp_mask); +if (unlikely (ret)) +return ret; + +/* merging chunks and putting them into the scatterlist */ + cur_page =0 ; +for_each_sg (sgt->sgl, s, sgt->orig_nents, i) { +unsigned long chunk_size; +unsigned int j; + +/* looking for the end of the current chunk */ +for (j = cur_page +1 ; j < n_pages; ++j) +if (pages[j] != pages[j -1 ] +1 ) +break ; + + chunk_size = ((j - cur_page) <<PAGE_SHIFT ) - offset; +sg_set_page (s, pages[cur_page],min (size, chunk_size), offset); + size -= chunk_size; + offset =0 ; + cur_page = j; + } + +return 0 ; +} +EXPORT_SYMBOL (sg_alloc_table_from_pages); + +/** * sg_miter_start - start mapping iteration over a sg list * @miter: sg mapping iter to be started * @sgl: sg list to iterate over Signature · 6 lines
1.7.5.4 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 3 lines
Daniel Vetter Mail: [email protected] Mobile: +41 (0)79 365 57 48