lkml.org 
[lkml]   [2012]   [Apr]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH v2] scatterlist: add sg_alloc_table_from_pages function
    On Tue, Apr 24, 2012 at 02:58:56PM +0200, 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.
    >
    > 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>

    I like this and we could replace the drm helper function in drm prime with
    this one. One comment below.
    -Daniel

    > ---
    > include/linux/scatterlist.h | 4 +++
    > lib/scatterlist.c | 63 +++++++++++++++++++++++++++++++++++++++++++
    > 2 files changed, 67 insertions(+), 0 deletions(-)
    >
    > diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
    > index ac9586d..7b600da 100644
    > --- a/include/linux/scatterlist.h
    > +++ b/include/linux/scatterlist.h
    > @@ -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);
    > diff --git a/lib/scatterlist.c b/lib/scatterlist.c
    > index 6096e89..90f9265 100644
    > --- a/lib/scatterlist.c
    > +++ b/lib/scatterlist.c
    > @@ -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_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 a start of the first page to a 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
    > + * 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 (pages[i] != pages[i - 1] + 1)
    > + ++chunks;

    I'm not aware of the details (and didn't bother to do a full audit), but
    I guess this could blow up on funky discontig-mem setups. Imo would be
    safer to compare the pfn or phys address. And also slightly more readable.
    Imo sg table creation is not a fastpath, the exporter should cache these
    anyway, so we can waste some cpu cycles here.

    > + 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_from_pages);
    > +
    > +/**
    > * sg_miter_start - start mapping iteration over a sg list
    > * @miter: sg mapping iter to be started
    > * @sgl: sg list to iterate over
    > --
    > 1.7.5.4
    >
    > _______________________________________________
    > dri-devel mailing list
    > dri-devel@lists.freedesktop.org
    > http://lists.freedesktop.org/mailman/listinfo/dri-devel

    --
    Daniel Vetter
    Mail: daniel@ffwll.ch
    Mobile: +41 (0)79 365 57 48


    \
     
     \ /
      Last update: 2012-04-24 16:37    [W:0.037 / U:0.412 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site