aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-20 08:14:23 -0500
committerSumit Semwal <sumit.semwal@linaro.org>2013-02-27 04:43:36 -0500
commitf00b4dad9d9eb001a04cf72e8351a2a1b9e99322 (patch)
treef1d7e737c8fa03488249c77eb0c6e5d5db149fcf
parentd895cb1af15c04c522a25c79cc429076987c089b (diff)
dma-buf: implement vmap refcounting in the interface logic
All drivers which implement this need to have some sort of refcount to allow concurrent vmap usage. Hence implement this in the dma-buf core. To protect against concurrent calls we need a lock, which potentially causes new funny locking inversions. But this shouldn't be a problem for exporters with statically allocated backing storage, and more dynamic drivers have decent issues already anyway. Inspired by some refactoring patches from Aaron Plattner, who implemented the same idea, but only for drm/prime drivers. v2: Check in dma_buf_release that no dangling vmaps are left. Suggested by Aaron Plattner. We might want to do similar checks for attachments, but that's for another patch. Also fix up ERR_PTR return for vmap. v3: Check whether the passed-in vmap address matches with the cached one for vunmap. Eventually we might want to remove that parameter - compared to the kmap functions there's no need for the vaddr for unmapping. Suggested by Chris Wilson. v4: Fix a brown-paper-bag bug spotted by Aaron Plattner. Cc: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Aaron Plattner <aplattner@nvidia.com> Tested-by: Aaron Plattner <aplattner@nvidia.com> Reviewed-by: Rob Clark <rob@ti.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
-rw-r--r--Documentation/dma-buf-sharing.txt6
-rw-r--r--drivers/base/dma-buf.c43
-rw-r--r--include/linux/dma-buf.h4
3 files changed, 46 insertions, 7 deletions
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt
index 0188903bc9e1..4966b1be42ac 100644
--- a/Documentation/dma-buf-sharing.txt
+++ b/Documentation/dma-buf-sharing.txt
@@ -302,7 +302,11 @@ Access to a dma_buf from the kernel context involves three steps:
302 void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) 302 void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
303 303
304 The vmap call can fail if there is no vmap support in the exporter, or if it 304 The vmap call can fail if there is no vmap support in the exporter, or if it
305 runs out of vmalloc space. Fallback to kmap should be implemented. 305 runs out of vmalloc space. Fallback to kmap should be implemented. Note that
306 the dma-buf layer keeps a reference count for all vmap access and calls down
307 into the exporter's vmap function only when no vmapping exists, and only
308 unmaps it once. Protection against concurrent vmap/vunmap calls is provided
309 by taking the dma_buf->lock mutex.
306 310
3073. Finish access 3113. Finish access
308 312
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index ff5b745c4705..394523807a6d 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)
39 39
40 dmabuf = file->private_data; 40 dmabuf = file->private_data;
41 41
42 BUG_ON(dmabuf->vmapping_counter);
43
42 dmabuf->ops->release(dmabuf); 44 dmabuf->ops->release(dmabuf);
43 kfree(dmabuf); 45 kfree(dmabuf);
44 return 0; 46 return 0;
@@ -481,12 +483,34 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
481 */ 483 */
482void *dma_buf_vmap(struct dma_buf *dmabuf) 484void *dma_buf_vmap(struct dma_buf *dmabuf)
483{ 485{
486 void *ptr;
487
484 if (WARN_ON(!dmabuf)) 488 if (WARN_ON(!dmabuf))
485 return NULL; 489 return NULL;
486 490
487 if (dmabuf->ops->vmap) 491 if (!dmabuf->ops->vmap)
488 return dmabuf->ops->vmap(dmabuf); 492 return NULL;
489 return NULL; 493
494 mutex_lock(&dmabuf->lock);
495 if (dmabuf->vmapping_counter) {
496 dmabuf->vmapping_counter++;
497 BUG_ON(!dmabuf->vmap_ptr);
498 ptr = dmabuf->vmap_ptr;
499 goto out_unlock;
500 }
501
502 BUG_ON(dmabuf->vmap_ptr);
503
504 ptr = dmabuf->ops->vmap(dmabuf);
505 if (IS_ERR_OR_NULL(ptr))
506 goto out_unlock;
507
508 dmabuf->vmap_ptr = ptr;
509 dmabuf->vmapping_counter = 1;
510
511out_unlock:
512 mutex_unlock(&dmabuf->lock);
513 return ptr;
490} 514}
491EXPORT_SYMBOL_GPL(dma_buf_vmap); 515EXPORT_SYMBOL_GPL(dma_buf_vmap);
492 516
@@ -500,7 +524,16 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
500 if (WARN_ON(!dmabuf)) 524 if (WARN_ON(!dmabuf))
501 return; 525 return;
502 526
503 if (dmabuf->ops->vunmap) 527 BUG_ON(!dmabuf->vmap_ptr);
504 dmabuf->ops->vunmap(dmabuf, vaddr); 528 BUG_ON(dmabuf->vmapping_counter == 0);
529 BUG_ON(dmabuf->vmap_ptr != vaddr);
530
531 mutex_lock(&dmabuf->lock);
532 if (--dmabuf->vmapping_counter == 0) {
533 if (dmabuf->ops->vunmap)
534 dmabuf->ops->vunmap(dmabuf, vaddr);
535 dmabuf->vmap_ptr = NULL;
536 }
537 mutex_unlock(&dmabuf->lock);
505} 538}
506EXPORT_SYMBOL_GPL(dma_buf_vunmap); 539EXPORT_SYMBOL_GPL(dma_buf_vunmap);
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index 3d754a394e92..9978b614a1aa 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -119,8 +119,10 @@ struct dma_buf {
119 struct file *file; 119 struct file *file;
120 struct list_head attachments; 120 struct list_head attachments;
121 const struct dma_buf_ops *ops; 121 const struct dma_buf_ops *ops;
122 /* mutex to serialize list manipulation and attach/detach */ 122 /* mutex to serialize list manipulation, attach/detach and vmap/unmap */
123 struct mutex lock; 123 struct mutex lock;
124 unsigned vmapping_counter;
125 void *vmap_ptr;
124 void *priv; 126 void *priv;
125}; 127};
126 128