xref: /linux-6.15/include/linux/scatterlist.h (revision f035ac82)
1 #ifndef _LINUX_SCATTERLIST_H
2 #define _LINUX_SCATTERLIST_H
3 
4 #include <asm/scatterlist.h>
5 #include <linux/mm.h>
6 #include <linux/string.h>
7 
8 static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
9 			      unsigned int buflen)
10 {
11 	sg->page = virt_to_page(buf);
12 	sg->offset = offset_in_page(buf);
13 	sg->length = buflen;
14 }
15 
16 static inline void sg_init_one(struct scatterlist *sg, const void *buf,
17 			       unsigned int buflen)
18 {
19 	memset(sg, 0, sizeof(*sg));
20 	sg_set_buf(sg, buf, buflen);
21 }
22 
23 /*
24  * We overload the LSB of the page pointer to indicate whether it's
25  * a valid sg entry, or whether it points to the start of a new scatterlist.
26  * Those low bits are there for everyone! (thanks mason :-)
27  */
28 #define sg_is_chain(sg)		((unsigned long) (sg)->page & 0x01)
29 #define sg_chain_ptr(sg)	\
30 	((struct scatterlist *) ((unsigned long) (sg)->page & ~0x01))
31 
32 /**
33  * sg_next - return the next scatterlist entry in a list
34  * @sg:		The current sg entry
35  *
36  * Usually the next entry will be @sg@ + 1, but if this sg element is part
37  * of a chained scatterlist, it could jump to the start of a new
38  * scatterlist array.
39  *
40  * Note that the caller must ensure that there are further entries after
41  * the current entry, this function will NOT return NULL for an end-of-list.
42  *
43  */
44 static inline struct scatterlist *sg_next(struct scatterlist *sg)
45 {
46 	sg++;
47 
48 	if (unlikely(sg_is_chain(sg)))
49 		sg = sg_chain_ptr(sg);
50 
51 	return sg;
52 }
53 
54 /*
55  * Loop over each sg element, following the pointer to a new list if necessary
56  */
57 #define for_each_sg(sglist, sg, nr, __i)	\
58 	for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
59 
60 /**
61  * sg_last - return the last scatterlist entry in a list
62  * @sgl:	First entry in the scatterlist
63  * @nents:	Number of entries in the scatterlist
64  *
65  * Should only be used casually, it (currently) scan the entire list
66  * to get the last entry.
67  *
68  * Note that the @sgl@ pointer passed in need not be the first one,
69  * the important bit is that @nents@ denotes the number of entries that
70  * exist from @sgl@.
71  *
72  */
73 static inline struct scatterlist *sg_last(struct scatterlist *sgl,
74 					  unsigned int nents)
75 {
76 #ifndef ARCH_HAS_SG_CHAIN
77 	struct scatterlist *ret = &sgl[nents - 1];
78 #else
79 	struct scatterlist *sg, *ret = NULL;
80 	int i;
81 
82 	for_each_sg(sgl, sg, nents, i)
83 		ret = sg;
84 
85 #endif
86 	return ret;
87 }
88 
89 /**
90  * sg_chain - Chain two sglists together
91  * @prv:	First scatterlist
92  * @prv_nents:	Number of entries in prv
93  * @sgl:	Second scatterlist
94  *
95  * Links @prv@ and @sgl@ together, to form a longer scatterlist.
96  *
97  */
98 static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
99 			    struct scatterlist *sgl)
100 {
101 #ifndef ARCH_HAS_SG_CHAIN
102 	BUG();
103 #endif
104 	prv[prv_nents - 1].page = (struct page *) ((unsigned long) sgl | 0x01);
105 }
106 
107 #endif /* _LINUX_SCATTERLIST_H */
108