18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky * Copyright (c) 2010 Panasas, Inc.
58306998fSHans Petter Selasky * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky * Copyright (c) 2015 Matthew Dillon <dillon@backplane.com>
7c072f6e8SVladimir Kondratyev * Copyright (c) 2016 Matthew Macy
88d59ecb2SHans Petter Selasky * All rights reserved.
98d59ecb2SHans Petter Selasky *
108d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without
118d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions
128d59ecb2SHans Petter Selasky * are met:
138d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
148d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following
158d59ecb2SHans Petter Selasky * disclaimer.
168d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
178d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
188d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution.
198d59ecb2SHans Petter Selasky *
208d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
218d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
228d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
238d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
248d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
258d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
268d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
278d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
288d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
298d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
308d59ecb2SHans Petter Selasky */
31307f78f3SVladimir Kondratyev #ifndef _LINUXKPI_LINUX_SCATTERLIST_H_
32307f78f3SVladimir Kondratyev #define _LINUXKPI_LINUX_SCATTERLIST_H_
338d59ecb2SHans Petter Selasky
344abbf816SBjoern A. Zeeb #include <sys/types.h>
35*256eb8d5SVladimir Kondratyev #include <sys/proc.h>
36*256eb8d5SVladimir Kondratyev #include <sys/sched.h>
374abbf816SBjoern A. Zeeb #include <sys/sf_buf.h>
384abbf816SBjoern A. Zeeb
39*256eb8d5SVladimir Kondratyev #include <linux/err.h>
408d59ecb2SHans Petter Selasky #include <linux/page.h>
418d59ecb2SHans Petter Selasky #include <linux/slab.h>
428306998fSHans Petter Selasky #include <linux/mm.h>
438d59ecb2SHans Petter Selasky
44442d12d8SHans Petter Selasky struct bus_dmamap;
458d59ecb2SHans Petter Selasky struct scatterlist {
468306998fSHans Petter Selasky unsigned long page_link;
4772ebbe00SHans Petter Selasky #define SG_PAGE_LINK_CHAIN 0x1UL
4872ebbe00SHans Petter Selasky #define SG_PAGE_LINK_LAST 0x2UL
4972ebbe00SHans Petter Selasky #define SG_PAGE_LINK_MASK 0x3UL
508306998fSHans Petter Selasky unsigned int offset;
518306998fSHans Petter Selasky unsigned int length;
52f211d536STycho Nightingale dma_addr_t dma_address;
53442d12d8SHans Petter Selasky struct bus_dmamap *dma_map; /* FreeBSD specific */
548d59ecb2SHans Petter Selasky };
558d59ecb2SHans Petter Selasky
5672ebbe00SHans Petter Selasky CTASSERT((sizeof(struct scatterlist) & SG_PAGE_LINK_MASK) == 0);
578306998fSHans Petter Selasky
588d59ecb2SHans Petter Selasky struct sg_table {
598d59ecb2SHans Petter Selasky struct scatterlist *sgl;
608d59ecb2SHans Petter Selasky unsigned int nents;
618d59ecb2SHans Petter Selasky unsigned int orig_nents;
628d59ecb2SHans Petter Selasky };
638d59ecb2SHans Petter Selasky
648d59ecb2SHans Petter Selasky struct sg_page_iter {
658d59ecb2SHans Petter Selasky struct scatterlist *sg;
668d59ecb2SHans Petter Selasky unsigned int sg_pgoffset;
678d59ecb2SHans Petter Selasky unsigned int maxents;
688306998fSHans Petter Selasky struct {
698306998fSHans Petter Selasky unsigned int nents;
708306998fSHans Petter Selasky int pg_advance;
718306998fSHans Petter Selasky } internal;
728d59ecb2SHans Petter Selasky };
738d59ecb2SHans Petter Selasky
74fe4b041aSHans Petter Selasky struct sg_dma_page_iter {
75fe4b041aSHans Petter Selasky struct sg_page_iter base;
76fe4b041aSHans Petter Selasky };
77fe4b041aSHans Petter Selasky
7857a865f8SHans Petter Selasky #define SCATTERLIST_MAX_SEGMENT (-1U & ~(PAGE_SIZE - 1))
7957a865f8SHans Petter Selasky
808d59ecb2SHans Petter Selasky #define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist))
818d59ecb2SHans Petter Selasky
828306998fSHans Petter Selasky #define SG_MAGIC 0x87654321UL
8356b16627SHans Petter Selasky #define SG_CHAIN SG_PAGE_LINK_CHAIN
8456b16627SHans Petter Selasky #define SG_END SG_PAGE_LINK_LAST
858306998fSHans Petter Selasky
8672ebbe00SHans Petter Selasky #define sg_is_chain(sg) ((sg)->page_link & SG_PAGE_LINK_CHAIN)
8772ebbe00SHans Petter Selasky #define sg_is_last(sg) ((sg)->page_link & SG_PAGE_LINK_LAST)
888306998fSHans Petter Selasky #define sg_chain_ptr(sg) \
8972ebbe00SHans Petter Selasky ((struct scatterlist *) ((sg)->page_link & ~SG_PAGE_LINK_MASK))
908306998fSHans Petter Selasky
91f211d536STycho Nightingale #define sg_dma_address(sg) (sg)->dma_address
92442d12d8SHans Petter Selasky #define sg_dma_len(sg) (sg)->length
938d59ecb2SHans Petter Selasky
948306998fSHans Petter Selasky #define for_each_sg_page(sgl, iter, nents, pgoffset) \
958306998fSHans Petter Selasky for (_sg_iter_init(sgl, iter, nents, pgoffset); \
968306998fSHans Petter Selasky (iter)->sg; _sg_iter_next(iter))
97fe4b041aSHans Petter Selasky #define for_each_sg_dma_page(sgl, iter, nents, pgoffset) \
98fe4b041aSHans Petter Selasky for_each_sg_page(sgl, &(iter)->base, nents, pgoffset)
998306998fSHans Petter Selasky
1008306998fSHans Petter Selasky #define for_each_sg(sglist, sg, sgmax, iter) \
1018306998fSHans Petter Selasky for (iter = 0, sg = (sglist); iter < (sgmax); iter++, sg = sg_next(sg))
1028306998fSHans Petter Selasky
1034370e9f1SEmmanuel Vadot #define for_each_sgtable_sg(sgt, sg, i) \
1044370e9f1SEmmanuel Vadot for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i)
1054370e9f1SEmmanuel Vadot
1064370e9f1SEmmanuel Vadot #define for_each_sgtable_page(sgt, iter, pgoffset) \
1074370e9f1SEmmanuel Vadot for_each_sg_page((sgt)->sgl, iter, (sgt)->orig_nents, pgoffset)
1084370e9f1SEmmanuel Vadot
1091aca8a6eSEmmanuel Vadot #define for_each_sgtable_dma_sg(sgt, sg, iter) \
1101aca8a6eSEmmanuel Vadot for_each_sg((sgt)->sgl, sg, (sgt)->nents, iter)
1111aca8a6eSEmmanuel Vadot
1121aca8a6eSEmmanuel Vadot #define for_each_sgtable_dma_page(sgt, iter, pgoffset) \
1131aca8a6eSEmmanuel Vadot for_each_sg_dma_page((sgt)->sgl, iter, (sgt)->nents, pgoffset)
1141aca8a6eSEmmanuel Vadot
1158306998fSHans Petter Selasky typedef struct scatterlist *(sg_alloc_fn) (unsigned int, gfp_t);
1168306998fSHans Petter Selasky typedef void (sg_free_fn) (struct scatterlist *, unsigned int);
1178306998fSHans Petter Selasky
1188306998fSHans Petter Selasky static inline void
sg_assign_page(struct scatterlist * sg,struct page * page)1198306998fSHans Petter Selasky sg_assign_page(struct scatterlist *sg, struct page *page)
1208306998fSHans Petter Selasky {
12172ebbe00SHans Petter Selasky unsigned long page_link = sg->page_link & SG_PAGE_LINK_MASK;
1228306998fSHans Petter Selasky
1238306998fSHans Petter Selasky sg->page_link = page_link | (unsigned long)page;
1248306998fSHans Petter Selasky }
1258d59ecb2SHans Petter Selasky
1268d59ecb2SHans Petter Selasky static inline void
sg_set_page(struct scatterlist * sg,struct page * page,unsigned int len,unsigned int offset)1278d59ecb2SHans Petter Selasky sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len,
1288d59ecb2SHans Petter Selasky unsigned int offset)
1298d59ecb2SHans Petter Selasky {
1308306998fSHans Petter Selasky sg_assign_page(sg, page);
1318d59ecb2SHans Petter Selasky sg->offset = offset;
1328306998fSHans Petter Selasky sg->length = len;
1338306998fSHans Petter Selasky }
1348306998fSHans Petter Selasky
1358306998fSHans Petter Selasky static inline struct page *
sg_page(struct scatterlist * sg)1368306998fSHans Petter Selasky sg_page(struct scatterlist *sg)
1378306998fSHans Petter Selasky {
13872ebbe00SHans Petter Selasky return ((struct page *)((sg)->page_link & ~SG_PAGE_LINK_MASK));
1398d59ecb2SHans Petter Selasky }
1408d59ecb2SHans Petter Selasky
1418d59ecb2SHans Petter Selasky static inline void
sg_set_buf(struct scatterlist * sg,const void * buf,unsigned int buflen)1428d59ecb2SHans Petter Selasky sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen)
1438d59ecb2SHans Petter Selasky {
1448d59ecb2SHans Petter Selasky sg_set_page(sg, virt_to_page(buf), buflen,
1458d59ecb2SHans Petter Selasky ((uintptr_t)buf) & (PAGE_SIZE - 1));
1468d59ecb2SHans Petter Selasky }
1478d59ecb2SHans Petter Selasky
1488d59ecb2SHans Petter Selasky static inline struct scatterlist *
sg_next(struct scatterlist * sg)1498d59ecb2SHans Petter Selasky sg_next(struct scatterlist *sg)
1508d59ecb2SHans Petter Selasky {
1518306998fSHans Petter Selasky if (sg_is_last(sg))
1528d59ecb2SHans Petter Selasky return (NULL);
1538d59ecb2SHans Petter Selasky sg++;
1548306998fSHans Petter Selasky if (sg_is_chain(sg))
1558306998fSHans Petter Selasky sg = sg_chain_ptr(sg);
1568d59ecb2SHans Petter Selasky return (sg);
1578d59ecb2SHans Petter Selasky }
1588d59ecb2SHans Petter Selasky
1598d59ecb2SHans Petter Selasky static inline vm_paddr_t
sg_phys(struct scatterlist * sg)1608d59ecb2SHans Petter Selasky sg_phys(struct scatterlist *sg)
1618d59ecb2SHans Petter Selasky {
162d1ea0764SBjoern A. Zeeb return (page_to_phys(sg_page(sg)) + sg->offset);
1638d59ecb2SHans Petter Selasky }
1648d59ecb2SHans Petter Selasky
165998f22ebSHans Petter Selasky static inline void *
sg_virt(struct scatterlist * sg)166998f22ebSHans Petter Selasky sg_virt(struct scatterlist *sg)
167998f22ebSHans Petter Selasky {
168998f22ebSHans Petter Selasky
169998f22ebSHans Petter Selasky return ((void *)((unsigned long)page_address(sg_page(sg)) + sg->offset));
170998f22ebSHans Petter Selasky }
171998f22ebSHans Petter Selasky
1728d59ecb2SHans Petter Selasky static inline void
sg_chain(struct scatterlist * prv,unsigned int prv_nents,struct scatterlist * sgl)1738d59ecb2SHans Petter Selasky sg_chain(struct scatterlist *prv, unsigned int prv_nents,
1748d59ecb2SHans Petter Selasky struct scatterlist *sgl)
1758d59ecb2SHans Petter Selasky {
1768d59ecb2SHans Petter Selasky struct scatterlist *sg = &prv[prv_nents - 1];
1778d59ecb2SHans Petter Selasky
1788d59ecb2SHans Petter Selasky sg->offset = 0;
1798d59ecb2SHans Petter Selasky sg->length = 0;
18072ebbe00SHans Petter Selasky sg->page_link = ((unsigned long)sgl |
18172ebbe00SHans Petter Selasky SG_PAGE_LINK_CHAIN) & ~SG_PAGE_LINK_LAST;
1828d59ecb2SHans Petter Selasky }
1838d59ecb2SHans Petter Selasky
1848d59ecb2SHans Petter Selasky static inline void
sg_mark_end(struct scatterlist * sg)1858d59ecb2SHans Petter Selasky sg_mark_end(struct scatterlist *sg)
1868d59ecb2SHans Petter Selasky {
18772ebbe00SHans Petter Selasky sg->page_link |= SG_PAGE_LINK_LAST;
18872ebbe00SHans Petter Selasky sg->page_link &= ~SG_PAGE_LINK_CHAIN;
1898d59ecb2SHans Petter Selasky }
1908d59ecb2SHans Petter Selasky
1918d59ecb2SHans Petter Selasky static inline void
sg_init_table(struct scatterlist * sg,unsigned int nents)1928306998fSHans Petter Selasky sg_init_table(struct scatterlist *sg, unsigned int nents)
1938306998fSHans Petter Selasky {
1948306998fSHans Petter Selasky bzero(sg, sizeof(*sg) * nents);
1958306998fSHans Petter Selasky sg_mark_end(&sg[nents - 1]);
1968306998fSHans Petter Selasky }
1978306998fSHans Petter Selasky
1982686b10dSAlex Richardson static inline void
sg_init_one(struct scatterlist * sg,const void * buf,unsigned int buflen)1992686b10dSAlex Richardson sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
2002686b10dSAlex Richardson {
2012686b10dSAlex Richardson sg_init_table(sg, 1);
2022686b10dSAlex Richardson sg_set_buf(sg, buf, buflen);
2032686b10dSAlex Richardson }
2042686b10dSAlex Richardson
2058306998fSHans Petter Selasky static struct scatterlist *
sg_kmalloc(unsigned int nents,gfp_t gfp_mask)2068306998fSHans Petter Selasky sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
2078306998fSHans Petter Selasky {
2088306998fSHans Petter Selasky if (nents == SG_MAX_SINGLE_ALLOC) {
2098306998fSHans Petter Selasky return ((void *)__get_free_page(gfp_mask));
2108306998fSHans Petter Selasky } else
2118306998fSHans Petter Selasky return (kmalloc(nents * sizeof(struct scatterlist), gfp_mask));
2128306998fSHans Petter Selasky }
2138306998fSHans Petter Selasky
2148306998fSHans Petter Selasky static inline void
sg_kfree(struct scatterlist * sg,unsigned int nents)2158306998fSHans Petter Selasky sg_kfree(struct scatterlist *sg, unsigned int nents)
2168306998fSHans Petter Selasky {
2178306998fSHans Petter Selasky if (nents == SG_MAX_SINGLE_ALLOC) {
2188306998fSHans Petter Selasky free_page((unsigned long)sg);
2198306998fSHans Petter Selasky } else
2208306998fSHans Petter Selasky kfree(sg);
2218306998fSHans Petter Selasky }
2228306998fSHans Petter Selasky
2238306998fSHans Petter Selasky static inline void
__sg_free_table(struct sg_table * table,unsigned int max_ents,bool skip_first_chunk,sg_free_fn * free_fn)2248306998fSHans Petter Selasky __sg_free_table(struct sg_table *table, unsigned int max_ents,
2258306998fSHans Petter Selasky bool skip_first_chunk, sg_free_fn * free_fn)
2268d59ecb2SHans Petter Selasky {
2278d59ecb2SHans Petter Selasky struct scatterlist *sgl, *next;
2288d59ecb2SHans Petter Selasky
2298d59ecb2SHans Petter Selasky if (unlikely(!table->sgl))
2308d59ecb2SHans Petter Selasky return;
2318d59ecb2SHans Petter Selasky
2328d59ecb2SHans Petter Selasky sgl = table->sgl;
2338d59ecb2SHans Petter Selasky while (table->orig_nents) {
2348d59ecb2SHans Petter Selasky unsigned int alloc_size = table->orig_nents;
2358d59ecb2SHans Petter Selasky unsigned int sg_size;
2368d59ecb2SHans Petter Selasky
2378d59ecb2SHans Petter Selasky if (alloc_size > max_ents) {
2388306998fSHans Petter Selasky next = sg_chain_ptr(&sgl[max_ents - 1]);
2398d59ecb2SHans Petter Selasky alloc_size = max_ents;
2408d59ecb2SHans Petter Selasky sg_size = alloc_size - 1;
2418d59ecb2SHans Petter Selasky } else {
2428d59ecb2SHans Petter Selasky sg_size = alloc_size;
2438d59ecb2SHans Petter Selasky next = NULL;
2448d59ecb2SHans Petter Selasky }
2458d59ecb2SHans Petter Selasky
2468d59ecb2SHans Petter Selasky table->orig_nents -= sg_size;
2478306998fSHans Petter Selasky if (skip_first_chunk)
2488306998fSHans Petter Selasky skip_first_chunk = 0;
2498306998fSHans Petter Selasky else
2508306998fSHans Petter Selasky free_fn(sgl, alloc_size);
2518d59ecb2SHans Petter Selasky sgl = next;
2528d59ecb2SHans Petter Selasky }
2538d59ecb2SHans Petter Selasky
2548d59ecb2SHans Petter Selasky table->sgl = NULL;
2558d59ecb2SHans Petter Selasky }
2568d59ecb2SHans Petter Selasky
2578d59ecb2SHans Petter Selasky static inline void
sg_free_table(struct sg_table * table)2588d59ecb2SHans Petter Selasky sg_free_table(struct sg_table *table)
2598d59ecb2SHans Petter Selasky {
2608306998fSHans Petter Selasky __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
2618d59ecb2SHans Petter Selasky }
2628d59ecb2SHans Petter Selasky
2638d59ecb2SHans Petter Selasky static inline int
__sg_alloc_table(struct sg_table * table,unsigned int nents,unsigned int max_ents,struct scatterlist * first_chunk,gfp_t gfp_mask,sg_alloc_fn * alloc_fn)2648d59ecb2SHans Petter Selasky __sg_alloc_table(struct sg_table *table, unsigned int nents,
2658306998fSHans Petter Selasky unsigned int max_ents, struct scatterlist *first_chunk,
2668306998fSHans Petter Selasky gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
2678d59ecb2SHans Petter Selasky {
2688d59ecb2SHans Petter Selasky struct scatterlist *sg, *prv;
2698d59ecb2SHans Petter Selasky unsigned int left;
2708d59ecb2SHans Petter Selasky
2718d59ecb2SHans Petter Selasky memset(table, 0, sizeof(*table));
2728d59ecb2SHans Petter Selasky
2738d59ecb2SHans Petter Selasky if (nents == 0)
2748306998fSHans Petter Selasky return (-EINVAL);
2758d59ecb2SHans Petter Selasky left = nents;
2768d59ecb2SHans Petter Selasky prv = NULL;
2778d59ecb2SHans Petter Selasky do {
2788d59ecb2SHans Petter Selasky unsigned int sg_size;
2798d59ecb2SHans Petter Selasky unsigned int alloc_size = left;
2808d59ecb2SHans Petter Selasky
2818d59ecb2SHans Petter Selasky if (alloc_size > max_ents) {
2828d59ecb2SHans Petter Selasky alloc_size = max_ents;
2838d59ecb2SHans Petter Selasky sg_size = alloc_size - 1;
2848d59ecb2SHans Petter Selasky } else
2858d59ecb2SHans Petter Selasky sg_size = alloc_size;
2868d59ecb2SHans Petter Selasky
2878d59ecb2SHans Petter Selasky left -= sg_size;
2888d59ecb2SHans Petter Selasky
2898306998fSHans Petter Selasky if (first_chunk) {
2908306998fSHans Petter Selasky sg = first_chunk;
2918306998fSHans Petter Selasky first_chunk = NULL;
2928306998fSHans Petter Selasky } else {
2938306998fSHans Petter Selasky sg = alloc_fn(alloc_size, gfp_mask);
2948306998fSHans Petter Selasky }
2958d59ecb2SHans Petter Selasky if (unlikely(!sg)) {
2968d59ecb2SHans Petter Selasky if (prv)
2978d59ecb2SHans Petter Selasky table->nents = ++table->orig_nents;
2988d59ecb2SHans Petter Selasky
2998306998fSHans Petter Selasky return (-ENOMEM);
3008d59ecb2SHans Petter Selasky }
3018d59ecb2SHans Petter Selasky sg_init_table(sg, alloc_size);
3028d59ecb2SHans Petter Selasky table->nents = table->orig_nents += sg_size;
3038d59ecb2SHans Petter Selasky
3048d59ecb2SHans Petter Selasky if (prv)
3058d59ecb2SHans Petter Selasky sg_chain(prv, max_ents, sg);
3068d59ecb2SHans Petter Selasky else
3078d59ecb2SHans Petter Selasky table->sgl = sg;
3088d59ecb2SHans Petter Selasky
3098d59ecb2SHans Petter Selasky if (!left)
3108d59ecb2SHans Petter Selasky sg_mark_end(&sg[sg_size - 1]);
3118d59ecb2SHans Petter Selasky
3128d59ecb2SHans Petter Selasky prv = sg;
3138d59ecb2SHans Petter Selasky } while (left);
3148d59ecb2SHans Petter Selasky
3158306998fSHans Petter Selasky return (0);
3168d59ecb2SHans Petter Selasky }
3178d59ecb2SHans Petter Selasky
3188d59ecb2SHans Petter Selasky static inline int
sg_alloc_table(struct sg_table * table,unsigned int nents,gfp_t gfp_mask)3198d59ecb2SHans Petter Selasky sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
3208d59ecb2SHans Petter Selasky {
3218d59ecb2SHans Petter Selasky int ret;
3228d59ecb2SHans Petter Selasky
3238d59ecb2SHans Petter Selasky ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
3248306998fSHans Petter Selasky NULL, gfp_mask, sg_kmalloc);
3258d59ecb2SHans Petter Selasky if (unlikely(ret))
3268306998fSHans Petter Selasky __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
3278d59ecb2SHans Petter Selasky
3288306998fSHans Petter Selasky return (ret);
3298306998fSHans Petter Selasky }
3308306998fSHans Petter Selasky
3313e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3323e0856b6SJean-Sébastien Pédron static inline struct scatterlist *
__sg_alloc_table_from_pages(struct sg_table * sgt,struct page ** pages,unsigned int count,unsigned long off,unsigned long size,unsigned int max_segment,struct scatterlist * prv,unsigned int left_pages,gfp_t gfp_mask)3333e0856b6SJean-Sébastien Pédron __sg_alloc_table_from_pages(struct sg_table *sgt,
3343e0856b6SJean-Sébastien Pédron struct page **pages, unsigned int count,
3353e0856b6SJean-Sébastien Pédron unsigned long off, unsigned long size,
3363e0856b6SJean-Sébastien Pédron unsigned int max_segment,
3373e0856b6SJean-Sébastien Pédron struct scatterlist *prv, unsigned int left_pages,
3383e0856b6SJean-Sébastien Pédron gfp_t gfp_mask)
3393e0856b6SJean-Sébastien Pédron #else
3408306998fSHans Petter Selasky static inline int
34157a865f8SHans Petter Selasky __sg_alloc_table_from_pages(struct sg_table *sgt,
3428306998fSHans Petter Selasky struct page **pages, unsigned int count,
3438306998fSHans Petter Selasky unsigned long off, unsigned long size,
34457a865f8SHans Petter Selasky unsigned int max_segment, gfp_t gfp_mask)
3453e0856b6SJean-Sébastien Pédron #endif
3468306998fSHans Petter Selasky {
34757a865f8SHans Petter Selasky unsigned int i, segs, cur, len;
3488306998fSHans Petter Selasky int rc;
34909b0401eSAustin Shafer struct scatterlist *s, *sg_iter;
3508306998fSHans Petter Selasky
3513e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3523e0856b6SJean-Sébastien Pédron if (prv != NULL) {
3533e0856b6SJean-Sébastien Pédron panic(
3543e0856b6SJean-Sébastien Pédron "Support for prv != NULL not implemented in "
3553e0856b6SJean-Sébastien Pédron "__sg_alloc_table_from_pages()");
3563e0856b6SJean-Sébastien Pédron }
3573e0856b6SJean-Sébastien Pédron #endif
3583e0856b6SJean-Sébastien Pédron
35957a865f8SHans Petter Selasky if (__predict_false(!max_segment || offset_in_page(max_segment)))
3603e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3613e0856b6SJean-Sébastien Pédron return (ERR_PTR(-EINVAL));
3623e0856b6SJean-Sébastien Pédron #else
36357a865f8SHans Petter Selasky return (-EINVAL);
3643e0856b6SJean-Sébastien Pédron #endif
36557a865f8SHans Petter Selasky
36657a865f8SHans Petter Selasky len = 0;
3678306998fSHans Petter Selasky for (segs = i = 1; i < count; ++i) {
36857a865f8SHans Petter Selasky len += PAGE_SIZE;
36957a865f8SHans Petter Selasky if (len >= max_segment ||
37057a865f8SHans Petter Selasky page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
3718306998fSHans Petter Selasky ++segs;
37257a865f8SHans Petter Selasky len = 0;
37357a865f8SHans Petter Selasky }
3748306998fSHans Petter Selasky }
3758306998fSHans Petter Selasky if (__predict_false((rc = sg_alloc_table(sgt, segs, gfp_mask))))
3763e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3773e0856b6SJean-Sébastien Pédron return (ERR_PTR(rc));
3783e0856b6SJean-Sébastien Pédron #else
3798306998fSHans Petter Selasky return (rc);
3803e0856b6SJean-Sébastien Pédron #endif
3818306998fSHans Petter Selasky
3828306998fSHans Petter Selasky cur = 0;
38309b0401eSAustin Shafer for_each_sg(sgt->sgl, sg_iter, sgt->orig_nents, i) {
3848306998fSHans Petter Selasky unsigned long seg_size;
3858306998fSHans Petter Selasky unsigned int j;
3868306998fSHans Petter Selasky
38709b0401eSAustin Shafer /*
38809b0401eSAustin Shafer * We need to make sure that when we exit this loop "s" has the
38909b0401eSAustin Shafer * last sg in the chain so we can call sg_mark_end() on it.
39009b0401eSAustin Shafer * Only set this inside the loop since sg_iter will be iterated
39109b0401eSAustin Shafer * until it is NULL.
39209b0401eSAustin Shafer */
39309b0401eSAustin Shafer s = sg_iter;
39409b0401eSAustin Shafer
39557a865f8SHans Petter Selasky len = 0;
39657a865f8SHans Petter Selasky for (j = cur + 1; j < count; ++j) {
39757a865f8SHans Petter Selasky len += PAGE_SIZE;
39857a865f8SHans Petter Selasky if (len >= max_segment || page_to_pfn(pages[j]) !=
3998306998fSHans Petter Selasky page_to_pfn(pages[j - 1]) + 1)
4008306998fSHans Petter Selasky break;
40157a865f8SHans Petter Selasky }
4028306998fSHans Petter Selasky
4038306998fSHans Petter Selasky seg_size = ((j - cur) << PAGE_SHIFT) - off;
404a399cf13SHans Petter Selasky sg_set_page(s, pages[cur], MIN(size, seg_size), off);
4058306998fSHans Petter Selasky size -= seg_size;
4068306998fSHans Petter Selasky off = 0;
4078306998fSHans Petter Selasky cur = j;
4088306998fSHans Petter Selasky }
4093e0856b6SJean-Sébastien Pédron KASSERT(s != NULL, ("s is NULL after loop in __sg_alloc_table_from_pages()"));
4103e0856b6SJean-Sébastien Pédron
4113e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
4123e0856b6SJean-Sébastien Pédron if (left_pages == 0)
4133e0856b6SJean-Sébastien Pédron sg_mark_end(s);
4143e0856b6SJean-Sébastien Pédron
4153e0856b6SJean-Sébastien Pédron return (s);
4163e0856b6SJean-Sébastien Pédron #else
4178306998fSHans Petter Selasky return (0);
4183e0856b6SJean-Sébastien Pédron #endif
4198306998fSHans Petter Selasky }
4208306998fSHans Petter Selasky
42157a865f8SHans Petter Selasky static inline int
sg_alloc_table_from_pages(struct sg_table * sgt,struct page ** pages,unsigned int count,unsigned long off,unsigned long size,gfp_t gfp_mask)42257a865f8SHans Petter Selasky sg_alloc_table_from_pages(struct sg_table *sgt,
42357a865f8SHans Petter Selasky struct page **pages, unsigned int count,
42457a865f8SHans Petter Selasky unsigned long off, unsigned long size,
42557a865f8SHans Petter Selasky gfp_t gfp_mask)
42657a865f8SHans Petter Selasky {
42757a865f8SHans Petter Selasky
4283e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
4293e0856b6SJean-Sébastien Pédron return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
4303e0856b6SJean-Sébastien Pédron SCATTERLIST_MAX_SEGMENT, NULL, 0, gfp_mask)));
4313e0856b6SJean-Sébastien Pédron #else
43257a865f8SHans Petter Selasky return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
43357a865f8SHans Petter Selasky SCATTERLIST_MAX_SEGMENT, gfp_mask));
4343e0856b6SJean-Sébastien Pédron #endif
43557a865f8SHans Petter Selasky }
4368306998fSHans Petter Selasky
4378306998fSHans Petter Selasky static inline int
sg_alloc_table_from_pages_segment(struct sg_table * sgt,struct page ** pages,unsigned int count,unsigned int off,unsigned long size,unsigned int max_segment,gfp_t gfp_mask)438f3490083SJean-Sébastien Pédron sg_alloc_table_from_pages_segment(struct sg_table *sgt,
439f3490083SJean-Sébastien Pédron struct page **pages, unsigned int count, unsigned int off,
440f3490083SJean-Sébastien Pédron unsigned long size, unsigned int max_segment, gfp_t gfp_mask)
441f3490083SJean-Sébastien Pédron {
442f3490083SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
443f3490083SJean-Sébastien Pédron return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
444f3490083SJean-Sébastien Pédron max_segment, NULL, 0, gfp_mask)));
445f3490083SJean-Sébastien Pédron #else
446f3490083SJean-Sébastien Pédron return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
447f3490083SJean-Sébastien Pédron max_segment, gfp_mask));
448f3490083SJean-Sébastien Pédron #endif
449f3490083SJean-Sébastien Pédron }
450f3490083SJean-Sébastien Pédron
451f3490083SJean-Sébastien Pédron static inline int
sg_nents(struct scatterlist * sg)4528306998fSHans Petter Selasky sg_nents(struct scatterlist *sg)
4538306998fSHans Petter Selasky {
4548306998fSHans Petter Selasky int nents;
4558306998fSHans Petter Selasky
4568306998fSHans Petter Selasky for (nents = 0; sg; sg = sg_next(sg))
4578306998fSHans Petter Selasky nents++;
4588306998fSHans Petter Selasky return (nents);
4598306998fSHans Petter Selasky }
4608306998fSHans Petter Selasky
4618306998fSHans Petter Selasky static inline void
__sg_page_iter_start(struct sg_page_iter * piter,struct scatterlist * sglist,unsigned int nents,unsigned long pgoffset)4628306998fSHans Petter Selasky __sg_page_iter_start(struct sg_page_iter *piter,
4638306998fSHans Petter Selasky struct scatterlist *sglist, unsigned int nents,
4648306998fSHans Petter Selasky unsigned long pgoffset)
4658306998fSHans Petter Selasky {
4668306998fSHans Petter Selasky piter->internal.pg_advance = 0;
4678306998fSHans Petter Selasky piter->internal.nents = nents;
4688306998fSHans Petter Selasky
4698306998fSHans Petter Selasky piter->sg = sglist;
4708306998fSHans Petter Selasky piter->sg_pgoffset = pgoffset;
4718d59ecb2SHans Petter Selasky }
4728d59ecb2SHans Petter Selasky
4738d59ecb2SHans Petter Selasky static inline void
_sg_iter_next(struct sg_page_iter * iter)4748d59ecb2SHans Petter Selasky _sg_iter_next(struct sg_page_iter *iter)
4758d59ecb2SHans Petter Selasky {
4768d59ecb2SHans Petter Selasky struct scatterlist *sg;
4778d59ecb2SHans Petter Selasky unsigned int pgcount;
4788d59ecb2SHans Petter Selasky
4798d59ecb2SHans Petter Selasky sg = iter->sg;
4808d59ecb2SHans Petter Selasky pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
4818d59ecb2SHans Petter Selasky
4828d59ecb2SHans Petter Selasky ++iter->sg_pgoffset;
4838d59ecb2SHans Petter Selasky while (iter->sg_pgoffset >= pgcount) {
4848d59ecb2SHans Petter Selasky iter->sg_pgoffset -= pgcount;
4858d59ecb2SHans Petter Selasky sg = sg_next(sg);
4868d59ecb2SHans Petter Selasky --iter->maxents;
4878d59ecb2SHans Petter Selasky if (sg == NULL || iter->maxents == 0)
4888d59ecb2SHans Petter Selasky break;
4898d59ecb2SHans Petter Selasky pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
4908d59ecb2SHans Petter Selasky }
4918d59ecb2SHans Petter Selasky iter->sg = sg;
4928d59ecb2SHans Petter Selasky }
4938d59ecb2SHans Petter Selasky
4948306998fSHans Petter Selasky static inline int
sg_page_count(struct scatterlist * sg)4958306998fSHans Petter Selasky sg_page_count(struct scatterlist *sg)
4968306998fSHans Petter Selasky {
4978306998fSHans Petter Selasky return (PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT);
4988306998fSHans Petter Selasky }
499fe4b041aSHans Petter Selasky #define sg_dma_page_count(sg) \
500fe4b041aSHans Petter Selasky sg_page_count(sg)
5018306998fSHans Petter Selasky
5028306998fSHans Petter Selasky static inline bool
__sg_page_iter_next(struct sg_page_iter * piter)5038306998fSHans Petter Selasky __sg_page_iter_next(struct sg_page_iter *piter)
5048306998fSHans Petter Selasky {
5055e6233ccSHans Petter Selasky unsigned int pgcount;
5065e6233ccSHans Petter Selasky
5078306998fSHans Petter Selasky if (piter->internal.nents == 0)
5088306998fSHans Petter Selasky return (0);
5098306998fSHans Petter Selasky if (piter->sg == NULL)
5108306998fSHans Petter Selasky return (0);
5118306998fSHans Petter Selasky
5128306998fSHans Petter Selasky piter->sg_pgoffset += piter->internal.pg_advance;
5138306998fSHans Petter Selasky piter->internal.pg_advance = 1;
5148306998fSHans Petter Selasky
5155e6233ccSHans Petter Selasky while (1) {
5165e6233ccSHans Petter Selasky pgcount = sg_page_count(piter->sg);
5175e6233ccSHans Petter Selasky if (likely(piter->sg_pgoffset < pgcount))
5185e6233ccSHans Petter Selasky break;
5195e6233ccSHans Petter Selasky piter->sg_pgoffset -= pgcount;
5208306998fSHans Petter Selasky piter->sg = sg_next(piter->sg);
5218306998fSHans Petter Selasky if (--piter->internal.nents == 0)
5228306998fSHans Petter Selasky return (0);
5238306998fSHans Petter Selasky if (piter->sg == NULL)
5248306998fSHans Petter Selasky return (0);
5258306998fSHans Petter Selasky }
5268306998fSHans Petter Selasky return (1);
5278306998fSHans Petter Selasky }
528fe4b041aSHans Petter Selasky #define __sg_page_iter_dma_next(itr) \
529fe4b041aSHans Petter Selasky __sg_page_iter_next(&(itr)->base)
5308306998fSHans Petter Selasky
5318d59ecb2SHans Petter Selasky static inline void
_sg_iter_init(struct scatterlist * sgl,struct sg_page_iter * iter,unsigned int nents,unsigned long pgoffset)5328d59ecb2SHans Petter Selasky _sg_iter_init(struct scatterlist *sgl, struct sg_page_iter *iter,
5338d59ecb2SHans Petter Selasky unsigned int nents, unsigned long pgoffset)
5348d59ecb2SHans Petter Selasky {
5358d59ecb2SHans Petter Selasky if (nents) {
5368d59ecb2SHans Petter Selasky iter->sg = sgl;
5378d59ecb2SHans Petter Selasky iter->sg_pgoffset = pgoffset - 1;
5388d59ecb2SHans Petter Selasky iter->maxents = nents;
5398d59ecb2SHans Petter Selasky _sg_iter_next(iter);
5408d59ecb2SHans Petter Selasky } else {
5418d59ecb2SHans Petter Selasky iter->sg = NULL;
5428d59ecb2SHans Petter Selasky iter->sg_pgoffset = 0;
5438d59ecb2SHans Petter Selasky iter->maxents = 0;
5448d59ecb2SHans Petter Selasky }
5458d59ecb2SHans Petter Selasky }
5468d59ecb2SHans Petter Selasky
547fe4b041aSHans Petter Selasky /*
548fe4b041aSHans Petter Selasky * sg_page_iter_dma_address() is implemented as a macro because it
549fe4b041aSHans Petter Selasky * needs to accept two different and identical structure types. This
550fe4b041aSHans Petter Selasky * allows both old and new code to co-exist. The compile time assert
551fe4b041aSHans Petter Selasky * adds some safety, that the structure sizes match.
552fe4b041aSHans Petter Selasky */
553fe4b041aSHans Petter Selasky #define sg_page_iter_dma_address(spi) ({ \
554fe4b041aSHans Petter Selasky struct sg_page_iter *__spi = (void *)(spi); \
555fe4b041aSHans Petter Selasky dma_addr_t __dma_address; \
556fe4b041aSHans Petter Selasky CTASSERT(sizeof(*(spi)) == sizeof(*__spi)); \
557fe4b041aSHans Petter Selasky __dma_address = __spi->sg->dma_address + \
558fe4b041aSHans Petter Selasky (__spi->sg_pgoffset << PAGE_SHIFT); \
559fe4b041aSHans Petter Selasky __dma_address; \
560fe4b041aSHans Petter Selasky })
5618d59ecb2SHans Petter Selasky
5628306998fSHans Petter Selasky static inline struct page *
sg_page_iter_page(struct sg_page_iter * piter)5638306998fSHans Petter Selasky sg_page_iter_page(struct sg_page_iter *piter)
5648306998fSHans Petter Selasky {
5658306998fSHans Petter Selasky return (nth_page(sg_page(piter->sg), piter->sg_pgoffset));
5668306998fSHans Petter Selasky }
5678d59ecb2SHans Petter Selasky
5684abbf816SBjoern A. Zeeb static __inline size_t
sg_pcopy_from_buffer(struct scatterlist * sgl,unsigned int nents,const void * buf,size_t buflen,off_t skip)5694abbf816SBjoern A. Zeeb sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents,
5704abbf816SBjoern A. Zeeb const void *buf, size_t buflen, off_t skip)
5714abbf816SBjoern A. Zeeb {
5724abbf816SBjoern A. Zeeb struct sg_page_iter piter;
5734abbf816SBjoern A. Zeeb struct page *page;
5744abbf816SBjoern A. Zeeb struct sf_buf *sf;
5754abbf816SBjoern A. Zeeb size_t len, copied;
5764abbf816SBjoern A. Zeeb char *p, *b;
5774abbf816SBjoern A. Zeeb
5784abbf816SBjoern A. Zeeb if (buflen == 0)
5794abbf816SBjoern A. Zeeb return (0);
5804abbf816SBjoern A. Zeeb
5814abbf816SBjoern A. Zeeb b = __DECONST(char *, buf);
5824abbf816SBjoern A. Zeeb copied = 0;
5834abbf816SBjoern A. Zeeb sched_pin();
5844abbf816SBjoern A. Zeeb for_each_sg_page(sgl, &piter, nents, 0) {
5854abbf816SBjoern A. Zeeb
5864abbf816SBjoern A. Zeeb /* Skip to the start. */
5874abbf816SBjoern A. Zeeb if (piter.sg->length <= skip) {
5884abbf816SBjoern A. Zeeb skip -= piter.sg->length;
5894abbf816SBjoern A. Zeeb continue;
5904abbf816SBjoern A. Zeeb }
5914abbf816SBjoern A. Zeeb
5924abbf816SBjoern A. Zeeb /* See how much to copy. */
5934abbf816SBjoern A. Zeeb KASSERT(((piter.sg->length - skip) != 0 && (buflen != 0)),
5944abbf816SBjoern A. Zeeb ("%s: sg len %u - skip %ju || buflen %zu is 0\n",
5954abbf816SBjoern A. Zeeb __func__, piter.sg->length, (uintmax_t)skip, buflen));
5964abbf816SBjoern A. Zeeb len = min(piter.sg->length - skip, buflen);
5974abbf816SBjoern A. Zeeb
5984abbf816SBjoern A. Zeeb page = sg_page_iter_page(&piter);
5994abbf816SBjoern A. Zeeb sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
6004abbf816SBjoern A. Zeeb if (sf == NULL)
6014abbf816SBjoern A. Zeeb break;
6024abbf816SBjoern A. Zeeb p = (char *)sf_buf_kva(sf) + piter.sg_pgoffset + skip;
6034abbf816SBjoern A. Zeeb memcpy(p, b, len);
6044abbf816SBjoern A. Zeeb sf_buf_free(sf);
6054abbf816SBjoern A. Zeeb
606edfcdffeSBjoern A. Zeeb /* We copied so nothing more to skip. */
607edfcdffeSBjoern A. Zeeb skip = 0;
6084abbf816SBjoern A. Zeeb copied += len;
6094abbf816SBjoern A. Zeeb /* Either we exactly filled the page, or we are done. */
6104abbf816SBjoern A. Zeeb buflen -= len;
6114abbf816SBjoern A. Zeeb if (buflen == 0)
6124abbf816SBjoern A. Zeeb break;
6134abbf816SBjoern A. Zeeb b += len;
6144abbf816SBjoern A. Zeeb }
6154abbf816SBjoern A. Zeeb sched_unpin();
6164abbf816SBjoern A. Zeeb
6174abbf816SBjoern A. Zeeb return (copied);
6184abbf816SBjoern A. Zeeb }
6194abbf816SBjoern A. Zeeb
620c072f6e8SVladimir Kondratyev static inline size_t
sg_copy_from_buffer(struct scatterlist * sgl,unsigned int nents,const void * buf,size_t buflen)621c072f6e8SVladimir Kondratyev sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
622c072f6e8SVladimir Kondratyev const void *buf, size_t buflen)
623c072f6e8SVladimir Kondratyev {
624c072f6e8SVladimir Kondratyev return (sg_pcopy_from_buffer(sgl, nents, buf, buflen, 0));
625c072f6e8SVladimir Kondratyev }
626c072f6e8SVladimir Kondratyev
627c072f6e8SVladimir Kondratyev static inline size_t
sg_pcopy_to_buffer(struct scatterlist * sgl,unsigned int nents,void * buf,size_t buflen,off_t offset)628c072f6e8SVladimir Kondratyev sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
629c072f6e8SVladimir Kondratyev void *buf, size_t buflen, off_t offset)
630c072f6e8SVladimir Kondratyev {
631c072f6e8SVladimir Kondratyev struct sg_page_iter iter;
632c072f6e8SVladimir Kondratyev struct scatterlist *sg;
633c072f6e8SVladimir Kondratyev struct page *page;
634c072f6e8SVladimir Kondratyev struct sf_buf *sf;
635c072f6e8SVladimir Kondratyev char *vaddr;
636c072f6e8SVladimir Kondratyev size_t total = 0;
637c072f6e8SVladimir Kondratyev size_t len;
638c072f6e8SVladimir Kondratyev
639c072f6e8SVladimir Kondratyev if (!PMAP_HAS_DMAP)
640c072f6e8SVladimir Kondratyev sched_pin();
641c072f6e8SVladimir Kondratyev for_each_sg_page(sgl, &iter, nents, 0) {
642c072f6e8SVladimir Kondratyev sg = iter.sg;
643c072f6e8SVladimir Kondratyev
644c072f6e8SVladimir Kondratyev if (offset >= sg->length) {
645c072f6e8SVladimir Kondratyev offset -= sg->length;
646c072f6e8SVladimir Kondratyev continue;
647c072f6e8SVladimir Kondratyev }
648c072f6e8SVladimir Kondratyev len = ulmin(buflen, sg->length - offset);
649c072f6e8SVladimir Kondratyev if (len == 0)
650c072f6e8SVladimir Kondratyev break;
651c072f6e8SVladimir Kondratyev
652c072f6e8SVladimir Kondratyev page = sg_page_iter_page(&iter);
653c072f6e8SVladimir Kondratyev if (!PMAP_HAS_DMAP) {
654c072f6e8SVladimir Kondratyev sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
655c072f6e8SVladimir Kondratyev if (sf == NULL)
656c072f6e8SVladimir Kondratyev break;
657c072f6e8SVladimir Kondratyev vaddr = (char *)sf_buf_kva(sf);
658c072f6e8SVladimir Kondratyev } else
659d1ea0764SBjoern A. Zeeb vaddr = (char *)PHYS_TO_DMAP(page_to_phys(page));
660c072f6e8SVladimir Kondratyev memcpy(buf, vaddr + sg->offset + offset, len);
661c072f6e8SVladimir Kondratyev if (!PMAP_HAS_DMAP)
662c072f6e8SVladimir Kondratyev sf_buf_free(sf);
663c072f6e8SVladimir Kondratyev
664c072f6e8SVladimir Kondratyev /* start at beginning of next page */
665c072f6e8SVladimir Kondratyev offset = 0;
666c072f6e8SVladimir Kondratyev
667c072f6e8SVladimir Kondratyev /* advance buffer */
668c072f6e8SVladimir Kondratyev buf = (char *)buf + len;
669c072f6e8SVladimir Kondratyev buflen -= len;
670c072f6e8SVladimir Kondratyev total += len;
671c072f6e8SVladimir Kondratyev }
672c072f6e8SVladimir Kondratyev if (!PMAP_HAS_DMAP)
673c072f6e8SVladimir Kondratyev sched_unpin();
674c072f6e8SVladimir Kondratyev return (total);
675c072f6e8SVladimir Kondratyev }
676c072f6e8SVladimir Kondratyev
677307f78f3SVladimir Kondratyev #endif /* _LINUXKPI_LINUX_SCATTERLIST_H_ */
678