diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/scatterlist.h | 202 |
1 files changed, 175 insertions, 27 deletions
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 2dc7464cce52..42daf5e15265 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h | |||
@@ -4,47 +4,95 @@ | |||
4 | #include <asm/scatterlist.h> | 4 | #include <asm/scatterlist.h> |
5 | #include <linux/mm.h> | 5 | #include <linux/mm.h> |
6 | #include <linux/string.h> | 6 | #include <linux/string.h> |
7 | #include <asm/io.h> | ||
7 | 8 | ||
9 | /* | ||
10 | * Notes on SG table design. | ||
11 | * | ||
12 | * Architectures must provide an unsigned long page_link field in the | ||
13 | * scatterlist struct. We use that to place the page pointer AND encode | ||
14 | * information about the sg table as well. The two lower bits are reserved | ||
15 | * for this information. | ||
16 | * | ||
17 | * If bit 0 is set, then the page_link contains a pointer to the next sg | ||
18 | * table list. Otherwise the next entry is at sg + 1. | ||
19 | * | ||
20 | * If bit 1 is set, then this sg entry is the last element in a list. | ||
21 | * | ||
22 | * See sg_next(). | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #define SG_MAGIC 0x87654321 | ||
27 | |||
28 | /** | ||
29 | * sg_set_page - Set sg entry to point at given page | ||
30 | * @sg: SG entry | ||
31 | * @page: The page | ||
32 | * | ||
33 | * Description: | ||
34 | * Use this function to set an sg entry pointing at a page, never assign | ||
35 | * the page directly. We encode sg table information in the lower bits | ||
36 | * of the page pointer. See sg_page() for looking up the page belonging | ||
37 | * to an sg entry. | ||
38 | * | ||
39 | **/ | ||
40 | static inline void sg_set_page(struct scatterlist *sg, struct page *page) | ||
41 | { | ||
42 | unsigned long page_link = sg->page_link & 0x3; | ||
43 | |||
44 | #ifdef CONFIG_DEBUG_SG | ||
45 | BUG_ON(sg->sg_magic != SG_MAGIC); | ||
46 | #endif | ||
47 | sg->page_link = page_link | (unsigned long) page; | ||
48 | } | ||
49 | |||
50 | #define sg_page(sg) ((struct page *) ((sg)->page_link & ~0x3)) | ||
51 | |||
52 | /** | ||
53 | * sg_set_buf - Set sg entry to point at given data | ||
54 | * @sg: SG entry | ||
55 | * @buf: Data | ||
56 | * @buflen: Data length | ||
57 | * | ||
58 | **/ | ||
8 | static inline void sg_set_buf(struct scatterlist *sg, const void *buf, | 59 | static inline void sg_set_buf(struct scatterlist *sg, const void *buf, |
9 | unsigned int buflen) | 60 | unsigned int buflen) |
10 | { | 61 | { |
11 | sg->page = virt_to_page(buf); | 62 | sg_set_page(sg, virt_to_page(buf)); |
12 | sg->offset = offset_in_page(buf); | 63 | sg->offset = offset_in_page(buf); |
13 | sg->length = buflen; | 64 | sg->length = buflen; |
14 | } | 65 | } |
15 | 66 | ||
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 | /* | 67 | /* |
24 | * We overload the LSB of the page pointer to indicate whether it's | 68 | * 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. | 69 | * 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 :-) | 70 | * Those low bits are there for everyone! (thanks mason :-) |
27 | */ | 71 | */ |
28 | #define sg_is_chain(sg) ((unsigned long) (sg)->page & 0x01) | 72 | #define sg_is_chain(sg) ((sg)->page_link & 0x01) |
73 | #define sg_is_last(sg) ((sg)->page_link & 0x02) | ||
29 | #define sg_chain_ptr(sg) \ | 74 | #define sg_chain_ptr(sg) \ |
30 | ((struct scatterlist *) ((unsigned long) (sg)->page & ~0x01)) | 75 | ((struct scatterlist *) ((sg)->page_link & ~0x03)) |
31 | 76 | ||
32 | /** | 77 | /** |
33 | * sg_next - return the next scatterlist entry in a list | 78 | * sg_next - return the next scatterlist entry in a list |
34 | * @sg: The current sg entry | 79 | * @sg: The current sg entry |
35 | * | 80 | * |
36 | * Usually the next entry will be @sg@ + 1, but if this sg element is part | 81 | * Description: |
37 | * of a chained scatterlist, it could jump to the start of a new | 82 | * Usually the next entry will be @sg@ + 1, but if this sg element is part |
38 | * scatterlist array. | 83 | * of a chained scatterlist, it could jump to the start of a new |
39 | * | 84 | * scatterlist array. |
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 | * | 85 | * |
43 | */ | 86 | **/ |
44 | static inline struct scatterlist *sg_next(struct scatterlist *sg) | 87 | static inline struct scatterlist *sg_next(struct scatterlist *sg) |
45 | { | 88 | { |
46 | sg++; | 89 | #ifdef CONFIG_DEBUG_SG |
90 | BUG_ON(sg->sg_magic != SG_MAGIC); | ||
91 | #endif | ||
92 | if (sg_is_last(sg)) | ||
93 | return NULL; | ||
47 | 94 | ||
95 | sg++; | ||
48 | if (unlikely(sg_is_chain(sg))) | 96 | if (unlikely(sg_is_chain(sg))) |
49 | sg = sg_chain_ptr(sg); | 97 | sg = sg_chain_ptr(sg); |
50 | 98 | ||
@@ -62,14 +110,15 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg) | |||
62 | * @sgl: First entry in the scatterlist | 110 | * @sgl: First entry in the scatterlist |
63 | * @nents: Number of entries in the scatterlist | 111 | * @nents: Number of entries in the scatterlist |
64 | * | 112 | * |
65 | * Should only be used casually, it (currently) scan the entire list | 113 | * Description: |
66 | * to get the last entry. | 114 | * Should only be used casually, it (currently) scan the entire list |
115 | * to get the last entry. | ||
67 | * | 116 | * |
68 | * Note that the @sgl@ pointer passed in need not be the first one, | 117 | * 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 | 118 | * the important bit is that @nents@ denotes the number of entries that |
70 | * exist from @sgl@. | 119 | * exist from @sgl@. |
71 | * | 120 | * |
72 | */ | 121 | **/ |
73 | static inline struct scatterlist *sg_last(struct scatterlist *sgl, | 122 | static inline struct scatterlist *sg_last(struct scatterlist *sgl, |
74 | unsigned int nents) | 123 | unsigned int nents) |
75 | { | 124 | { |
@@ -83,6 +132,10 @@ static inline struct scatterlist *sg_last(struct scatterlist *sgl, | |||
83 | ret = sg; | 132 | ret = sg; |
84 | 133 | ||
85 | #endif | 134 | #endif |
135 | #ifdef CONFIG_DEBUG_SG | ||
136 | BUG_ON(sgl[0].sg_magic != SG_MAGIC); | ||
137 | BUG_ON(!sg_is_last(ret)); | ||
138 | #endif | ||
86 | return ret; | 139 | return ret; |
87 | } | 140 | } |
88 | 141 | ||
@@ -92,16 +145,111 @@ static inline struct scatterlist *sg_last(struct scatterlist *sgl, | |||
92 | * @prv_nents: Number of entries in prv | 145 | * @prv_nents: Number of entries in prv |
93 | * @sgl: Second scatterlist | 146 | * @sgl: Second scatterlist |
94 | * | 147 | * |
95 | * Links @prv@ and @sgl@ together, to form a longer scatterlist. | 148 | * Description: |
149 | * Links @prv@ and @sgl@ together, to form a longer scatterlist. | ||
96 | * | 150 | * |
97 | */ | 151 | **/ |
98 | static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents, | 152 | static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents, |
99 | struct scatterlist *sgl) | 153 | struct scatterlist *sgl) |
100 | { | 154 | { |
101 | #ifndef ARCH_HAS_SG_CHAIN | 155 | #ifndef ARCH_HAS_SG_CHAIN |
102 | BUG(); | 156 | BUG(); |
103 | #endif | 157 | #endif |
104 | prv[prv_nents - 1].page = (struct page *) ((unsigned long) sgl | 0x01); | 158 | prv[prv_nents - 1].page_link = (unsigned long) sgl | 0x01; |
159 | } | ||
160 | |||
161 | /** | ||
162 | * sg_mark_end - Mark the end of the scatterlist | ||
163 | * @sgl: Scatterlist | ||
164 | * @nents: Number of entries in sgl | ||
165 | * | ||
166 | * Description: | ||
167 | * Marks the last entry as the termination point for sg_next() | ||
168 | * | ||
169 | **/ | ||
170 | static inline void sg_mark_end(struct scatterlist *sgl, unsigned int nents) | ||
171 | { | ||
172 | sgl[nents - 1].page_link = 0x02; | ||
173 | } | ||
174 | |||
175 | static inline void __sg_mark_end(struct scatterlist *sg) | ||
176 | { | ||
177 | sg->page_link |= 0x02; | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * sg_init_one - Initialize a single entry sg list | ||
182 | * @sg: SG entry | ||
183 | * @buf: Virtual address for IO | ||
184 | * @buflen: IO length | ||
185 | * | ||
186 | * Notes: | ||
187 | * This should not be used on a single entry that is part of a larger | ||
188 | * table. Use sg_init_table() for that. | ||
189 | * | ||
190 | **/ | ||
191 | static inline void sg_init_one(struct scatterlist *sg, const void *buf, | ||
192 | unsigned int buflen) | ||
193 | { | ||
194 | memset(sg, 0, sizeof(*sg)); | ||
195 | #ifdef CONFIG_DEBUG_SG | ||
196 | sg->sg_magic = SG_MAGIC; | ||
197 | #endif | ||
198 | sg_mark_end(sg, 1); | ||
199 | sg_set_buf(sg, buf, buflen); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * sg_init_table - Initialize SG table | ||
204 | * @sgl: The SG table | ||
205 | * @nents: Number of entries in table | ||
206 | * | ||
207 | * Notes: | ||
208 | * If this is part of a chained sg table, sg_mark_end() should be | ||
209 | * used only on the last table part. | ||
210 | * | ||
211 | **/ | ||
212 | static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) | ||
213 | { | ||
214 | memset(sgl, 0, sizeof(*sgl) * nents); | ||
215 | sg_mark_end(sgl, nents); | ||
216 | #ifdef CONFIG_DEBUG_SG | ||
217 | { | ||
218 | int i; | ||
219 | for (i = 0; i < nents; i++) | ||
220 | sgl[i].sg_magic = SG_MAGIC; | ||
221 | } | ||
222 | #endif | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * sg_phys - Return physical address of an sg entry | ||
227 | * @sg: SG entry | ||
228 | * | ||
229 | * Description: | ||
230 | * This calls page_to_phys() on the page in this sg entry, and adds the | ||
231 | * sg offset. The caller must know that it is legal to call page_to_phys() | ||
232 | * on the sg page. | ||
233 | * | ||
234 | **/ | ||
235 | static inline unsigned long sg_phys(struct scatterlist *sg) | ||
236 | { | ||
237 | return page_to_phys(sg_page(sg)) + sg->offset; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * sg_virt - Return virtual address of an sg entry | ||
242 | * @sg: SG entry | ||
243 | * | ||
244 | * Description: | ||
245 | * This calls page_address() on the page in this sg entry, and adds the | ||
246 | * sg offset. The caller must know that the sg page has a valid virtual | ||
247 | * mapping. | ||
248 | * | ||
249 | **/ | ||
250 | static inline void *sg_virt(struct scatterlist *sg) | ||
251 | { | ||
252 | return page_address(sg_page(sg)) + sg->offset; | ||
105 | } | 253 | } |
106 | 254 | ||
107 | #endif /* _LINUX_SCATTERLIST_H */ | 255 | #endif /* _LINUX_SCATTERLIST_H */ |