On Tue, 08 May 2012 11:50:33 +0200 Tomasz Stanislawski t.stanislaws@samsung.com wrote:
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.
...
/**
- 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. Continuous
s/Continuous/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
- **/
nit: Use */, not **/ here.
+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)
I guess a 32-bit n_pages is OK. A 16TB IO seems enough ;)
+{
- unsigned int chunks;
- unsigned int i;
erk, please choose a different name for this. When a C programmer sees "i", he very much assumes it has type "int". Making it unsigned causes surprise.
And don't rename it to "u"! Let's give it a nice meaningful name. pageno?
- 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)
This assumes that if two pages have contiguous pfn's then they are physically contiguous. Is that true for all architectures and memory models, including sparsemem? See sparse_encode_mem_map().
++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;
"j" is an "int", too.
/* looking for the end of the current chunk */
s/looking/look/
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);