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 */ |
