diff options
Diffstat (limited to 'drivers/base/dma-buf.c')
| -rw-r--r-- | drivers/base/dma-buf.c | 43 | 
1 files changed, 38 insertions, 5 deletions
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index ff5b745c470..394523807a6 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -39,6 +39,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)  	dmabuf = file->private_data; +	BUG_ON(dmabuf->vmapping_counter); +  	dmabuf->ops->release(dmabuf);  	kfree(dmabuf);  	return 0; @@ -481,12 +483,34 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);   */  void *dma_buf_vmap(struct dma_buf *dmabuf)  { +	void *ptr; +  	if (WARN_ON(!dmabuf))  		return NULL; -	if (dmabuf->ops->vmap) -		return dmabuf->ops->vmap(dmabuf); -	return NULL; +	if (!dmabuf->ops->vmap) +		return NULL; + +	mutex_lock(&dmabuf->lock); +	if (dmabuf->vmapping_counter) { +		dmabuf->vmapping_counter++; +		BUG_ON(!dmabuf->vmap_ptr); +		ptr = dmabuf->vmap_ptr; +		goto out_unlock; +	} + +	BUG_ON(dmabuf->vmap_ptr); + +	ptr = dmabuf->ops->vmap(dmabuf); +	if (IS_ERR_OR_NULL(ptr)) +		goto out_unlock; + +	dmabuf->vmap_ptr = ptr; +	dmabuf->vmapping_counter = 1; + +out_unlock: +	mutex_unlock(&dmabuf->lock); +	return ptr;  }  EXPORT_SYMBOL_GPL(dma_buf_vmap); @@ -500,7 +524,16 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)  	if (WARN_ON(!dmabuf))  		return; -	if (dmabuf->ops->vunmap) -		dmabuf->ops->vunmap(dmabuf, vaddr); +	BUG_ON(!dmabuf->vmap_ptr); +	BUG_ON(dmabuf->vmapping_counter == 0); +	BUG_ON(dmabuf->vmap_ptr != vaddr); + +	mutex_lock(&dmabuf->lock); +	if (--dmabuf->vmapping_counter == 0) { +		if (dmabuf->ops->vunmap) +			dmabuf->ops->vunmap(dmabuf, vaddr); +		dmabuf->vmap_ptr = NULL; +	} +	mutex_unlock(&dmabuf->lock);  }  EXPORT_SYMBOL_GPL(dma_buf_vunmap);  |