xref: /openbsd-src/sys/dev/pci/drm/include/linux/scatterlist.h (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: scatterlist.h,v 1.3 2020/06/11 11:28:12 jsg Exp $	*/
2 /*
3  * Copyright (c) 2013, 2014, 2015 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #ifndef _LINUX_SCATTERLIST_H
19 #define _LINUX_SCATTERLIST_H
20 
21 #include <sys/types.h>
22 #include <sys/param.h>
23 #include <uvm/uvm_extern.h>
24 
25 #include <linux/mm.h>
26 
27 struct scatterlist {
28 	struct vm_page *__page;
29 	dma_addr_t dma_address;
30 	unsigned int offset;
31 	unsigned int length;
32 	bool end;
33 };
34 
35 struct sg_table {
36 	struct scatterlist *sgl;
37 	unsigned int nents;
38 	unsigned int orig_nents;
39 };
40 
41 struct sg_page_iter {
42 	struct scatterlist *sg;
43 	unsigned int sg_pgoffset;
44 	unsigned int __nents;
45 };
46 
47 #define sg_is_chain(sg)		false
48 #define sg_is_last(sg)		((sg)->end)
49 #define sg_chain_ptr(sg)	NULL
50 
51 static inline struct scatterlist *
52 sg_next(struct scatterlist *sgl)
53 {
54 	return sg_is_last(sgl) ? NULL : ++sgl;
55 }
56 
57 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
58 void sg_free_table(struct sg_table *);
59 
60 static inline void
61 sg_mark_end(struct scatterlist *sgl)
62 {
63 	sgl->end = true;
64 }
65 
66 static inline void
67 __sg_page_iter_start(struct sg_page_iter *iter, struct scatterlist *sgl,
68     unsigned int nents, unsigned long pgoffset)
69 {
70 	iter->sg = sgl;
71 	iter->sg_pgoffset = pgoffset - 1;
72 	iter->__nents = nents;
73 }
74 
75 static inline bool
76 __sg_page_iter_next(struct sg_page_iter *iter)
77 {
78 	iter->sg_pgoffset++;
79 	while (iter->__nents > 0 &&
80 	    iter->sg_pgoffset >= (iter->sg->length / PAGE_SIZE)) {
81 		iter->sg_pgoffset -= (iter->sg->length / PAGE_SIZE);
82 		iter->sg++;
83 		iter->__nents--;
84 	}
85 
86 	return (iter->__nents > 0);
87 }
88 
89 static inline paddr_t
90 sg_page_iter_dma_address(struct sg_page_iter *iter)
91 {
92 	return iter->sg->dma_address + (iter->sg_pgoffset << PAGE_SHIFT);
93 }
94 
95 static inline struct vm_page *
96 sg_page_iter_page(struct sg_page_iter *iter)
97 {
98 	return PHYS_TO_VM_PAGE(sg_page_iter_dma_address(iter));
99 }
100 
101 static inline struct vm_page *
102 sg_page(struct scatterlist *sgl)
103 {
104 	return sgl->__page;
105 }
106 
107 static inline void
108 sg_assign_page(struct scatterlist *sgl, struct vm_page *page)
109 {
110 	sgl->__page = page;
111 }
112 
113 static inline void
114 sg_set_page(struct scatterlist *sgl, struct vm_page *page,
115     unsigned int length, unsigned int offset)
116 {
117 	sgl->__page = page;
118 	sgl->dma_address = page ? VM_PAGE_TO_PHYS(page) : 0;
119 	sgl->offset = offset;
120 	sgl->length = length;
121 	sgl->end = false;
122 }
123 
124 #define sg_dma_address(sg)	((sg)->dma_address)
125 #define sg_dma_len(sg)		((sg)->length)
126 
127 #define for_each_sg(sgl, sg, nents, i) \
128   for (i = 0, sg = (sgl); i < (nents); i++, sg = sg_next(sg))
129 
130 #define for_each_sg_page(sgl, iter, nents, pgoffset) \
131   __sg_page_iter_start((iter), (sgl), (nents), (pgoffset)); \
132   while (__sg_page_iter_next(iter))
133 
134 size_t sg_copy_from_buffer(struct scatterlist *, unsigned int,
135     const void *, size_t);
136 
137 #endif
138