xref: /openbsd/sys/dev/pci/drm/include/linux/scatterlist.h (revision 667382c7)
1 /*	$OpenBSD: scatterlist.h,v 1.7 2024/01/06 09:33:08 kettenis 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 	bus_dmamap_t dmamap;
41 };
42 
43 struct sg_page_iter {
44 	struct scatterlist *sg;
45 	unsigned int sg_pgoffset;
46 	unsigned int __nents;
47 };
48 
49 #define sg_is_chain(sg)		false
50 #define sg_is_last(sg)		((sg)->end)
51 #define sg_chain_ptr(sg)	NULL
52 
53 static inline struct scatterlist *
sg_next(struct scatterlist * sgl)54 sg_next(struct scatterlist *sgl)
55 {
56 	return sg_is_last(sgl) ? NULL : ++sgl;
57 }
58 
59 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
60 void sg_free_table(struct sg_table *);
61 
62 static inline void
sg_mark_end(struct scatterlist * sgl)63 sg_mark_end(struct scatterlist *sgl)
64 {
65 	sgl->end = true;
66 }
67 
68 static inline void
__sg_page_iter_start(struct sg_page_iter * iter,struct scatterlist * sgl,unsigned int nents,unsigned long pgoffset)69 __sg_page_iter_start(struct sg_page_iter *iter, struct scatterlist *sgl,
70     unsigned int nents, unsigned long pgoffset)
71 {
72 	iter->sg = sgl;
73 	iter->sg_pgoffset = pgoffset - 1;
74 	iter->__nents = nents;
75 }
76 
77 static inline bool
__sg_page_iter_next(struct sg_page_iter * iter)78 __sg_page_iter_next(struct sg_page_iter *iter)
79 {
80 	iter->sg_pgoffset++;
81 	while (iter->__nents > 0 &&
82 	    iter->sg_pgoffset >= (iter->sg->length / PAGE_SIZE)) {
83 		iter->sg_pgoffset -= (iter->sg->length / PAGE_SIZE);
84 		iter->sg++;
85 		iter->__nents--;
86 	}
87 
88 	return (iter->__nents > 0);
89 }
90 
91 static inline paddr_t
sg_page_iter_dma_address(struct sg_page_iter * iter)92 sg_page_iter_dma_address(struct sg_page_iter *iter)
93 {
94 	return iter->sg->dma_address + (iter->sg_pgoffset << PAGE_SHIFT);
95 }
96 
97 static inline struct vm_page *
sg_page_iter_page(struct sg_page_iter * iter)98 sg_page_iter_page(struct sg_page_iter *iter)
99 {
100 	return PHYS_TO_VM_PAGE(sg_page_iter_dma_address(iter));
101 }
102 
103 static inline struct vm_page *
sg_page(struct scatterlist * sgl)104 sg_page(struct scatterlist *sgl)
105 {
106 	return sgl->__page;
107 }
108 
109 static inline void
sg_assign_page(struct scatterlist * sgl,struct vm_page * page)110 sg_assign_page(struct scatterlist *sgl, struct vm_page *page)
111 {
112 	sgl->__page = page;
113 }
114 
115 static inline void
sg_set_page(struct scatterlist * sgl,struct vm_page * page,unsigned int length,unsigned int offset)116 sg_set_page(struct scatterlist *sgl, struct vm_page *page,
117     unsigned int length, unsigned int offset)
118 {
119 	sgl->__page = page;
120 	sgl->dma_address = page ? VM_PAGE_TO_PHYS(page) : 0;
121 	sgl->offset = offset;
122 	sgl->length = length;
123 }
124 
125 #define sg_dma_address(sg)	((sg)->dma_address)
126 #define sg_dma_len(sg)		((sg)->length)
127 
128 #define for_each_sg(sgl, sg, nents, i) \
129   for (i = 0, sg = (sgl); i < (nents); i++, sg = sg_next(sg))
130 
131 #define for_each_sg_page(sgl, iter, nents, pgoffset) \
132   __sg_page_iter_start((iter), (sgl), (nents), (pgoffset)); \
133   while (__sg_page_iter_next(iter))
134 
135 #define for_each_sgtable_page(st, iter, pgoffset) \
136 	for_each_sg_page((st)->sgl, iter, (st)->orig_nents, pgoffset)
137 
138 size_t sg_copy_from_buffer(struct scatterlist *, unsigned int,
139     const void *, size_t);
140 
141 #endif
142