lib/scatterlist: Introduce and export __sg_alloc_table_from_pages
authorTvrtko Ursulin <tvrtko.ursulin@intel.com>
Thu, 3 Aug 2017 09:13:51 +0000 (10:13 +0100)
committerTvrtko Ursulin <tvrtko.ursulin@intel.com>
Thu, 7 Sep 2017 09:48:29 +0000 (10:48 +0100)
Drivers like i915 benefit from being able to control the maxium
size of the sg coalesced segment while building the scatter-
gather list.

Introduce and export the __sg_alloc_table_from_pages function
which will allow it that control.

v2: Reorder parameters. (Chris Wilson)
v3: Fix incomplete reordering in v2.
v4: max_segment needs to be page aligned.
v5: Rebase.
v6: Rebase.
v7: Fix spelling in commit and mention max segment size in
    __sg_alloc_table_from_pages kerneldoc. (Andrew Morton)

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: linux-kernel@vger.kernel.org
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20170803091351.23594-1-tvrtko.ursulin@linux.intel.com
include/linux/scatterlist.h
lib/scatterlist.c

index 6dd2ddbc62301f545888e4983da41ab5ba33b07c..874b50c232de2acfc3646e76ee40258136faa698 100644 (file)
@@ -267,10 +267,13 @@ void sg_free_table(struct sg_table *);
 int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int,
                     struct scatterlist *, 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 int offset, unsigned long size,
-       gfp_t gfp_mask);
+int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
+                               unsigned int n_pages, unsigned int offset,
+                               unsigned long size, unsigned int max_segment,
+                               gfp_t gfp_mask);
+int sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
+                             unsigned int n_pages, unsigned int offset,
+                             unsigned long size, gfp_t gfp_mask);
 
 size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf,
                      size_t buflen, off_t skip, bool to_buffer);
index 7b2e74da2c44ba4103d5fe7ff8b3d66ac3ea0444..7c1c55f7daaa832df2aef731cd218d4ed80f44dc 100644 (file)
@@ -370,35 +370,38 @@ 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
+ * __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)
+ * @max_segment: Maximum size of a scatterlist node in bytes (page aligned)
+ * @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.
+ *    ranges of the pages are squashed into a single scatterlist node up to the
+ *    maximum size specified in @max_segment. An 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 int offset, unsigned long size,
-       gfp_t gfp_mask)
+int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
+                               unsigned int n_pages, unsigned int offset,
+                               unsigned long size, unsigned int max_segment,
+                               gfp_t gfp_mask)
 {
-       const unsigned int max_segment = SCATTERLIST_MAX_SEGMENT;
        unsigned int chunks, cur_page, seg_len, i;
        int ret;
        struct scatterlist *s;
 
+       if (WARN_ON(!max_segment || offset_in_page(max_segment)))
+               return -EINVAL;
+
        /* compute number of contiguous chunks */
        chunks = 1;
        seg_len = 0;
@@ -440,6 +443,35 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
 
        return 0;
 }
+EXPORT_SYMBOL(__sg_alloc_table_from_pages);
+
+/**
+ * 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 int offset,
+                             unsigned long size, gfp_t gfp_mask)
+{
+       return __sg_alloc_table_from_pages(sgt, pages, n_pages, offset, size,
+                                          SCATTERLIST_MAX_SEGMENT, gfp_mask);
+}
 EXPORT_SYMBOL(sg_alloc_table_from_pages);
 
 void __sg_page_iter_start(struct sg_page_iter *piter,