staging: comedi: 8255_pci: fix namespace due to rename of driver
[pandora-kernel.git] / lib / scatterlist.c
index 6096e89..fadae77 100644 (file)
@@ -279,14 +279,6 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                if (!left)
                        sg_mark_end(&sg[sg_size - 1]);
 
-               /*
-                * only really needed for mempool backed sg allocations (like
-                * SCSI), a possible improvement here would be to pass the
-                * table pointer into the allocator and let that clear these
-                * flags
-                */
-               gfp_mask &= ~__GFP_WAIT;
-               gfp_mask |= __GFP_HIGH;
                prv = sg;
        } while (left);
 
@@ -318,6 +310,70 @@ 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
+ *
+ *  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(sg_alloc_table_from_pages);
+
 /**
  * sg_miter_start - start mapping iteration over a sg list
  * @miter: sg mapping iter to be started