Blame view

mm/dmapool.c 13 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <linux/module.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
35
36
37
38
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/string.h>
  #include <linux/types.h>
  #include <linux/wait.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

b5ee5befa   Andi Kleen   dmapool: enable d...
40
41
42
  #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB_DEBUG_ON)
  #define DMAPOOL_DEBUG 1
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
43
44
45
  struct dma_pool {		/* the pool */
  	struct list_head page_list;
  	spinlock_t lock;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
46
47
48
  	size_t size;
  	struct device *dev;
  	size_t allocation;
e34f44b35   Matthew Wilcox   pool: Improve mem...
49
  	size_t boundary;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
50
51
52
  	char name[32];
  	wait_queue_head_t waitq;
  	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
61
62
  };
  
  #define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
64
  static DEFINE_MUTEX(pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
  
  static ssize_t
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
67
  show_pools(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  {
  	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 ...
82
  	mutex_lock(&pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
  	list_for_each_entry(pool, &dev->dma_pools, pools) {
  		unsigned pages = 0;
  		unsigned blocks = 0;
c49568235   Thomas Gleixner   dmapools: protect...
86
  		spin_lock_irq(&pool->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
  		list_for_each_entry(page, &pool->page_list, page_list) {
  			pages++;
  			blocks += page->in_use;
  		}
c49568235   Thomas Gleixner   dmapools: protect...
91
  		spin_unlock_irq(&pool->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
  
  		/* per-pool info, no real statistics yet */
  		temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u
  ",
a35a34551   Matthew Wilcox   Change dmapool fr...
96
97
  				 pool->name, blocks,
  				 pages * (pool->allocation / pool->size),
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
98
  				 pool->size, pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
  		size -= temp;
  		next += temp;
  	}
b2366d68d   Matthias Kaehlcke   Driver core: use ...
102
  	mutex_unlock(&pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
  
  	return PAGE_SIZE - size;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
106
107
  
  static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
  
  /**
   * 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...
115
   * @boundary: returned blocks won't cross this power of two boundary
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
123
124
   * 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...
125
   * If @boundary is nonzero, objects returned from dma_pool_alloc() won't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
   * 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...
130
  struct dma_pool *dma_pool_create(const char *name, struct device *dev,
e34f44b35   Matthew Wilcox   pool: Improve mem...
131
  				 size_t size, size_t align, size_t boundary)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
133
  	struct dma_pool *retval;
e34f44b35   Matthew Wilcox   pool: Improve mem...
134
  	size_t allocation;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135

399154be2   Matthew Wilcox   dmapool: Validate...
136
  	if (align == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  		align = 1;
399154be2   Matthew Wilcox   dmapool: Validate...
138
  	} else if (align & (align - 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
141
  	if (size == 0) {
399154be2   Matthew Wilcox   dmapool: Validate...
142
  		return NULL;
a35a34551   Matthew Wilcox   Change dmapool fr...
143
144
145
  	} else if (size < 4) {
  		size = 4;
  	}
399154be2   Matthew Wilcox   dmapool: Validate...
146
147
148
  
  	if ((size % align) != 0)
  		size = ALIGN(size, align);
e34f44b35   Matthew Wilcox   pool: Improve mem...
149
150
151
152
153
  	allocation = max_t(size_t, size, PAGE_SIZE);
  
  	if (!boundary) {
  		boundary = allocation;
  	} else if ((boundary < size) || (boundary & (boundary - 1))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  		return NULL;
e34f44b35   Matthew Wilcox   pool: Improve mem...
155
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156

e34f44b35   Matthew Wilcox   pool: Improve mem...
157
158
  	retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev));
  	if (!retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  		return retval;
e34f44b35   Matthew Wilcox   pool: Improve mem...
160
  	strlcpy(retval->name, name, sizeof(retval->name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
  
  	retval->dev = dev;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
163
164
  	INIT_LIST_HEAD(&retval->page_list);
  	spin_lock_init(&retval->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	retval->size = size;
e34f44b35   Matthew Wilcox   pool: Improve mem...
166
  	retval->boundary = boundary;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  	retval->allocation = allocation;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
168
  	init_waitqueue_head(&retval->waitq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  
  	if (dev) {
141ecc532   Cornelia Huck   driver core fixes...
171
  		int ret;
b2366d68d   Matthias Kaehlcke   Driver core: use ...
172
  		mutex_lock(&pools_lock);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
173
174
  		if (list_empty(&dev->dma_pools))
  			ret = device_create_file(dev, &dev_attr_pools);
141ecc532   Cornelia Huck   driver core fixes...
175
176
  		else
  			ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  		/* note:  not currently insisting "name" be unique */
141ecc532   Cornelia Huck   driver core fixes...
178
  		if (!ret)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
179
  			list_add(&retval->pools, &dev->dma_pools);
141ecc532   Cornelia Huck   driver core fixes...
180
181
182
183
  		else {
  			kfree(retval);
  			retval = NULL;
  		}
b2366d68d   Matthias Kaehlcke   Driver core: use ...
184
  		mutex_unlock(&pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	} else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
186
  		INIT_LIST_HEAD(&retval->pools);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
  
  	return retval;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
190
  EXPORT_SYMBOL(dma_pool_create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191

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

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

b5ee5befa   Andi Kleen   dmapool: enable d...
238
  #ifdef	DMAPOOL_DEBUG
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
239
  	memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
241
242
243
  	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
244
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
250
251
252
  /**
   * 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...
253
  void dma_pool_destroy(struct dma_pool *pool)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  {
b2366d68d   Matthias Kaehlcke   Driver core: use ...
255
  	mutex_lock(&pools_lock);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
256
257
258
  	list_del(&pool->pools);
  	if (pool->dev && list_empty(&pool->dev->dma_pools))
  		device_remove_file(pool->dev, &dev_attr_pools);
b2366d68d   Matthias Kaehlcke   Driver core: use ...
259
  	mutex_unlock(&pools_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
261
262
263
264
  	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...
265
  		if (is_page_busy(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  			if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
267
268
269
  				dev_err(pool->dev,
  					"dma_pool_destroy %s, %p busy
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
  					pool->name, page->vaddr);
  			else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
272
273
274
275
  				printk(KERN_ERR
  				       "dma_pool_destroy %s, %p busy
  ",
  				       pool->name, page->vaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  			/* leak the still-in-use consistent memory */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
277
278
  			list_del(&page->page_list);
  			kfree(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  		} else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
280
  			pool_free_page(pool, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
282
  	kfree(pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
284
  EXPORT_SYMBOL(dma_pool_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
290
291
292
293
  
  /**
   * 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 ...
294
   * If such a memory block can't be allocated, %NULL is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
   */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
296
297
  void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
  		     dma_addr_t *handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
299
300
  	unsigned long flags;
  	struct dma_page *page;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
301
302
  	size_t offset;
  	void *retval;
ea05c8444   Dima Zavin   mm: add a might_s...
303
  	might_sleep_if(mem_flags & __GFP_WAIT);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
304
  	spin_lock_irqsave(&pool->lock, flags);
2cae367e4   Matthew Wilcox   Avoid taking wait...
305
   restart:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  	list_for_each_entry(page, &pool->page_list, page_list) {
a35a34551   Matthew Wilcox   Change dmapool fr...
307
308
  		if (page->offset < pool->allocation)
  			goto ready;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
310
311
  	page = pool_alloc_page(pool, GFP_ATOMIC);
  	if (!page) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  		if (mem_flags & __GFP_WAIT) {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
313
  			DECLARE_WAITQUEUE(wait, current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314

684265d4a   Andrew Morton   mm/dmapool.c: use...
315
  			__set_current_state(TASK_UNINTERRUPTIBLE);
2cae367e4   Matthew Wilcox   Avoid taking wait...
316
  			__add_wait_queue(&pool->waitq, &wait);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
317
  			spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
319
  			schedule_timeout(POOL_TIMEOUT_JIFFIES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320

2cae367e4   Matthew Wilcox   Avoid taking wait...
321
322
  			spin_lock_irqsave(&pool->lock, flags);
  			__remove_wait_queue(&pool->waitq, &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
  			goto restart;
  		}
  		retval = NULL;
  		goto done;
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
328
   ready:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  	page->in_use++;
a35a34551   Matthew Wilcox   Change dmapool fr...
330
331
  	offset = page->offset;
  	page->offset = *(int *)(page->vaddr + offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  	retval = offset + page->vaddr;
  	*handle = offset + page->dma;
b5ee5befa   Andi Kleen   dmapool: enable d...
334
  #ifdef	DMAPOOL_DEBUG
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
335
  	memset(retval, POOL_POISON_ALLOCATED, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
337
338
   done:
  	spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
  	return retval;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
341
  EXPORT_SYMBOL(dma_pool_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
343
  static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
345
  	struct dma_page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
  	list_for_each_entry(page, &pool->page_list, page_list) {
  		if (dma < page->dma)
  			continue;
  		if (dma < (page->dma + pool->allocation))
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
351
  			return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	}
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
353
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
360
361
362
363
  /**
   * 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...
364
  void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
366
367
  	struct dma_page *page;
  	unsigned long flags;
a35a34551   Matthew Wilcox   Change dmapool fr...
368
  	unsigned int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369

84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
370
  	spin_lock_irqsave(&pool->lock, flags);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
371
372
  	page = pool_find_page(pool, dma);
  	if (!page) {
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
373
  		spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  		if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
375
376
377
378
  			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
379
  		else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
380
381
382
  			printk(KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)
  ",
  			       pool->name, vaddr, (unsigned long)dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  		return;
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
385
  	offset = vaddr - page->vaddr;
b5ee5befa   Andi Kleen   dmapool: enable d...
386
  #ifdef	DMAPOOL_DEBUG
a35a34551   Matthew Wilcox   Change dmapool fr...
387
  	if ((dma - page->dma) != offset) {
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
388
  		spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  		if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
390
391
392
393
  			dev_err(pool->dev,
  				"dma_pool_free %s, %p (bad vaddr)/%Lx
  ",
  				pool->name, vaddr, (unsigned long long)dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  		else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
395
396
397
398
  			printk(KERN_ERR
  			       "dma_pool_free %s, %p (bad vaddr)/%Lx
  ",
  			       pool->name, vaddr, (unsigned long long)dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
  		return;
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
401
402
403
404
405
406
407
  	{
  		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...
408
  			spin_unlock_irqrestore(&pool->lock, flags);
a35a34551   Matthew Wilcox   Change dmapool fr...
409
410
411
412
413
414
415
416
417
418
419
420
  			if (pool->dev)
  				dev_err(pool->dev, "dma_pool_free %s, dma %Lx "
  					"already free
  ", pool->name,
  					(unsigned long long)dma);
  			else
  				printk(KERN_ERR "dma_pool_free %s, dma %Lx "
  					"already free
  ", pool->name,
  					(unsigned long long)dma);
  			return;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
422
  	memset(vaddr, POOL_POISON_FREED, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	page->in_use--;
a35a34551   Matthew Wilcox   Change dmapool fr...
425
426
  	*(int *)vaddr = page->offset;
  	page->offset = offset;
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
427
  	if (waitqueue_active(&pool->waitq))
2cae367e4   Matthew Wilcox   Avoid taking wait...
428
  		wake_up_locked(&pool->waitq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
  	/*
  	 * Resist a temptation to do
a35a34551   Matthew Wilcox   Change dmapool fr...
431
  	 *    if (!is_page_busy(page)) pool_free_page(pool, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
  	 * Better have a few empty pages hang around.
  	 */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
434
  	spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
436
  EXPORT_SYMBOL(dma_pool_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

9ac7849e3   Tejun Heo   devres: device re...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  /*
   * 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...
481
  EXPORT_SYMBOL(dmam_pool_create);
9ac7849e3   Tejun Heo   devres: device re...
482
483
484
485
486
487
488
489
490
491
  
  /**
   * 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;
9ac7849e3   Tejun Heo   devres: device re...
492
  	WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
ae891a1b9   Maxin B John   devres: fix possi...
493
  	dma_pool_destroy(pool);
9ac7849e3   Tejun Heo   devres: device re...
494
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
495
  EXPORT_SYMBOL(dmam_pool_destroy);