aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/scatterlist.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/scatterlist.h')
-rw-r--r--include/linux/scatterlist.h191
1 files changed, 67 insertions, 124 deletions
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 457123171389..a3d567a974e8 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -7,6 +7,12 @@
7#include <linux/string.h> 7#include <linux/string.h>
8#include <asm/io.h> 8#include <asm/io.h>
9 9
10struct sg_table {
11 struct scatterlist *sgl; /* the list */
12 unsigned int nents; /* number of mapped entries */
13 unsigned int orig_nents; /* original size of list */
14};
15
10/* 16/*
11 * Notes on SG table design. 17 * Notes on SG table design.
12 * 18 *
@@ -26,6 +32,16 @@
26 32
27#define SG_MAGIC 0x87654321 33#define SG_MAGIC 0x87654321
28 34
35/*
36 * We overload the LSB of the page pointer to indicate whether it's
37 * a valid sg entry, or whether it points to the start of a new scatterlist.
38 * Those low bits are there for everyone! (thanks mason :-)
39 */
40#define sg_is_chain(sg) ((sg)->page_link & 0x01)
41#define sg_is_last(sg) ((sg)->page_link & 0x02)
42#define sg_chain_ptr(sg) \
43 ((struct scatterlist *) ((sg)->page_link & ~0x03))
44
29/** 45/**
30 * sg_assign_page - Assign a given page to an SG entry 46 * sg_assign_page - Assign a given page to an SG entry
31 * @sg: SG entry 47 * @sg: SG entry
@@ -47,6 +63,7 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
47 BUG_ON((unsigned long) page & 0x03); 63 BUG_ON((unsigned long) page & 0x03);
48#ifdef CONFIG_DEBUG_SG 64#ifdef CONFIG_DEBUG_SG
49 BUG_ON(sg->sg_magic != SG_MAGIC); 65 BUG_ON(sg->sg_magic != SG_MAGIC);
66 BUG_ON(sg_is_chain(sg));
50#endif 67#endif
51 sg->page_link = page_link | (unsigned long) page; 68 sg->page_link = page_link | (unsigned long) page;
52} 69}
@@ -73,7 +90,14 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page,
73 sg->length = len; 90 sg->length = len;
74} 91}
75 92
76#define sg_page(sg) ((struct page *) ((sg)->page_link & ~0x3)) 93static inline struct page *sg_page(struct scatterlist *sg)
94{
95#ifdef CONFIG_DEBUG_SG
96 BUG_ON(sg->sg_magic != SG_MAGIC);
97 BUG_ON(sg_is_chain(sg));
98#endif
99 return (struct page *)((sg)->page_link & ~0x3);
100}
77 101
78/** 102/**
79 * sg_set_buf - Set sg entry to point at given data 103 * sg_set_buf - Set sg entry to point at given data
@@ -89,81 +113,12 @@ static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
89} 113}
90 114
91/* 115/*
92 * We overload the LSB of the page pointer to indicate whether it's
93 * a valid sg entry, or whether it points to the start of a new scatterlist.
94 * Those low bits are there for everyone! (thanks mason :-)
95 */
96#define sg_is_chain(sg) ((sg)->page_link & 0x01)
97#define sg_is_last(sg) ((sg)->page_link & 0x02)
98#define sg_chain_ptr(sg) \
99 ((struct scatterlist *) ((sg)->page_link & ~0x03))
100
101/**
102 * sg_next - return the next scatterlist entry in a list
103 * @sg: The current sg entry
104 *
105 * Description:
106 * Usually the next entry will be @sg@ + 1, but if this sg element is part
107 * of a chained scatterlist, it could jump to the start of a new
108 * scatterlist array.
109 *
110 **/
111static inline struct scatterlist *sg_next(struct scatterlist *sg)
112{
113#ifdef CONFIG_DEBUG_SG
114 BUG_ON(sg->sg_magic != SG_MAGIC);
115#endif
116 if (sg_is_last(sg))
117 return NULL;
118
119 sg++;
120 if (unlikely(sg_is_chain(sg)))
121 sg = sg_chain_ptr(sg);
122
123 return sg;
124}
125
126/*
127 * Loop over each sg element, following the pointer to a new list if necessary 116 * Loop over each sg element, following the pointer to a new list if necessary
128 */ 117 */
129#define for_each_sg(sglist, sg, nr, __i) \ 118#define for_each_sg(sglist, sg, nr, __i) \
130 for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) 119 for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
131 120
132/** 121/**
133 * sg_last - return the last scatterlist entry in a list
134 * @sgl: First entry in the scatterlist
135 * @nents: Number of entries in the scatterlist
136 *
137 * Description:
138 * Should only be used casually, it (currently) scan the entire list
139 * to get the last entry.
140 *
141 * Note that the @sgl@ pointer passed in need not be the first one,
142 * the important bit is that @nents@ denotes the number of entries that
143 * exist from @sgl@.
144 *
145 **/
146static inline struct scatterlist *sg_last(struct scatterlist *sgl,
147 unsigned int nents)
148{
149#ifndef ARCH_HAS_SG_CHAIN
150 struct scatterlist *ret = &sgl[nents - 1];
151#else
152 struct scatterlist *sg, *ret = NULL;
153 int i;
154
155 for_each_sg(sgl, sg, nents, i)
156 ret = sg;
157
158#endif
159#ifdef CONFIG_DEBUG_SG
160 BUG_ON(sgl[0].sg_magic != SG_MAGIC);
161 BUG_ON(!sg_is_last(ret));
162#endif
163 return ret;
164}
165
166/**
167 * sg_chain - Chain two sglists together 122 * sg_chain - Chain two sglists together
168 * @prv: First scatterlist 123 * @prv: First scatterlist
169 * @prv_nents: Number of entries in prv 124 * @prv_nents: Number of entries in prv
@@ -179,71 +134,39 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
179#ifndef ARCH_HAS_SG_CHAIN 134#ifndef ARCH_HAS_SG_CHAIN
180 BUG(); 135 BUG();
181#endif 136#endif
182 prv[prv_nents - 1].page_link = (unsigned long) sgl | 0x01;
183}
184 137
185/** 138 /*
186 * sg_mark_end - Mark the end of the scatterlist 139 * offset and length are unused for chain entry. Clear them.
187 * @sgl: Scatterlist 140 */
188 * @nents: Number of entries in sgl 141 prv[prv_nents - 1].offset = 0;
189 * 142 prv[prv_nents - 1].length = 0;
190 * Description:
191 * Marks the last entry as the termination point for sg_next()
192 *
193 **/
194static inline void sg_mark_end(struct scatterlist *sgl, unsigned int nents)
195{
196 sgl[nents - 1].page_link = 0x02;
197}
198
199static inline void __sg_mark_end(struct scatterlist *sg)
200{
201 sg->page_link |= 0x02;
202}
203 143
204/** 144 /*
205 * sg_init_one - Initialize a single entry sg list 145 * Set lowest bit to indicate a link pointer, and make sure to clear
206 * @sg: SG entry 146 * the termination bit if it happens to be set.
207 * @buf: Virtual address for IO 147 */
208 * @buflen: IO length 148 prv[prv_nents - 1].page_link = ((unsigned long) sgl | 0x01) & ~0x02;
209 *
210 * Notes:
211 * This should not be used on a single entry that is part of a larger
212 * table. Use sg_init_table() for that.
213 *
214 **/
215static inline void sg_init_one(struct scatterlist *sg, const void *buf,
216 unsigned int buflen)
217{
218 memset(sg, 0, sizeof(*sg));
219#ifdef CONFIG_DEBUG_SG
220 sg->sg_magic = SG_MAGIC;
221#endif
222 sg_mark_end(sg, 1);
223 sg_set_buf(sg, buf, buflen);
224} 149}
225 150
226/** 151/**
227 * sg_init_table - Initialize SG table 152 * sg_mark_end - Mark the end of the scatterlist
228 * @sgl: The SG table 153 * @sg: SG entryScatterlist
229 * @nents: Number of entries in table
230 * 154 *
231 * Notes: 155 * Description:
232 * If this is part of a chained sg table, sg_mark_end() should be 156 * Marks the passed in sg entry as the termination point for the sg
233 * used only on the last table part. 157 * table. A call to sg_next() on this entry will return NULL.
234 * 158 *
235 **/ 159 **/
236static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) 160static inline void sg_mark_end(struct scatterlist *sg)
237{ 161{
238 memset(sgl, 0, sizeof(*sgl) * nents);
239 sg_mark_end(sgl, nents);
240#ifdef CONFIG_DEBUG_SG 162#ifdef CONFIG_DEBUG_SG
241 { 163 BUG_ON(sg->sg_magic != SG_MAGIC);
242 int i;
243 for (i = 0; i < nents; i++)
244 sgl[i].sg_magic = SG_MAGIC;
245 }
246#endif 164#endif
165 /*
166 * Set termination bit, clear potential chain bit
167 */
168 sg->page_link |= 0x02;
169 sg->page_link &= ~0x01;
247} 170}
248 171
249/** 172/**
@@ -276,4 +199,24 @@ static inline void *sg_virt(struct scatterlist *sg)
276 return page_address(sg_page(sg)) + sg->offset; 199 return page_address(sg_page(sg)) + sg->offset;
277} 200}
278 201
202struct scatterlist *sg_next(struct scatterlist *);
203struct scatterlist *sg_last(struct scatterlist *s, unsigned int);
204void sg_init_table(struct scatterlist *, unsigned int);
205void sg_init_one(struct scatterlist *, const void *, unsigned int);
206
207typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t);
208typedef void (sg_free_fn)(struct scatterlist *, unsigned int);
209
210void __sg_free_table(struct sg_table *, unsigned int, sg_free_fn *);
211void sg_free_table(struct sg_table *);
212int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t,
213 sg_alloc_fn *);
214int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
215
216/*
217 * Maximum number of entries that will be allocated in one piece, if
218 * a list larger than this is required then chaining will be utilized.
219 */
220#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist))
221
279#endif /* _LINUX_SCATTERLIST_H */ 222#endif /* _LINUX_SCATTERLIST_H */