xref: /openbsd-src/sys/dev/pci/drm/include/linux/scatterlist.h (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: scatterlist.h,v 1.1 2019/04/14 10:14:53 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 struct scatterlist {
26 	dma_addr_t dma_address;
27 	unsigned int offset;
28 	unsigned int length;
29 	bool end;
30 };
31 
32 struct sg_table {
33 	struct scatterlist *sgl;
34 	unsigned int nents;
35 	unsigned int orig_nents;
36 };
37 
38 struct sg_page_iter {
39 	struct scatterlist *sg;
40 	unsigned int sg_pgoffset;
41 	unsigned int __nents;
42 };
43 
44 #define sg_is_chain(sg)		false
45 #define sg_is_last(sg)		((sg)->end)
46 #define sg_chain_ptr(sg)	NULL
47 
48 static inline struct scatterlist *
49 sg_next(struct scatterlist *sgl)
50 {
51 	return sg_is_last(sgl) ? NULL : ++sgl;
52 }
53 
54 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
55 void sg_free_table(struct sg_table *);
56 
57 static inline void
58 sg_mark_end(struct scatterlist *sgl)
59 {
60 	sgl->end = true;
61 }
62 
63 static inline void
64 __sg_page_iter_start(struct sg_page_iter *iter, struct scatterlist *sgl,
65     unsigned int nents, unsigned long pgoffset)
66 {
67 	iter->sg = sgl;
68 	iter->sg_pgoffset = pgoffset - 1;
69 	iter->__nents = nents;
70 }
71 
72 static inline bool
73 __sg_page_iter_next(struct sg_page_iter *iter)
74 {
75 	iter->sg_pgoffset++;
76 	while (iter->__nents > 0 &&
77 	    iter->sg_pgoffset >= (iter->sg->length / PAGE_SIZE)) {
78 		iter->sg_pgoffset -= (iter->sg->length / PAGE_SIZE);
79 		iter->sg++;
80 		iter->__nents--;
81 	}
82 
83 	return (iter->__nents > 0);
84 }
85 
86 static inline paddr_t
87 sg_page_iter_dma_address(struct sg_page_iter *iter)
88 {
89 	return iter->sg->dma_address + (iter->sg_pgoffset << PAGE_SHIFT);
90 }
91 
92 static inline struct vm_page *
93 sg_page_iter_page(struct sg_page_iter *iter)
94 {
95 	return PHYS_TO_VM_PAGE(sg_page_iter_dma_address(iter));
96 }
97 
98 static inline struct vm_page *
99 sg_page(struct scatterlist *sgl)
100 {
101 	return PHYS_TO_VM_PAGE(sgl->dma_address);
102 }
103 
104 static inline void
105 sg_set_page(struct scatterlist *sgl, struct vm_page *page,
106     unsigned int length, unsigned int offset)
107 {
108 	sgl->dma_address = VM_PAGE_TO_PHYS(page);
109 	sgl->offset = offset;
110 	sgl->length = length;
111 	sgl->end = false;
112 }
113 
114 #define sg_dma_address(sg)	((sg)->dma_address)
115 #define sg_dma_len(sg)		((sg)->length)
116 
117 #define for_each_sg(sgl, sg, nents, i) \
118   for (i = 0, sg = (sgl); i < (nents); i++, sg = sg_next(sg))
119 
120 #define for_each_sg_page(sgl, iter, nents, pgoffset) \
121   __sg_page_iter_start((iter), (sgl), (nents), (pgoffset)); \
122   while (__sg_page_iter_next(iter))
123 
124 size_t sg_copy_from_buffer(struct scatterlist *, unsigned int,
125     const void *, size_t);
126 
127 #endif
128