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