aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 13:11:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 13:11:31 -0400
commit6f51f51582e793ea13e7de7ed6b138f71c51784b (patch)
tree211ecbf88cdf2f183e23da3f8f23153ac6133410 /lib
parent76159c20c0bcf5b38178fbfb61049eeb6380bb54 (diff)
parent97ef952a20853fad72087a53fa556fbec45edd8f (diff)
Merge branch 'for-linus-for-3.6-rc1' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping
Pull DMA-mapping updates from Marek Szyprowski: "Those patches are continuation of my earlier work. They contains extensions to DMA-mapping framework to remove limitation of the current ARM implementation (like limited total size of DMA coherent/write combine buffers), improve performance of buffer sharing between devices (attributes to skip cpu cache operations or creation of additional kernel mapping for some specific use cases) as well as some unification of the common code for dma_mmap_attrs() and dma_mmap_coherent() functions. All extensions have been implemented and tested for ARM architecture." * 'for-linus-for-3.6-rc1' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping: ARM: dma-mapping: add support for DMA_ATTR_SKIP_CPU_SYNC attribute common: DMA-mapping: add DMA_ATTR_SKIP_CPU_SYNC attribute ARM: dma-mapping: add support for dma_get_sgtable() common: dma-mapping: introduce dma_get_sgtable() function ARM: dma-mapping: add support for DMA_ATTR_NO_KERNEL_MAPPING attribute common: DMA-mapping: add DMA_ATTR_NO_KERNEL_MAPPING attribute common: dma-mapping: add support for generic dma_mmap_* calls ARM: dma-mapping: fix error path for memory allocation failure ARM: dma-mapping: add more sanity checks in arm_dma_mmap() ARM: dma-mapping: remove custom consistent dma region mm: vmalloc: use const void * for caller argument scatterlist: add sg_alloc_table_from_pages function
Diffstat (limited to 'lib')
-rw-r--r--lib/scatterlist.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 6096e89bee55..e719adf695bf 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -319,6 +319,70 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
319EXPORT_SYMBOL(sg_alloc_table); 319EXPORT_SYMBOL(sg_alloc_table);
320 320
321/** 321/**
322 * sg_alloc_table_from_pages - Allocate and initialize an sg table from
323 * an array of pages
324 * @sgt: The sg table header to use
325 * @pages: Pointer to an array of page pointers
326 * @n_pages: Number of pages in the pages array
327 * @offset: Offset from start of the first page to the start of a buffer
328 * @size: Number of valid bytes in the buffer (after offset)
329 * @gfp_mask: GFP allocation mask
330 *
331 * Description:
332 * Allocate and initialize an sg table from a list of pages. Contiguous
333 * ranges of the pages are squashed into a single scatterlist node. A user
334 * may provide an offset at a start and a size of valid data in a buffer
335 * specified by the page array. The returned sg table is released by
336 * sg_free_table.
337 *
338 * Returns:
339 * 0 on success, negative error on failure
340 */
341int sg_alloc_table_from_pages(struct sg_table *sgt,
342 struct page **pages, unsigned int n_pages,
343 unsigned long offset, unsigned long size,
344 gfp_t gfp_mask)
345{
346 unsigned int chunks;
347 unsigned int i;
348 unsigned int cur_page;
349 int ret;
350 struct scatterlist *s;
351
352 /* compute number of contiguous chunks */
353 chunks = 1;
354 for (i = 1; i < n_pages; ++i)
355 if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
356 ++chunks;
357
358 ret = sg_alloc_table(sgt, chunks, gfp_mask);
359 if (unlikely(ret))
360 return ret;
361
362 /* merging chunks and putting them into the scatterlist */
363 cur_page = 0;
364 for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
365 unsigned long chunk_size;
366 unsigned int j;
367
368 /* look for the end of the current chunk */
369 for (j = cur_page + 1; j < n_pages; ++j)
370 if (page_to_pfn(pages[j]) !=
371 page_to_pfn(pages[j - 1]) + 1)
372 break;
373
374 chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
375 sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
376 size -= chunk_size;
377 offset = 0;
378 cur_page = j;
379 }
380
381 return 0;
382}
383EXPORT_SYMBOL(sg_alloc_table_from_pages);
384
385/**
322 * sg_miter_start - start mapping iteration over a sg list 386 * sg_miter_start - start mapping iteration over a sg list
323 * @miter: sg mapping iter to be started 387 * @miter: sg mapping iter to be started
324 * @sgl: sg list to iterate over 388 * @sgl: sg list to iterate over