Subversion Repositories Kolibri OS

Rev

Rev 5056 | Rev 6082 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5056 serge 1
/*
2
 * Copyright (C) 2007 Jens Axboe 
3
 *
4
 * Scatterlist handling helpers.
5
 *
6
 * This source code is licensed under the GNU General Public License,
7
 * Version 2. See the file COPYING for more details.
8
 */
9
#include 
5270 serge 10
#include 
5056 serge 11
#include 
12
 
13
/**
14
 * sg_next - return the next scatterlist entry in a list
15
 * @sg:		The current sg entry
16
 *
17
 * Description:
18
 *   Usually the next entry will be @sg@ + 1, but if this sg element is part
19
 *   of a chained scatterlist, it could jump to the start of a new
20
 *   scatterlist array.
21
 *
22
 **/
23
struct scatterlist *sg_next(struct scatterlist *sg)
24
{
25
#ifdef CONFIG_DEBUG_SG
26
	BUG_ON(sg->sg_magic != SG_MAGIC);
27
#endif
28
    if (sg_is_last(sg))
29
        return NULL;
30
 
31
    sg++;
32
    if (unlikely(sg_is_chain(sg)))
33
            sg = sg_chain_ptr(sg);
34
 
35
    return sg;
36
}
37
EXPORT_SYMBOL(sg_next);
38
 
39
/**
40
 * sg_nents - return total count of entries in scatterlist
41
 * @sg:		The scatterlist
42
 *
43
 * Description:
44
 * Allows to know how many entries are in sg, taking into acount
45
 * chaining as well
46
 *
47
 **/
48
int sg_nents(struct scatterlist *sg)
49
{
50
	int nents;
51
	for (nents = 0; sg; sg = sg_next(sg))
52
		nents++;
53
	return nents;
54
}
55
EXPORT_SYMBOL(sg_nents);
56
 
57
 
58
/**
59
 * sg_last - return the last scatterlist entry in a list
60
 * @sgl:	First entry in the scatterlist
61
 * @nents:	Number of entries in the scatterlist
62
 *
63
 * Description:
64
 *   Should only be used casually, it (currently) scans the entire list
65
 *   to get the last entry.
66
 *
67
 *   Note that the @sgl@ pointer passed in need not be the first one,
68
 *   the important bit is that @nents@ denotes the number of entries that
69
 *   exist from @sgl@.
70
 *
71
 **/
72
struct scatterlist *sg_last(struct scatterlist *sgl, unsigned int nents)
73
{
5270 serge 74
#ifndef CONFIG_ARCH_HAS_SG_CHAIN
5056 serge 75
	struct scatterlist *ret = &sgl[nents - 1];
76
#else
77
	struct scatterlist *sg, *ret = NULL;
78
	unsigned int i;
79
 
80
	for_each_sg(sgl, sg, nents, i)
81
		ret = sg;
82
 
83
#endif
84
#ifdef CONFIG_DEBUG_SG
85
	BUG_ON(sgl[0].sg_magic != SG_MAGIC);
86
	BUG_ON(!sg_is_last(ret));
87
#endif
88
	return ret;
89
}
90
EXPORT_SYMBOL(sg_last);
91
 
92
/**
93
 * sg_init_table - Initialize SG table
94
 * @sgl:	   The SG table
95
 * @nents:	   Number of entries in table
96
 *
97
 * Notes:
98
 *   If this is part of a chained sg table, sg_mark_end() should be
99
 *   used only on the last table part.
100
 *
101
 **/
102
void sg_init_table(struct scatterlist *sgl, unsigned int nents)
103
{
104
    memset(sgl, 0, sizeof(*sgl) * nents);
105
#ifdef CONFIG_DEBUG_SG
106
    {
107
            unsigned int i;
108
            for (i = 0; i < nents; i++)
109
                    sgl[i].sg_magic = SG_MAGIC;
110
    }
111
#endif
112
    sg_mark_end(&sgl[nents - 1]);
113
}
114
EXPORT_SYMBOL(sg_init_table);
115
 
116
/**
117
 * sg_init_one - Initialize a single entry sg list
118
 * @sg:		 SG entry
119
 * @buf:	 Virtual address for IO
120
 * @buflen:	 IO length
121
 *
122
 **/
123
//void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
124
//{
125
//   sg_init_table(sg, 1);
126
//   sg_set_buf(sg, buf, buflen);
127
//}
128
EXPORT_SYMBOL(sg_init_one);
129
 
130
/*
131
 * The default behaviour of sg_alloc_table() is to use these kmalloc/kfree
132
 * helpers.
133
 */
134
static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
135
{
136
	return kmalloc(nents * sizeof(struct scatterlist), gfp_mask);
137
}
138
 
139
static void sg_kfree(struct scatterlist *sg, unsigned int nents)
140
{
141
	kfree(sg);
142
}
143
 
144
/**
145
 * __sg_free_table - Free a previously mapped sg table
146
 * @table:	The sg table header to use
147
 * @max_ents:	The maximum number of entries per single scatterlist
148
 * @skip_first_chunk: don't free the (preallocated) first scatterlist chunk
149
 * @free_fn:	Free function
150
 *
151
 *  Description:
152
 *    Free an sg table previously allocated and setup with
153
 *    __sg_alloc_table().  The @max_ents value must be identical to
154
 *    that previously used with __sg_alloc_table().
155
 *
156
 **/
157
void __sg_free_table(struct sg_table *table, unsigned int max_ents,
158
		     bool skip_first_chunk, sg_free_fn *free_fn)
159
{
160
    struct scatterlist *sgl, *next;
161
 
162
    if (unlikely(!table->sgl))
163
            return;
164
 
165
    sgl = table->sgl;
166
    while (table->orig_nents) {
167
        unsigned int alloc_size = table->orig_nents;
168
        unsigned int sg_size;
169
 
170
        /*
171
         * If we have more than max_ents segments left,
172
         * then assign 'next' to the sg table after the current one.
173
         * sg_size is then one less than alloc size, since the last
174
         * element is the chain pointer.
175
         */
176
        if (alloc_size > max_ents) {
177
                next = sg_chain_ptr(&sgl[max_ents - 1]);
178
                alloc_size = max_ents;
179
                sg_size = alloc_size - 1;
180
        } else {
181
                sg_size = alloc_size;
182
                next = NULL;
183
        }
184
 
185
        table->orig_nents -= sg_size;
5270 serge 186
		if (skip_first_chunk)
187
			skip_first_chunk = false;
188
		else
5056 serge 189
			free_fn(sgl, alloc_size);
190
        sgl = next;
191
    }
192
 
193
    table->sgl = NULL;
194
}
195
EXPORT_SYMBOL(__sg_free_table);
196
 
197
/**
198
 * sg_free_table - Free a previously allocated sg table
199
 * @table:	The mapped sg table header
200
 *
201
 **/
202
void sg_free_table(struct sg_table *table)
203
{
204
	__sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);
205
}
206
EXPORT_SYMBOL(sg_free_table);
207
 
208
/**
209
 * __sg_alloc_table - Allocate and initialize an sg table with given allocator
210
 * @table:	The sg table header to use
211
 * @nents:	Number of entries in sg list
212
 * @max_ents:	The maximum number of entries the allocator returns per call
213
 * @gfp_mask:	GFP allocation mask
214
 * @alloc_fn:	Allocator to use
215
 *
216
 * Description:
217
 *   This function returns a @table @nents long. The allocator is
218
 *   defined to return scatterlist chunks of maximum size @max_ents.
219
 *   Thus if @nents is bigger than @max_ents, the scatterlists will be
220
 *   chained in units of @max_ents.
221
 *
222
 * Notes:
223
 *   If this function returns non-0 (eg failure), the caller must call
224
 *   __sg_free_table() to cleanup any leftover allocations.
225
 *
226
 **/
227
int __sg_alloc_table(struct sg_table *table, unsigned int nents,
228
		     unsigned int max_ents, struct scatterlist *first_chunk,
229
		     gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
230
{
231
    struct scatterlist *sg, *prv;
232
    unsigned int left;
233
 
234
	memset(table, 0, sizeof(*table));
235
 
236
	if (nents == 0)
237
		return -EINVAL;
5270 serge 238
#ifndef CONFIG_ARCH_HAS_SG_CHAIN
5056 serge 239
	if (WARN_ON_ONCE(nents > max_ents))
240
		return -EINVAL;
241
#endif
242
 
243
    left = nents;
244
    prv = NULL;
245
    do {
246
        unsigned int sg_size, alloc_size = left;
247
 
248
        if (alloc_size > max_ents) {
249
                alloc_size = max_ents;
250
                sg_size = alloc_size - 1;
251
        } else
252
                sg_size = alloc_size;
253
 
254
        left -= sg_size;
255
 
256
		if (first_chunk) {
257
			sg = first_chunk;
258
			first_chunk = NULL;
259
		} else {
260
			sg = alloc_fn(alloc_size, gfp_mask);
261
		}
262
        if (unlikely(!sg)) {
263
                /*
264
                 * Adjust entry count to reflect that the last
265
                 * entry of the previous table won't be used for
266
                 * linkage.  Without this, sg_kfree() may get
267
                 * confused.
268
                 */
269
                if (prv)
270
                        table->nents = ++table->orig_nents;
271
 
272
 			return -ENOMEM;
273
        }
274
 
275
        sg_init_table(sg, alloc_size);
276
        table->nents = table->orig_nents += sg_size;
277
 
278
        /*
279
         * If this is the first mapping, assign the sg table header.
280
         * If this is not the first mapping, chain previous part.
281
         */
282
        if (prv)
283
                sg_chain(prv, max_ents, sg);
284
        else
285
                table->sgl = sg;
286
 
287
        /*
288
         * If no more entries after this one, mark the end
289
         */
290
        if (!left)
291
                sg_mark_end(&sg[sg_size - 1]);
292
 
293
        prv = sg;
294
    } while (left);
295
 
296
    return 0;
297
}
298
EXPORT_SYMBOL(__sg_alloc_table);
299
 
300
/**
301
 * sg_alloc_table - Allocate and initialize an sg table
302
 * @table:	The sg table header to use
303
 * @nents:	Number of entries in sg list
304
 * @gfp_mask:	GFP allocation mask
305
 *
306
 *  Description:
307
 *    Allocate and initialize an sg table. If @nents@ is larger than
308
 *    SG_MAX_SINGLE_ALLOC a chained sg table will be setup.
309
 *
310
 **/
311
int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
312
{
313
	int ret;
314
 
315
	ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
316
			       NULL, gfp_mask, sg_kmalloc);
317
	if (unlikely(ret))
318
		__sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);
319
 
320
	return ret;
321
}
322
EXPORT_SYMBOL(sg_alloc_table);
323
 
324
 
325
 
326
 
327
void __sg_page_iter_start(struct sg_page_iter *piter,
328
              struct scatterlist *sglist, unsigned int nents,
329
              unsigned long pgoffset)
330
{
331
    piter->__pg_advance = 0;
332
    piter->__nents = nents;
333
 
334
    piter->sg = sglist;
335
    piter->sg_pgoffset = pgoffset;
336
}
337
EXPORT_SYMBOL(__sg_page_iter_start);
338
 
339
static int sg_page_count(struct scatterlist *sg)
340
{
341
    return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT;
342
}
343
 
344
bool __sg_page_iter_next(struct sg_page_iter *piter)
345
{
346
    if (!piter->__nents || !piter->sg)
347
        return false;
348
 
349
    piter->sg_pgoffset += piter->__pg_advance;
350
    piter->__pg_advance = 1;
351
 
352
    while (piter->sg_pgoffset >= sg_page_count(piter->sg)) {
353
        piter->sg_pgoffset -= sg_page_count(piter->sg);
354
        piter->sg = sg_next(piter->sg);
355
        if (!--piter->__nents || !piter->sg)
356
            return false;
357
    }
358
 
359
    return true;
360
}
361
EXPORT_SYMBOL(__sg_page_iter_next);
362