Commit 89d8589c authored by Tvrtko Ursulin's avatar Tvrtko Ursulin

lib/scatterlist: Introduce and export __sg_alloc_table_from_pages

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: default avatarTvrtko 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: default avatarChris 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
parent c125906b
...@@ -267,10 +267,13 @@ void sg_free_table(struct sg_table *); ...@@ -267,10 +267,13 @@ void sg_free_table(struct sg_table *);
int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int,
struct scatterlist *, gfp_t, sg_alloc_fn *); struct scatterlist *, gfp_t, sg_alloc_fn *);
int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
int sg_alloc_table_from_pages(struct sg_table *sgt, int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
struct page **pages, unsigned int n_pages, unsigned int n_pages, unsigned int offset,
unsigned int offset, unsigned long size, unsigned long size, unsigned int max_segment,
gfp_t gfp_mask); 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 sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf,
size_t buflen, off_t skip, bool to_buffer); size_t buflen, off_t skip, bool to_buffer);
......
...@@ -370,35 +370,38 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) ...@@ -370,35 +370,38 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
EXPORT_SYMBOL(sg_alloc_table); EXPORT_SYMBOL(sg_alloc_table);
/** /**
* sg_alloc_table_from_pages - Allocate and initialize an sg table from * __sg_alloc_table_from_pages - Allocate and initialize an sg table from
* an array of pages * an array of pages
* @sgt: The sg table header to use * @sgt: The sg table header to use
* @pages: Pointer to an array of page pointers * @pages: Pointer to an array of page pointers
* @n_pages: Number of pages in the pages array * @n_pages: Number of pages in the pages array
* @offset: Offset from start of the first page to the start of a buffer * @offset: Offset from start of the first page to the start of a buffer
* @size: Number of valid bytes in the buffer (after offset) * @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 * @gfp_mask: GFP allocation mask
* *
* Description: * Description:
* Allocate and initialize an sg table from a list of pages. Contiguous * 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 * ranges of the pages are squashed into a single scatterlist node up to the
* may provide an offset at a start and a size of valid data in a buffer * maximum size specified in @max_segment. An user may provide an offset at a
* specified by the page array. The returned sg table is released by * start and a size of valid data in a buffer specified by the page array.
* sg_free_table. * The returned sg table is released by sg_free_table.
* *
* Returns: * Returns:
* 0 on success, negative error on failure * 0 on success, negative error on failure
*/ */
int sg_alloc_table_from_pages(struct sg_table *sgt, int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
struct page **pages, unsigned int n_pages, unsigned int n_pages, unsigned int offset,
unsigned int offset, unsigned long size, unsigned long size, unsigned int max_segment,
gfp_t gfp_mask) gfp_t gfp_mask)
{ {
const unsigned int max_segment = SCATTERLIST_MAX_SEGMENT;
unsigned int chunks, cur_page, seg_len, i; unsigned int chunks, cur_page, seg_len, i;
int ret; int ret;
struct scatterlist *s; struct scatterlist *s;
if (WARN_ON(!max_segment || offset_in_page(max_segment)))
return -EINVAL;
/* compute number of contiguous chunks */ /* compute number of contiguous chunks */
chunks = 1; chunks = 1;
seg_len = 0; seg_len = 0;
...@@ -440,6 +443,35 @@ int sg_alloc_table_from_pages(struct sg_table *sgt, ...@@ -440,6 +443,35 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
return 0; 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); EXPORT_SYMBOL(sg_alloc_table_from_pages);
void __sg_page_iter_start(struct sg_page_iter *piter, void __sg_page_iter_start(struct sg_page_iter *piter,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment