diff options
Diffstat (limited to 'mm/dmapool.c')
| -rw-r--r-- | mm/dmapool.c | 99 | 
1 files changed, 48 insertions, 51 deletions
diff --git a/mm/dmapool.c b/mm/dmapool.c index 4df2de77e06..306baa594f9 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -27,11 +27,12 @@  #include <linux/dmapool.h>  #include <linux/kernel.h>  #include <linux/list.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/mutex.h>  #include <linux/poison.h>  #include <linux/sched.h>  #include <linux/slab.h> +#include <linux/stat.h>  #include <linux/spinlock.h>  #include <linux/string.h>  #include <linux/types.h> @@ -49,7 +50,6 @@ struct dma_pool {		/* the pool */  	size_t allocation;  	size_t boundary;  	char name[32]; -	wait_queue_head_t waitq;  	struct list_head pools;  }; @@ -61,8 +61,6 @@ struct dma_page {		/* cacheable header for 'allocation' bytes */  	unsigned int offset;  }; -#define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000) -  static DEFINE_MUTEX(pools_lock);  static ssize_t @@ -171,26 +169,17 @@ struct dma_pool *dma_pool_create(const char *name, struct device *dev,  	retval->size = size;  	retval->boundary = boundary;  	retval->allocation = allocation; -	init_waitqueue_head(&retval->waitq); -	if (dev) { -		int ret; +	INIT_LIST_HEAD(&retval->pools); -		mutex_lock(&pools_lock); -		if (list_empty(&dev->dma_pools)) -			ret = device_create_file(dev, &dev_attr_pools); -		else -			ret = 0; -		/* note:  not currently insisting "name" be unique */ -		if (!ret) -			list_add(&retval->pools, &dev->dma_pools); -		else { -			kfree(retval); -			retval = NULL; -		} -		mutex_unlock(&pools_lock); +	mutex_lock(&pools_lock); +	if (list_empty(&dev->dma_pools) && +	    device_create_file(dev, &dev_attr_pools)) { +		kfree(retval); +		return NULL;  	} else -		INIT_LIST_HEAD(&retval->pools); +		list_add(&retval->pools, &dev->dma_pools); +	mutex_unlock(&pools_lock);  	return retval;  } @@ -226,7 +215,6 @@ static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)  		memset(page->vaddr, POOL_POISON_FREED, pool->allocation);  #endif  		pool_initialise_page(pool, page); -		list_add(&page->page_list, &pool->page_list);  		page->in_use = 0;  		page->offset = 0;  	} else { @@ -314,30 +302,21 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,  	might_sleep_if(mem_flags & __GFP_WAIT);  	spin_lock_irqsave(&pool->lock, flags); - restart:  	list_for_each_entry(page, &pool->page_list, page_list) {  		if (page->offset < pool->allocation)  			goto ready;  	} -	page = pool_alloc_page(pool, GFP_ATOMIC); -	if (!page) { -		if (mem_flags & __GFP_WAIT) { -			DECLARE_WAITQUEUE(wait, current); -			__set_current_state(TASK_INTERRUPTIBLE); -			__add_wait_queue(&pool->waitq, &wait); -			spin_unlock_irqrestore(&pool->lock, flags); +	/* pool_alloc_page() might sleep, so temporarily drop &pool->lock */ +	spin_unlock_irqrestore(&pool->lock, flags); -			schedule_timeout(POOL_TIMEOUT_JIFFIES); +	page = pool_alloc_page(pool, mem_flags); +	if (!page) +		return NULL; -			spin_lock_irqsave(&pool->lock, flags); -			__remove_wait_queue(&pool->waitq, &wait); -			goto restart; -		} -		retval = NULL; -		goto done; -	} +	spin_lock_irqsave(&pool->lock, flags); +	list_add(&page->page_list, &pool->page_list);   ready:  	page->in_use++;  	offset = page->offset; @@ -345,9 +324,32 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,  	retval = offset + page->vaddr;  	*handle = offset + page->dma;  #ifdef	DMAPOOL_DEBUG +	{ +		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 (corrupted)\n", +					pool->name, retval); +			else +				pr_err("dma_pool_alloc %s, %p (corrupted)\n", +					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; +		} +	}  	memset(retval, POOL_POISON_ALLOCATED, pool->size);  #endif - done:  	spin_unlock_irqrestore(&pool->lock, flags);  	return retval;  } @@ -355,20 +357,15 @@ EXPORT_SYMBOL(dma_pool_alloc);  static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)  { -	unsigned long flags;  	struct dma_page *page; -	spin_lock_irqsave(&pool->lock, flags);  	list_for_each_entry(page, &pool->page_list, page_list) {  		if (dma < page->dma)  			continue;  		if (dma < (page->dma + pool->allocation)) -			goto done; +			return page;  	} -	page = NULL; - done: -	spin_unlock_irqrestore(&pool->lock, flags); -	return page; +	return NULL;  }  /** @@ -386,8 +383,10 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)  	unsigned long flags;  	unsigned int offset; +	spin_lock_irqsave(&pool->lock, flags);  	page = pool_find_page(pool, dma);  	if (!page) { +		spin_unlock_irqrestore(&pool->lock, flags);  		if (pool->dev)  			dev_err(pool->dev,  				"dma_pool_free %s, %p/%lx (bad dma)\n", @@ -401,6 +400,7 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)  	offset = vaddr - page->vaddr;  #ifdef	DMAPOOL_DEBUG  	if ((dma - page->dma) != offset) { +		spin_unlock_irqrestore(&pool->lock, flags);  		if (pool->dev)  			dev_err(pool->dev,  				"dma_pool_free %s, %p (bad vaddr)/%Lx\n", @@ -418,6 +418,7 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)  				chain = *(int *)(page->vaddr + chain);  				continue;  			} +			spin_unlock_irqrestore(&pool->lock, flags);  			if (pool->dev)  				dev_err(pool->dev, "dma_pool_free %s, dma %Lx "  					"already free\n", pool->name, @@ -432,12 +433,9 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)  	memset(vaddr, POOL_POISON_FREED, pool->size);  #endif -	spin_lock_irqsave(&pool->lock, flags);  	page->in_use--;  	*(int *)vaddr = page->offset;  	page->offset = offset; -	if (waitqueue_active(&pool->waitq)) -		wake_up_locked(&pool->waitq);  	/*  	 * Resist a temptation to do  	 *    if (!is_page_busy(page)) pool_free_page(pool, page); @@ -502,7 +500,6 @@ void dmam_pool_destroy(struct dma_pool *pool)  {  	struct device *dev = pool->dev; -	dma_pool_destroy(pool); -	WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool)); +	WARN_ON(devres_release(dev, dmam_pool_release, dmam_pool_match, pool));  }  EXPORT_SYMBOL(dmam_pool_destroy);  | 
