compat: backport sg_alloc_table_from_pages() from efc42bc9
authorLuis R. Rodriguez <mcgrof@do-not-panic.com>
Thu, 21 Mar 2013 23:29:23 +0000 (23:29 +0000)
committerLuis R. Rodriguez <mcgrof@do-not-panic.com>
Fri, 22 Mar 2013 19:36:42 +0000 (12:36 -0700)
This backports sg_alloc_table_from_pages() added via commit efc42bc9

mcgrof@frijol ~/linux-next (git::master)$ git describe --contains efc42bc9
v3.6-rc1~57^2~11

commit efc42bc98058a36d761b16a114823db1a902ed05
Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
Date:   Mon Jun 18 09:25:01 2012 +0200

    scatterlist: add sg_alloc_table_from_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 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>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
compat/Makefile
compat/compat-3.6.c [new file with mode: 0644]
include/linux/compat-3.6.h

index 5abdc35a4f435d33ed3c5236ac3451ef77504384..469025e52992aae3b6c049067b2af98a7ed2ad74 100644 (file)
@@ -49,6 +49,7 @@ compat-$(CONFIG_COMPAT_KERNEL_3_4) += compat-3.4.o
 compat-$(CONFIG_COMPAT_KERNEL_3_5) += \
        compat-3.5.o \
        user_namespace.o
+compat-$(CONFIG_COMPAT_KERNEL_3_6) += compat-3.6.o
 compat-$(CONFIG_COMPAT_KERNEL_3_7) += compat-3.7.o
 compat-$(CONFIG_COMPAT_KERNEL_3_8) += compat-3.8.o
 compat-$(CONFIG_COMPAT_KERNEL_3_9) += compat-3.9.o
diff --git a/compat/compat-3.6.c b/compat/compat-3.6.c
new file mode 100644 (file)
index 0000000..113e3a8
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013  Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * Backport compatibility file for Linux for kernels 3.6.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+
+/**
+ * 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 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 (page_to_pfn(pages[i]) != page_to_pfn(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;
+
+               /* look for the end of the current chunk */
+               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_GPL(sg_alloc_table_from_pages);
index 97b59933f53a836df319610da0bf5dec02c040f5..d9c964ed3f9a5049f63b7543a33399b4a0ee6dba 100644 (file)
@@ -5,6 +5,15 @@
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0))
 
+#include <linux/scatterlist.h>
+
+/* backports efc42bc9 */
+#define sg_alloc_table_from_pages LINUX_BACKPORT(sg_alloc_table_from_pages)
+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);
+
 /**
  * Backports
  *