Blame view

mm/dmapool.c 13.7 KB
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   * DMA Pool allocator
   *
   * Copyright 2001 David Brownell
   * Copyright 2007 Intel Corporation
   *   Author: Matthew Wilcox <willy@linux.intel.com>
   *
   * This software may be redistributed and/or modified under the terms of
   * the GNU General Public License ("GPL") version 2 as published by the
   * Free Software Foundation.
   *
   * This allocator returns small blocks of a given size which are DMA-able by
   * the given device.  It uses the dma_alloc_coherent page allocator to get
   * new pages, then splits them up into blocks of the required size.
   * Many older drivers still have their own code to do this.
   *
   * The current design of this allocator is fairly simple.  The pool is
   * represented by the 'struct dma_pool' which keeps a doubly-linked list of
   * allocated pages.  Each page in the page_list is split into blocks of at
a35a34551   Matthew Wilcox   Change dmapool fr...
20
21
22
   * least 'size' bytes.  Free blocks are tracked in an unsorted singly-linked
   * list of free blocks within the page.  Used blocks aren't tracked, but we
   * keep a count of how many are currently allocated from each page.
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
23
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  
  #include <linux/device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  #include <linux/dma-mapping.h>
  #include <linux/dmapool.h>
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
28
29
  #include <linux/kernel.h>
  #include <linux/list.h>
b95f1b31b   Paul Gortmaker   mm: Map most file...
30
  #include <linux/export.h>
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
31
  #include <linux/mutex.h>
c9cf55285   Randy Dunlap   [PATCH] add poiso...
32
  #include <linux/poison.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
33
  #include <linux/sched.h>
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
34
  #include <linux/slab.h>
7c77509c5   Paul Gortmaker   mm: fix implicit ...
35
  #include <linux/stat.h>
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
36
37
38
39
  #include <linux/spinlock.h>
  #include <linux/string.h>
  #include <linux/types.h>
  #include <linux/wait.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40

b5ee5befa   Andi Kleen   dmapool: enable d...
41
42
43
  #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB_DEBUG_ON)
  #define DMAPOOL_DEBUG 1
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
44
45
46
  struct dma_pool {		/* the pool */
  	struct list_head page_list;
  	spinlock_t lock;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
47
48
49
  	size_t size;
  	struct device *dev;
  	size_t allocation;
e34f44b35   Matthew Wilcox   pool: Improve mem...
50
  	size_t boundary;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
51
  	char name[32];
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
52
  	struct list_head pools;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  };
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
54
55
56
57
  struct dma_page {		/* cacheable header for 'allocation' bytes */
  	struct list_head page_list;
  	void *vaddr;
  	dma_addr_t dma;
a35a34551   Matthew Wilcox   Change dmapool fr...
58
59
  	unsigned int in_use;
  	unsigned int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  };
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
61
  static DEFINE_MUTEX(pools_lock);
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
62
  static DEFINE_MUTEX(pools_reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  
  static ssize_t
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
65
  show_pools(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  {
  	unsigned temp;
  	unsigned size;
  	char *next;
  	struct dma_page *page;
  	struct dma_pool *pool;
  
  	next = buf;
  	size = PAGE_SIZE;
  
  	temp = scnprintf(next, size, "poolinfo - 0.1
  ");
  	size -= temp;
  	next += temp;
b2366d68d   Matthias Kaehlcke   Driver core: use ...
80
  	mutex_lock(&pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  	list_for_each_entry(pool, &dev->dma_pools, pools) {
  		unsigned pages = 0;
  		unsigned blocks = 0;
c49568235   Thomas Gleixner   dmapools: protect...
84
  		spin_lock_irq(&pool->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
  		list_for_each_entry(page, &pool->page_list, page_list) {
  			pages++;
  			blocks += page->in_use;
  		}
c49568235   Thomas Gleixner   dmapools: protect...
89
  		spin_unlock_irq(&pool->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
  
  		/* per-pool info, no real statistics yet */
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
92
93
  		temp = scnprintf(next, size, "%-16s %4u %4zu %4zu %2u
  ",
a35a34551   Matthew Wilcox   Change dmapool fr...
94
95
  				 pool->name, blocks,
  				 pages * (pool->allocation / pool->size),
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
96
  				 pool->size, pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  		size -= temp;
  		next += temp;
  	}
b2366d68d   Matthias Kaehlcke   Driver core: use ...
100
  	mutex_unlock(&pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
  
  	return PAGE_SIZE - size;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
104
105
  
  static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
112
  
  /**
   * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
   * @name: name of pool, for diagnostics
   * @dev: device that will be doing the DMA
   * @size: size of the blocks in this pool.
   * @align: alignment requirement for blocks; must be a power of two
e34f44b35   Matthew Wilcox   pool: Improve mem...
113
   * @boundary: returned blocks won't cross this power of two boundary
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
   * Context: !in_interrupt()
   *
   * Returns a dma allocation pool with the requested characteristics, or
   * null if one can't be created.  Given one of these pools, dma_pool_alloc()
   * may be used to allocate memory.  Such memory will all have "consistent"
   * DMA mappings, accessible by the device and its driver without using
   * cache flushing primitives.  The actual size of blocks allocated may be
   * larger than requested because of alignment.
   *
e34f44b35   Matthew Wilcox   pool: Improve mem...
123
   * If @boundary is nonzero, objects returned from dma_pool_alloc() won't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
   * cross that size boundary.  This is useful for devices which have
   * addressing restrictions on individual DMA transfers, such as not crossing
   * boundaries of 4KBytes.
   */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
128
  struct dma_pool *dma_pool_create(const char *name, struct device *dev,
e34f44b35   Matthew Wilcox   pool: Improve mem...
129
  				 size_t size, size_t align, size_t boundary)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
131
  	struct dma_pool *retval;
e34f44b35   Matthew Wilcox   pool: Improve mem...
132
  	size_t allocation;
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
133
  	bool empty = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

baa2ef839   Paul McQuade   mm/dmapool.c: fix...
135
  	if (align == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  		align = 1;
baa2ef839   Paul McQuade   mm/dmapool.c: fix...
137
  	else if (align & (align - 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

baa2ef839   Paul McQuade   mm/dmapool.c: fix...
140
  	if (size == 0)
399154be2   Matthew Wilcox   dmapool: Validate...
141
  		return NULL;
baa2ef839   Paul McQuade   mm/dmapool.c: fix...
142
  	else if (size < 4)
a35a34551   Matthew Wilcox   Change dmapool fr...
143
  		size = 4;
399154be2   Matthew Wilcox   dmapool: Validate...
144
145
146
  
  	if ((size % align) != 0)
  		size = ALIGN(size, align);
e34f44b35   Matthew Wilcox   pool: Improve mem...
147
  	allocation = max_t(size_t, size, PAGE_SIZE);
baa2ef839   Paul McQuade   mm/dmapool.c: fix...
148
  	if (!boundary)
e34f44b35   Matthew Wilcox   pool: Improve mem...
149
  		boundary = allocation;
baa2ef839   Paul McQuade   mm/dmapool.c: fix...
150
  	else if ((boundary < size) || (boundary & (boundary - 1)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  		return NULL;
e34f44b35   Matthew Wilcox   pool: Improve mem...
152
153
  	retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev));
  	if (!retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  		return retval;
e34f44b35   Matthew Wilcox   pool: Improve mem...
155
  	strlcpy(retval->name, name, sizeof(retval->name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  
  	retval->dev = dev;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
158
159
  	INIT_LIST_HEAD(&retval->page_list);
  	spin_lock_init(&retval->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  	retval->size = size;
e34f44b35   Matthew Wilcox   pool: Improve mem...
161
  	retval->boundary = boundary;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  	retval->allocation = allocation;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163

cc6b664aa   Daeseok Youn   mm/dmapool.c: rem...
164
  	INIT_LIST_HEAD(&retval->pools);
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
165
166
167
168
169
170
171
172
173
  	/*
  	 * pools_lock ensures that the ->dma_pools list does not get corrupted.
  	 * pools_reg_lock ensures that there is not a race between
  	 * dma_pool_create() and dma_pool_destroy() or within dma_pool_create()
  	 * when the first invocation of dma_pool_create() failed on
  	 * device_create_file() and the second assumes that it has been done (I
  	 * know it is a short window).
  	 */
  	mutex_lock(&pools_reg_lock);
cc6b664aa   Daeseok Youn   mm/dmapool.c: rem...
174
  	mutex_lock(&pools_lock);
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
175
176
177
  	if (list_empty(&dev->dma_pools))
  		empty = true;
  	list_add(&retval->pools, &dev->dma_pools);
cc6b664aa   Daeseok Youn   mm/dmapool.c: rem...
178
  	mutex_unlock(&pools_lock);
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  	if (empty) {
  		int err;
  
  		err = device_create_file(dev, &dev_attr_pools);
  		if (err) {
  			mutex_lock(&pools_lock);
  			list_del(&retval->pools);
  			mutex_unlock(&pools_lock);
  			mutex_unlock(&pools_reg_lock);
  			kfree(retval);
  			return NULL;
  		}
  	}
  	mutex_unlock(&pools_reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  	return retval;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
195
  EXPORT_SYMBOL(dma_pool_create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196

a35a34551   Matthew Wilcox   Change dmapool fr...
197
198
199
  static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page)
  {
  	unsigned int offset = 0;
e34f44b35   Matthew Wilcox   pool: Improve mem...
200
  	unsigned int next_boundary = pool->boundary;
a35a34551   Matthew Wilcox   Change dmapool fr...
201
202
203
  
  	do {
  		unsigned int next = offset + pool->size;
e34f44b35   Matthew Wilcox   pool: Improve mem...
204
205
206
207
  		if (unlikely((next + pool->size) >= next_boundary)) {
  			next = next_boundary;
  			next_boundary += pool->boundary;
  		}
a35a34551   Matthew Wilcox   Change dmapool fr...
208
209
210
211
  		*(int *)(page->vaddr + offset) = next;
  		offset = next;
  	} while (offset < pool->allocation);
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
212
  static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
214
  	struct dma_page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215

a35a34551   Matthew Wilcox   Change dmapool fr...
216
  	page = kmalloc(sizeof(*page), mem_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  	if (!page)
  		return NULL;
a35a34551   Matthew Wilcox   Change dmapool fr...
219
  	page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation,
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
220
  					 &page->dma, mem_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  	if (page->vaddr) {
b5ee5befa   Andi Kleen   dmapool: enable d...
222
  #ifdef	DMAPOOL_DEBUG
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
223
  		memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  #endif
a35a34551   Matthew Wilcox   Change dmapool fr...
225
  		pool_initialise_page(pool, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  		page->in_use = 0;
a35a34551   Matthew Wilcox   Change dmapool fr...
227
  		page->offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
  	} else {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
229
  		kfree(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
  		page = NULL;
  	}
  	return page;
  }
d9e7e37b4   Nicholas Krause   mm/dmapool.c: cha...
234
  static inline bool is_page_busy(struct dma_page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  {
a35a34551   Matthew Wilcox   Change dmapool fr...
236
  	return page->in_use != 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
238
  static void pool_free_page(struct dma_pool *pool, struct dma_page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
240
  	dma_addr_t dma = page->dma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241

b5ee5befa   Andi Kleen   dmapool: enable d...
242
  #ifdef	DMAPOOL_DEBUG
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
243
  	memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
245
246
247
  	dma_free_coherent(pool->dev, pool->allocation, page->vaddr, dma);
  	list_del(&page->page_list);
  	kfree(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
  /**
   * dma_pool_destroy - destroys a pool of dma memory blocks.
   * @pool: dma pool that will be destroyed
   * Context: !in_interrupt()
   *
   * Caller guarantees that no more memory from the pool is in use,
   * and that nothing will try to use the pool after this call.
   */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
257
  void dma_pool_destroy(struct dma_pool *pool)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  {
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
259
  	bool empty = false;
44d7175da   Sergey Senozhatsky   mm/dmapool: allow...
260
261
  	if (unlikely(!pool))
  		return;
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
262
  	mutex_lock(&pools_reg_lock);
b2366d68d   Matthias Kaehlcke   Driver core: use ...
263
  	mutex_lock(&pools_lock);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
264
265
  	list_del(&pool->pools);
  	if (pool->dev && list_empty(&pool->dev->dma_pools))
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
266
  		empty = true;
b2366d68d   Matthias Kaehlcke   Driver core: use ...
267
  	mutex_unlock(&pools_lock);
01c2965f0   Sebastian Andrzej Siewior   mm: dmapool: add/...
268
269
270
  	if (empty)
  		device_remove_file(pool->dev, &dev_attr_pools);
  	mutex_unlock(&pools_reg_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
272
273
274
275
  	while (!list_empty(&pool->page_list)) {
  		struct dma_page *page;
  		page = list_entry(pool->page_list.next,
  				  struct dma_page, page_list);
a35a34551   Matthew Wilcox   Change dmapool fr...
276
  		if (is_page_busy(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  			if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
278
279
280
  				dev_err(pool->dev,
  					"dma_pool_destroy %s, %p busy
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
  					pool->name, page->vaddr);
  			else
1170532bb   Joe Perches   mm: convert print...
283
284
  				pr_err("dma_pool_destroy %s, %p busy
  ",
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
285
  				       pool->name, page->vaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  			/* leak the still-in-use consistent memory */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
287
288
  			list_del(&page->page_list);
  			kfree(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  		} else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
290
  			pool_free_page(pool, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
292
  	kfree(pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
294
  EXPORT_SYMBOL(dma_pool_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
303
  
  /**
   * dma_pool_alloc - get a block of consistent memory
   * @pool: dma pool that will produce the block
   * @mem_flags: GFP_* bitmask
   * @handle: pointer to dma address of block
   *
   * This returns the kernel virtual address of a currently unused block,
   * and reports its dma address through the handle.
6182a0943   Matthew Wilcox   dmapool: Tidy up ...
304
   * If such a memory block can't be allocated, %NULL is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
   */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
306
307
  void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
  		     dma_addr_t *handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
309
310
  	unsigned long flags;
  	struct dma_page *page;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
311
312
  	size_t offset;
  	void *retval;
d0164adc8   Mel Gorman   mm, page_alloc: d...
313
  	might_sleep_if(gfpflags_allow_blocking(mem_flags));
ea05c8444   Dima Zavin   mm: add a might_s...
314

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
315
  	spin_lock_irqsave(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  	list_for_each_entry(page, &pool->page_list, page_list) {
a35a34551   Matthew Wilcox   Change dmapool fr...
317
318
  		if (page->offset < pool->allocation)
  			goto ready;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320

387870f2d   Marek Szyprowski   mm: dmapool: use ...
321
322
  	/* pool_alloc_page() might sleep, so temporarily drop &pool->lock */
  	spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323

fa23f56d9   Sean O. Stalley   mm: add support f...
324
  	page = pool_alloc_page(pool, mem_flags & (~__GFP_ZERO));
387870f2d   Marek Szyprowski   mm: dmapool: use ...
325
326
  	if (!page)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327

387870f2d   Marek Szyprowski   mm: dmapool: use ...
328
  	spin_lock_irqsave(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329

387870f2d   Marek Szyprowski   mm: dmapool: use ...
330
  	list_add(&page->page_list, &pool->page_list);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
331
   ready:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  	page->in_use++;
a35a34551   Matthew Wilcox   Change dmapool fr...
333
334
  	offset = page->offset;
  	page->offset = *(int *)(page->vaddr + offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
  	retval = offset + page->vaddr;
  	*handle = offset + page->dma;
b5ee5befa   Andi Kleen   dmapool: enable d...
337
  #ifdef	DMAPOOL_DEBUG
5de55b265   Matthieu CASTET   dmapool: make DMA...
338
339
340
341
342
343
344
345
346
  	{
  		int i;
  		u8 *data = retval;
  		/* page->offset is stored in first 4 bytes */
  		for (i = sizeof(page->offset); i < pool->size; i++) {
  			if (data[i] == POOL_POISON_FREED)
  				continue;
  			if (pool->dev)
  				dev_err(pool->dev,
5835f2511   Hiroshige Sato   mm: Fix printk ty...
347
348
  					"dma_pool_alloc %s, %p (corrupted)
  ",
5de55b265   Matthieu CASTET   dmapool: make DMA...
349
350
  					pool->name, retval);
  			else
5835f2511   Hiroshige Sato   mm: Fix printk ty...
351
352
  				pr_err("dma_pool_alloc %s, %p (corrupted)
  ",
5de55b265   Matthieu CASTET   dmapool: make DMA...
353
354
355
356
357
358
359
360
361
362
363
  					pool->name, retval);
  
  			/*
  			 * Dump the first 4 bytes even if they are not
  			 * POOL_POISON_FREED
  			 */
  			print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1,
  					data, pool->size, 1);
  			break;
  		}
  	}
fa23f56d9   Sean O. Stalley   mm: add support f...
364
365
  	if (!(mem_flags & __GFP_ZERO))
  		memset(retval, POOL_POISON_ALLOCATED, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
367
  	spin_unlock_irqrestore(&pool->lock, flags);
fa23f56d9   Sean O. Stalley   mm: add support f...
368
369
370
  
  	if (mem_flags & __GFP_ZERO)
  		memset(retval, 0, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
  	return retval;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
373
  EXPORT_SYMBOL(dma_pool_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
375
  static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
377
  	struct dma_page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
  	list_for_each_entry(page, &pool->page_list, page_list) {
  		if (dma < page->dma)
  			continue;
676bd9917   Robin Murphy   dmapool: fix over...
382
  		if ((dma - page->dma) < pool->allocation)
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
383
  			return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  	}
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
385
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
392
393
394
395
  /**
   * dma_pool_free - put block back into dma pool
   * @pool: the dma pool holding the block
   * @vaddr: virtual address of block
   * @dma: dma address of block
   *
   * Caller promises neither device nor driver will again touch this block
   * unless it is first re-allocated.
   */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
396
  void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
398
399
  	struct dma_page *page;
  	unsigned long flags;
a35a34551   Matthew Wilcox   Change dmapool fr...
400
  	unsigned int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401

84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
402
  	spin_lock_irqsave(&pool->lock, flags);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
403
404
  	page = pool_find_page(pool, dma);
  	if (!page) {
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
405
  		spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  		if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
407
408
409
410
  			dev_err(pool->dev,
  				"dma_pool_free %s, %p/%lx (bad dma)
  ",
  				pool->name, vaddr, (unsigned long)dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  		else
1170532bb   Joe Perches   mm: convert print...
412
413
  			pr_err("dma_pool_free %s, %p/%lx (bad dma)
  ",
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
414
  			       pool->name, vaddr, (unsigned long)dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
  		return;
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
417
  	offset = vaddr - page->vaddr;
b5ee5befa   Andi Kleen   dmapool: enable d...
418
  #ifdef	DMAPOOL_DEBUG
a35a34551   Matthew Wilcox   Change dmapool fr...
419
  	if ((dma - page->dma) != offset) {
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
420
  		spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  		if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
422
  			dev_err(pool->dev,
199eaa05a   Miles Chen   mm: cleanups for ...
423
424
425
  				"dma_pool_free %s, %p (bad vaddr)/%pad
  ",
  				pool->name, vaddr, &dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  		else
199eaa05a   Miles Chen   mm: cleanups for ...
427
428
429
  			pr_err("dma_pool_free %s, %p (bad vaddr)/%pad
  ",
  			       pool->name, vaddr, &dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  		return;
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
432
433
434
435
436
437
438
  	{
  		unsigned int chain = page->offset;
  		while (chain < pool->allocation) {
  			if (chain != offset) {
  				chain = *(int *)(page->vaddr + chain);
  				continue;
  			}
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
439
  			spin_unlock_irqrestore(&pool->lock, flags);
a35a34551   Matthew Wilcox   Change dmapool fr...
440
  			if (pool->dev)
199eaa05a   Miles Chen   mm: cleanups for ...
441
442
443
  				dev_err(pool->dev, "dma_pool_free %s, dma %pad already free
  ",
  					pool->name, &dma);
a35a34551   Matthew Wilcox   Change dmapool fr...
444
  			else
199eaa05a   Miles Chen   mm: cleanups for ...
445
446
447
  				pr_err("dma_pool_free %s, dma %pad already free
  ",
  				       pool->name, &dma);
a35a34551   Matthew Wilcox   Change dmapool fr...
448
449
  			return;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
451
  	memset(vaddr, POOL_POISON_FREED, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  	page->in_use--;
a35a34551   Matthew Wilcox   Change dmapool fr...
454
455
  	*(int *)vaddr = page->offset;
  	page->offset = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  	/*
  	 * Resist a temptation to do
a35a34551   Matthew Wilcox   Change dmapool fr...
458
  	 *    if (!is_page_busy(page)) pool_free_page(pool, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
  	 * Better have a few empty pages hang around.
  	 */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
461
  	spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
463
  EXPORT_SYMBOL(dma_pool_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

9ac7849e3   Tejun Heo   devres: device re...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  /*
   * Managed DMA pool
   */
  static void dmam_pool_release(struct device *dev, void *res)
  {
  	struct dma_pool *pool = *(struct dma_pool **)res;
  
  	dma_pool_destroy(pool);
  }
  
  static int dmam_pool_match(struct device *dev, void *res, void *match_data)
  {
  	return *(struct dma_pool **)res == match_data;
  }
  
  /**
   * dmam_pool_create - Managed dma_pool_create()
   * @name: name of pool, for diagnostics
   * @dev: device that will be doing the DMA
   * @size: size of the blocks in this pool.
   * @align: alignment requirement for blocks; must be a power of two
   * @allocation: returned blocks won't cross this boundary (or zero)
   *
   * Managed dma_pool_create().  DMA pool created with this function is
   * automatically destroyed on driver detach.
   */
  struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
  				  size_t size, size_t align, size_t allocation)
  {
  	struct dma_pool **ptr, *pool;
  
  	ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
  	if (!ptr)
  		return NULL;
  
  	pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
  	if (pool)
  		devres_add(dev, ptr);
  	else
  		devres_free(ptr);
  
  	return pool;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
508
  EXPORT_SYMBOL(dmam_pool_create);
9ac7849e3   Tejun Heo   devres: device re...
509
510
511
512
513
514
515
516
517
518
  
  /**
   * dmam_pool_destroy - Managed dma_pool_destroy()
   * @pool: dma pool that will be destroyed
   *
   * Managed dma_pool_destroy().
   */
  void dmam_pool_destroy(struct dma_pool *pool)
  {
  	struct device *dev = pool->dev;
172cb4b3d   Andy Shevchenko   mm/dmapool.c: reu...
519
  	WARN_ON(devres_release(dev, dmam_pool_release, dmam_pool_match, pool));
9ac7849e3   Tejun Heo   devres: device re...
520
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
521
  EXPORT_SYMBOL(dmam_pool_destroy);