forked from Minki/linux
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. Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> CC: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
28a33cbc24
commit
efc42bc980
@ -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);
|
||||
|
@ -318,6 +318,70 @@ 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 start of the first page to the 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. Contiguous
|
||||
* 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;
|
||||
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 (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
|
||||
++chunks;
|
||||
|
||||
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;
|
||||
|
||||
/* look for the end of the current chunk */
|
||||
for (j = cur_page + 1; j < n_pages; ++j)
|
||||
if (page_to_pfn(pages[j]) !=
|
||||
page_to_pfn(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
|
||||
|
Loading…
Reference in New Issue
Block a user