Skip to contentSkip to conversation

scatterlist: add sg_alloc_table_by_pages function

PATCH Superseded Tomasz Stanislawski 2 participants 2 messages Apr 18, 2012 – Apr 21, 2012

Subsystems (2)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 scatterlist: add sg_alloc_table_by_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 performs conversion from an page array to a scatterlist. Moreover the scatterlist should be squashed in order to save memory and to speed-up 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
index ac9586d..8d9e6fe 100644
@@ -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_by_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
#1 lore raw

Hi Tomasz,

Thanks for the patch.

Quoted 5 lines · On Wednesday 18 April 2012 11:44:59 Tomasz Stanislawski 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.

Quoted 7 lines

The function is dedicated for DMABUF exporters which often performs conversion from an page array to a scatterlist. Moreover the scatterlist should be squashed in order to save memory and to speed-up 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.

The patch looks good to me. Just a small comment, what do you think about naming the function sg_alloc_table_from_pages instead of sg_table_alloc_by_pages ?

Quoted 40 lines
---
 include/linux/scatterlist.h |    4 +++
 lib/scatterlist.c           |   63

+++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 0 deletions(-)

include/linux/scatterlist.h +4 -0
index ac9586d..8d9e6fe 100644
@@ -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_by_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 +1 -0
index 6096e89..30b9def 100644
@@ -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_by_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:

Quoted 8 lines

+ * 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

Maybe you should mention what it returns in case of an error as well.

Quoted 48 lines

+ **/

lib/scatterlist.c +44 -0
+int sg_alloc_table_by_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 (pages[i] != 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;
+
+		/* 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_by_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 · 3 lines
Regards,

Laurent Pinchart