1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/slab.h>
32#include <linux/module.h>
33#include <linux/bitmap.h>
34#include <linux/rculist.h>
35#include <linux/interrupt.h>
36#include <linux/genalloc.h>
37
38static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
39{
40 unsigned long val, nval;
41
42 nval = *addr;
43 do {
44 val = nval;
45 if (val & mask_to_set)
46 return -EBUSY;
47 cpu_relax();
48 } while ((nval = cmpxchg(addr, val, val | mask_to_set)) != val);
49
50 return 0;
51}
52
53static int clear_bits_ll(unsigned long *addr, unsigned long mask_to_clear)
54{
55 unsigned long val, nval;
56
57 nval = *addr;
58 do {
59 val = nval;
60 if ((val & mask_to_clear) != mask_to_clear)
61 return -EBUSY;
62 cpu_relax();
63 } while ((nval = cmpxchg(addr, val, val & ~mask_to_clear)) != val);
64
65 return 0;
66}
67
68
69
70
71
72
73
74
75
76
77
78
79static int bitmap_set_ll(unsigned long *map, int start, int nr)
80{
81 unsigned long *p = map + BIT_WORD(start);
82 const int size = start + nr;
83 int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
84 unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
85
86 while (nr - bits_to_set >= 0) {
87 if (set_bits_ll(p, mask_to_set))
88 return nr;
89 nr -= bits_to_set;
90 bits_to_set = BITS_PER_LONG;
91 mask_to_set = ~0UL;
92 p++;
93 }
94 if (nr) {
95 mask_to_set &= BITMAP_LAST_WORD_MASK(size);
96 if (set_bits_ll(p, mask_to_set))
97 return nr;
98 }
99
100 return 0;
101}
102
103
104
105
106
107
108
109
110
111
112
113
114static int bitmap_clear_ll(unsigned long *map, int start, int nr)
115{
116 unsigned long *p = map + BIT_WORD(start);
117 const int size = start + nr;
118 int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
119 unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
120
121 while (nr - bits_to_clear >= 0) {
122 if (clear_bits_ll(p, mask_to_clear))
123 return nr;
124 nr -= bits_to_clear;
125 bits_to_clear = BITS_PER_LONG;
126 mask_to_clear = ~0UL;
127 p++;
128 }
129 if (nr) {
130 mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
131 if (clear_bits_ll(p, mask_to_clear))
132 return nr;
133 }
134
135 return 0;
136}
137
138
139
140
141
142
143
144
145
146struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
147{
148 struct gen_pool *pool;
149
150 pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid);
151 if (pool != NULL) {
152 spin_lock_init(&pool->lock);
153 INIT_LIST_HEAD(&pool->chunks);
154 pool->min_alloc_order = min_alloc_order;
155 }
156 return pool;
157}
158EXPORT_SYMBOL(gen_pool_create);
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
174 size_t size, int nid)
175{
176 struct gen_pool_chunk *chunk;
177 int nbits = size >> pool->min_alloc_order;
178 int nbytes = sizeof(struct gen_pool_chunk) +
179 (nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
180
181 chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
182 if (unlikely(chunk == NULL))
183 return -ENOMEM;
184
185 chunk->phys_addr = phys;
186 chunk->start_addr = virt;
187 chunk->end_addr = virt + size;
188 atomic_set(&chunk->avail, size);
189
190 spin_lock(&pool->lock);
191 list_add_rcu(&chunk->next_chunk, &pool->chunks);
192 spin_unlock(&pool->lock);
193
194 return 0;
195}
196EXPORT_SYMBOL(gen_pool_add_virt);
197
198
199
200
201
202
203
204
205phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
206{
207 struct gen_pool_chunk *chunk;
208 phys_addr_t paddr = -1;
209
210 rcu_read_lock();
211 list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
212 if (addr >= chunk->start_addr && addr < chunk->end_addr) {
213 paddr = chunk->phys_addr + (addr - chunk->start_addr);
214 break;
215 }
216 }
217 rcu_read_unlock();
218
219 return paddr;
220}
221EXPORT_SYMBOL(gen_pool_virt_to_phys);
222
223
224
225
226
227
228
229
230void gen_pool_destroy(struct gen_pool *pool)
231{
232 struct list_head *_chunk, *_next_chunk;
233 struct gen_pool_chunk *chunk;
234 int order = pool->min_alloc_order;
235 int bit, end_bit;
236
237 list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
238 chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
239 list_del(&chunk->next_chunk);
240
241 end_bit = (chunk->end_addr - chunk->start_addr) >> order;
242 bit = find_next_bit(chunk->bits, end_bit, 0);
243 BUG_ON(bit < end_bit);
244
245 kfree(chunk);
246 }
247 kfree(pool);
248 return;
249}
250EXPORT_SYMBOL(gen_pool_destroy);
251
252
253
254
255
256
257
258
259
260
261unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
262{
263 struct gen_pool_chunk *chunk;
264 unsigned long addr = 0;
265 int order = pool->min_alloc_order;
266 int nbits, start_bit = 0, end_bit, remain;
267
268#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
269 BUG_ON(in_nmi());
270#endif
271
272 if (size == 0)
273 return 0;
274
275 nbits = (size + (1UL << order) - 1) >> order;
276 rcu_read_lock();
277 list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
278 if (size > atomic_read(&chunk->avail))
279 continue;
280
281 end_bit = (chunk->end_addr - chunk->start_addr) >> order;
282retry:
283 start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit,
284 start_bit, nbits, 0);
285 if (start_bit >= end_bit)
286 continue;
287 remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
288 if (remain) {
289 remain = bitmap_clear_ll(chunk->bits, start_bit,
290 nbits - remain);
291 BUG_ON(remain);
292 goto retry;
293 }
294
295 addr = chunk->start_addr + ((unsigned long)start_bit << order);
296 size = nbits << order;
297 atomic_sub(size, &chunk->avail);
298 break;
299 }
300 rcu_read_unlock();
301 return addr;
302}
303EXPORT_SYMBOL(gen_pool_alloc);
304
305
306
307
308
309
310
311
312
313
314
315void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
316{
317 struct gen_pool_chunk *chunk;
318 int order = pool->min_alloc_order;
319 int start_bit, nbits, remain;
320
321#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
322 BUG_ON(in_nmi());
323#endif
324
325 nbits = (size + (1UL << order) - 1) >> order;
326 rcu_read_lock();
327 list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
328 if (addr >= chunk->start_addr && addr < chunk->end_addr) {
329 BUG_ON(addr + size > chunk->end_addr);
330 start_bit = (addr - chunk->start_addr) >> order;
331 remain = bitmap_clear_ll(chunk->bits, start_bit, nbits);
332 BUG_ON(remain);
333 size = nbits << order;
334 atomic_add(size, &chunk->avail);
335 rcu_read_unlock();
336 return;
337 }
338 }
339 rcu_read_unlock();
340 BUG();
341}
342EXPORT_SYMBOL(gen_pool_free);
343
344
345
346
347
348
349
350
351
352
353void gen_pool_for_each_chunk(struct gen_pool *pool,
354 void (*func)(struct gen_pool *pool, struct gen_pool_chunk *chunk, void *data),
355 void *data)
356{
357 struct gen_pool_chunk *chunk;
358
359 rcu_read_lock();
360 list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk)
361 func(pool, chunk, data);
362 rcu_read_unlock();
363}
364EXPORT_SYMBOL(gen_pool_for_each_chunk);
365
366
367
368
369
370
371
372size_t gen_pool_avail(struct gen_pool *pool)
373{
374 struct gen_pool_chunk *chunk;
375 size_t avail = 0;
376
377 rcu_read_lock();
378 list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
379 avail += atomic_read(&chunk->avail);
380 rcu_read_unlock();
381 return avail;
382}
383EXPORT_SYMBOL_GPL(gen_pool_avail);
384
385
386
387
388
389
390
391size_t gen_pool_size(struct gen_pool *pool)
392{
393 struct gen_pool_chunk *chunk;
394 size_t size = 0;
395
396 rcu_read_lock();
397 list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
398 size += chunk->end_addr - chunk->start_addr;
399 rcu_read_unlock();
400 return size;
401}
402EXPORT_SYMBOL_GPL(gen_pool_size);
403