diff options
-rw-r--r-- | include/linux/scatterlist.h | 10 | ||||
-rw-r--r-- | lib/Kconfig | 4 | ||||
-rw-r--r-- | lib/scatterlist.c | 105 |
3 files changed, 119 insertions, 0 deletions
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index b7c83254c566..b8a7c1d1dbe3 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h | |||
@@ -276,6 +276,16 @@ int sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages, | |||
276 | unsigned int n_pages, unsigned int offset, | 276 | unsigned int n_pages, unsigned int offset, |
277 | unsigned long size, gfp_t gfp_mask); | 277 | unsigned long size, gfp_t gfp_mask); |
278 | 278 | ||
279 | #ifdef CONFIG_SGL_ALLOC | ||
280 | struct scatterlist *sgl_alloc_order(unsigned long long length, | ||
281 | unsigned int order, bool chainable, | ||
282 | gfp_t gfp, unsigned int *nent_p); | ||
283 | struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp, | ||
284 | unsigned int *nent_p); | ||
285 | void sgl_free_order(struct scatterlist *sgl, int order); | ||
286 | void sgl_free(struct scatterlist *sgl); | ||
287 | #endif /* CONFIG_SGL_ALLOC */ | ||
288 | |||
279 | size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, | 289 | size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, |
280 | size_t buflen, off_t skip, bool to_buffer); | 290 | size_t buflen, off_t skip, bool to_buffer); |
281 | 291 | ||
diff --git a/lib/Kconfig b/lib/Kconfig index c5e84fbcb30b..4dd5c11366f9 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -409,6 +409,10 @@ config HAS_DMA | |||
409 | depends on !NO_DMA | 409 | depends on !NO_DMA |
410 | default y | 410 | default y |
411 | 411 | ||
412 | config SGL_ALLOC | ||
413 | bool | ||
414 | default n | ||
415 | |||
412 | config DMA_NOOP_OPS | 416 | config DMA_NOOP_OPS |
413 | bool | 417 | bool |
414 | depends on HAS_DMA && (!64BIT || ARCH_DMA_ADDR_T_64BIT) | 418 | depends on HAS_DMA && (!64BIT || ARCH_DMA_ADDR_T_64BIT) |
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 7c1c55f7daaa..9afc9b432083 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
@@ -474,6 +474,111 @@ int sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages, | |||
474 | } | 474 | } |
475 | EXPORT_SYMBOL(sg_alloc_table_from_pages); | 475 | EXPORT_SYMBOL(sg_alloc_table_from_pages); |
476 | 476 | ||
477 | #ifdef CONFIG_SGL_ALLOC | ||
478 | |||
479 | /** | ||
480 | * sgl_alloc_order - allocate a scatterlist and its pages | ||
481 | * @length: Length in bytes of the scatterlist. Must be at least one | ||
482 | * @order: Second argument for alloc_pages() | ||
483 | * @chainable: Whether or not to allocate an extra element in the scatterlist | ||
484 | * for scatterlist chaining purposes | ||
485 | * @gfp: Memory allocation flags | ||
486 | * @nent_p: [out] Number of entries in the scatterlist that have pages | ||
487 | * | ||
488 | * Returns: A pointer to an initialized scatterlist or %NULL upon failure. | ||
489 | */ | ||
490 | struct scatterlist *sgl_alloc_order(unsigned long long length, | ||
491 | unsigned int order, bool chainable, | ||
492 | gfp_t gfp, unsigned int *nent_p) | ||
493 | { | ||
494 | struct scatterlist *sgl, *sg; | ||
495 | struct page *page; | ||
496 | unsigned int nent, nalloc; | ||
497 | u32 elem_len; | ||
498 | |||
499 | nent = round_up(length, PAGE_SIZE << order) >> (PAGE_SHIFT + order); | ||
500 | /* Check for integer overflow */ | ||
501 | if (length > (nent << (PAGE_SHIFT + order))) | ||
502 | return NULL; | ||
503 | nalloc = nent; | ||
504 | if (chainable) { | ||
505 | /* Check for integer overflow */ | ||
506 | if (nalloc + 1 < nalloc) | ||
507 | return NULL; | ||
508 | nalloc++; | ||
509 | } | ||
510 | sgl = kmalloc_array(nalloc, sizeof(struct scatterlist), | ||
511 | (gfp & ~GFP_DMA) | __GFP_ZERO); | ||
512 | if (!sgl) | ||
513 | return NULL; | ||
514 | |||
515 | sg_init_table(sgl, nent); | ||
516 | sg = sgl; | ||
517 | while (length) { | ||
518 | elem_len = min_t(u64, length, PAGE_SIZE << order); | ||
519 | page = alloc_pages(gfp, order); | ||
520 | if (!page) { | ||
521 | sgl_free(sgl); | ||
522 | return NULL; | ||
523 | } | ||
524 | |||
525 | sg_set_page(sg, page, elem_len, 0); | ||
526 | length -= elem_len; | ||
527 | sg = sg_next(sg); | ||
528 | } | ||
529 | WARN_ON_ONCE(sg); | ||
530 | if (nent_p) | ||
531 | *nent_p = nent; | ||
532 | return sgl; | ||
533 | } | ||
534 | EXPORT_SYMBOL(sgl_alloc_order); | ||
535 | |||
536 | /** | ||
537 | * sgl_alloc - allocate a scatterlist and its pages | ||
538 | * @length: Length in bytes of the scatterlist | ||
539 | * @gfp: Memory allocation flags | ||
540 | * @nent_p: [out] Number of entries in the scatterlist | ||
541 | * | ||
542 | * Returns: A pointer to an initialized scatterlist or %NULL upon failure. | ||
543 | */ | ||
544 | struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp, | ||
545 | unsigned int *nent_p) | ||
546 | { | ||
547 | return sgl_alloc_order(length, 0, false, gfp, nent_p); | ||
548 | } | ||
549 | EXPORT_SYMBOL(sgl_alloc); | ||
550 | |||
551 | /** | ||
552 | * sgl_free_order - free a scatterlist and its pages | ||
553 | * @sgl: Scatterlist with one or more elements | ||
554 | * @order: Second argument for __free_pages() | ||
555 | */ | ||
556 | void sgl_free_order(struct scatterlist *sgl, int order) | ||
557 | { | ||
558 | struct scatterlist *sg; | ||
559 | struct page *page; | ||
560 | |||
561 | for (sg = sgl; sg; sg = sg_next(sg)) { | ||
562 | page = sg_page(sg); | ||
563 | if (page) | ||
564 | __free_pages(page, order); | ||
565 | } | ||
566 | kfree(sgl); | ||
567 | } | ||
568 | EXPORT_SYMBOL(sgl_free_order); | ||
569 | |||
570 | /** | ||
571 | * sgl_free - free a scatterlist and its pages | ||
572 | * @sgl: Scatterlist with one or more elements | ||
573 | */ | ||
574 | void sgl_free(struct scatterlist *sgl) | ||
575 | { | ||
576 | sgl_free_order(sgl, 0); | ||
577 | } | ||
578 | EXPORT_SYMBOL(sgl_free); | ||
579 | |||
580 | #endif /* CONFIG_SGL_ALLOC */ | ||
581 | |||
477 | void __sg_page_iter_start(struct sg_page_iter *piter, | 582 | void __sg_page_iter_start(struct sg_page_iter *piter, |
478 | struct scatterlist *sglist, unsigned int nents, | 583 | struct scatterlist *sglist, unsigned int nents, |
479 | unsigned long pgoffset) | 584 | unsigned long pgoffset) |