Blame view

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

399154be2   Matthew Wilcox   dmapool: Validate...
133
  	if (align == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  		align = 1;
399154be2   Matthew Wilcox   dmapool: Validate...
135
  	} else if (align & (align - 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
138
  	if (size == 0) {
399154be2   Matthew Wilcox   dmapool: Validate...
139
  		return NULL;
a35a34551   Matthew Wilcox   Change dmapool fr...
140
141
142
  	} else if (size < 4) {
  		size = 4;
  	}
399154be2   Matthew Wilcox   dmapool: Validate...
143
144
145
  
  	if ((size % align) != 0)
  		size = ALIGN(size, align);
e34f44b35   Matthew Wilcox   pool: Improve mem...
146
147
148
149
150
  	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
151
  		return NULL;
e34f44b35   Matthew Wilcox   pool: Improve mem...
152
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153

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

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

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

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

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

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

387870f2d   Marek Szyprowski   mm: dmapool: use ...
308
309
310
  	page = pool_alloc_page(pool, mem_flags);
  	if (!page)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311

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

387870f2d   Marek Szyprowski   mm: dmapool: use ...
314
  	list_add(&page->page_list, &pool->page_list);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
315
   ready:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  	page->in_use++;
a35a34551   Matthew Wilcox   Change dmapool fr...
317
318
  	offset = page->offset;
  	page->offset = *(int *)(page->vaddr + offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	retval = offset + page->vaddr;
  	*handle = offset + page->dma;
b5ee5befa   Andi Kleen   dmapool: enable d...
321
  #ifdef	DMAPOOL_DEBUG
5de55b265   Matthieu CASTET   dmapool: make DMA...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
  	{
  		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,
  					"dma_pool_alloc %s, %p (corruped)
  ",
  					pool->name, retval);
  			else
  				pr_err("dma_pool_alloc %s, %p (corruped)
  ",
  					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;
  		}
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
348
  	memset(retval, POOL_POISON_ALLOCATED, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  #endif
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
350
  	spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  	return retval;
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
353
  EXPORT_SYMBOL(dma_pool_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354

e87aa7737   Matthew Wilcox   dmapool: Fix styl...
355
  static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
357
  	struct dma_page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
  	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...
363
  			return page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	}
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
365
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
  /**
   * 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...
376
  void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  {
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
378
379
  	struct dma_page *page;
  	unsigned long flags;
a35a34551   Matthew Wilcox   Change dmapool fr...
380
  	unsigned int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381

84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
382
  	spin_lock_irqsave(&pool->lock, flags);
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
383
384
  	page = pool_find_page(pool, dma);
  	if (!page) {
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
385
  		spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  		if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
387
388
389
390
  			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
391
  		else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
392
393
394
  			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
395
396
  		return;
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
397
  	offset = vaddr - page->vaddr;
b5ee5befa   Andi Kleen   dmapool: enable d...
398
  #ifdef	DMAPOOL_DEBUG
a35a34551   Matthew Wilcox   Change dmapool fr...
399
  	if ((dma - page->dma) != offset) {
84bc227d7   Rolf Eike Beer   mm/dmapool.c: tak...
400
  		spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  		if (pool->dev)
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
402
403
404
405
  			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
406
  		else
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
407
408
409
410
  			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
411
412
  		return;
  	}
a35a34551   Matthew Wilcox   Change dmapool fr...
413
414
415
416
417
418
419
  	{
  		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...
420
  			spin_unlock_irqrestore(&pool->lock, flags);
a35a34551   Matthew Wilcox   Change dmapool fr...
421
422
423
424
425
426
427
428
429
430
431
432
  			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
433
  	}
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
434
  	memset(vaddr, POOL_POISON_FREED, pool->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  	page->in_use--;
a35a34551   Matthew Wilcox   Change dmapool fr...
437
438
  	*(int *)vaddr = page->offset;
  	page->offset = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	/*
  	 * Resist a temptation to do
a35a34551   Matthew Wilcox   Change dmapool fr...
441
  	 *    if (!is_page_busy(page)) pool_free_page(pool, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  	 * Better have a few empty pages hang around.
  	 */
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
444
  	spin_unlock_irqrestore(&pool->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
446
  EXPORT_SYMBOL(dma_pool_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447

9ac7849e3   Tejun Heo   devres: device re...
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
481
482
483
484
485
486
487
488
489
490
  /*
   * 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...
491
  EXPORT_SYMBOL(dmam_pool_create);
9ac7849e3   Tejun Heo   devres: device re...
492
493
494
495
496
497
498
499
500
501
  
  /**
   * 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...
502
  	WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
ae891a1b9   Maxin B John   devres: fix possi...
503
  	dma_pool_destroy(pool);
9ac7849e3   Tejun Heo   devres: device re...
504
  }
e87aa7737   Matthew Wilcox   dmapool: Fix styl...
505
  EXPORT_SYMBOL(dmam_pool_destroy);