diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-25 12:37:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-25 12:37:26 -0400 |
commit | da89fb165e5e51a2ec1ff8a0ff6bc052d1068184 (patch) | |
tree | 1f15b6177a886ceef83d60c3b5a7af926442f581 /drivers/base/dma-buf.c | |
parent | d5adf235adc8d8d67c10afd43922c92753f6be3c (diff) | |
parent | b25b086d23eb852bf3cfdeb60409b4967ebb3c0c (diff) |
Merge tag 'tag-for-linus-3.5' of git://git.linaro.org/people/sumitsemwal/linux-dma-buf
Pull dma-buf updates from Sumit Semwal:
"Here's the first signed-tag pull request for dma-buf framework. It
includes the following key items:
- mmap support
- vmap support
- related documentation updates
These are needed by various drivers to allow mmap/vmap of dma-buf
shared buffers. Dave Airlie has some prime patches dependent on the
vmap pull as well."
* tag 'tag-for-linus-3.5' of git://git.linaro.org/people/sumitsemwal/linux-dma-buf:
dma-buf: add initial vmap documentation
dma-buf: minor documentation fixes.
dma-buf: add vmap interface
dma-buf: mmap support
Diffstat (limited to 'drivers/base/dma-buf.c')
-rw-r--r-- | drivers/base/dma-buf.c | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 05c64c11bad2..24e88fe29ec1 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c | |||
@@ -44,8 +44,26 @@ static int dma_buf_release(struct inode *inode, struct file *file) | |||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) | ||
48 | { | ||
49 | struct dma_buf *dmabuf; | ||
50 | |||
51 | if (!is_dma_buf_file(file)) | ||
52 | return -EINVAL; | ||
53 | |||
54 | dmabuf = file->private_data; | ||
55 | |||
56 | /* check for overflowing the buffer's size */ | ||
57 | if (vma->vm_pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > | ||
58 | dmabuf->size >> PAGE_SHIFT) | ||
59 | return -EINVAL; | ||
60 | |||
61 | return dmabuf->ops->mmap(dmabuf, vma); | ||
62 | } | ||
63 | |||
47 | static const struct file_operations dma_buf_fops = { | 64 | static const struct file_operations dma_buf_fops = { |
48 | .release = dma_buf_release, | 65 | .release = dma_buf_release, |
66 | .mmap = dma_buf_mmap_internal, | ||
49 | }; | 67 | }; |
50 | 68 | ||
51 | /* | 69 | /* |
@@ -82,7 +100,8 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, | |||
82 | || !ops->unmap_dma_buf | 100 | || !ops->unmap_dma_buf |
83 | || !ops->release | 101 | || !ops->release |
84 | || !ops->kmap_atomic | 102 | || !ops->kmap_atomic |
85 | || !ops->kmap)) { | 103 | || !ops->kmap |
104 | || !ops->mmap)) { | ||
86 | return ERR_PTR(-EINVAL); | 105 | return ERR_PTR(-EINVAL); |
87 | } | 106 | } |
88 | 107 | ||
@@ -406,3 +425,81 @@ void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num, | |||
406 | dmabuf->ops->kunmap(dmabuf, page_num, vaddr); | 425 | dmabuf->ops->kunmap(dmabuf, page_num, vaddr); |
407 | } | 426 | } |
408 | EXPORT_SYMBOL_GPL(dma_buf_kunmap); | 427 | EXPORT_SYMBOL_GPL(dma_buf_kunmap); |
428 | |||
429 | |||
430 | /** | ||
431 | * dma_buf_mmap - Setup up a userspace mmap with the given vma | ||
432 | * @dmabuf: [in] buffer that should back the vma | ||
433 | * @vma: [in] vma for the mmap | ||
434 | * @pgoff: [in] offset in pages where this mmap should start within the | ||
435 | * dma-buf buffer. | ||
436 | * | ||
437 | * This function adjusts the passed in vma so that it points at the file of the | ||
438 | * dma_buf operation. It alsog adjusts the starting pgoff and does bounds | ||
439 | * checking on the size of the vma. Then it calls the exporters mmap function to | ||
440 | * set up the mapping. | ||
441 | * | ||
442 | * Can return negative error values, returns 0 on success. | ||
443 | */ | ||
444 | int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, | ||
445 | unsigned long pgoff) | ||
446 | { | ||
447 | if (WARN_ON(!dmabuf || !vma)) | ||
448 | return -EINVAL; | ||
449 | |||
450 | /* check for offset overflow */ | ||
451 | if (pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) < pgoff) | ||
452 | return -EOVERFLOW; | ||
453 | |||
454 | /* check for overflowing the buffer's size */ | ||
455 | if (pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > | ||
456 | dmabuf->size >> PAGE_SHIFT) | ||
457 | return -EINVAL; | ||
458 | |||
459 | /* readjust the vma */ | ||
460 | if (vma->vm_file) | ||
461 | fput(vma->vm_file); | ||
462 | |||
463 | vma->vm_file = dmabuf->file; | ||
464 | get_file(vma->vm_file); | ||
465 | |||
466 | vma->vm_pgoff = pgoff; | ||
467 | |||
468 | return dmabuf->ops->mmap(dmabuf, vma); | ||
469 | } | ||
470 | EXPORT_SYMBOL_GPL(dma_buf_mmap); | ||
471 | |||
472 | /** | ||
473 | * dma_buf_vmap - Create virtual mapping for the buffer object into kernel | ||
474 | * address space. Same restrictions as for vmap and friends apply. | ||
475 | * @dmabuf: [in] buffer to vmap | ||
476 | * | ||
477 | * This call may fail due to lack of virtual mapping address space. | ||
478 | * These calls are optional in drivers. The intended use for them | ||
479 | * is for mapping objects linear in kernel space for high use objects. | ||
480 | * Please attempt to use kmap/kunmap before thinking about these interfaces. | ||
481 | */ | ||
482 | void *dma_buf_vmap(struct dma_buf *dmabuf) | ||
483 | { | ||
484 | if (WARN_ON(!dmabuf)) | ||
485 | return NULL; | ||
486 | |||
487 | if (dmabuf->ops->vmap) | ||
488 | return dmabuf->ops->vmap(dmabuf); | ||
489 | return NULL; | ||
490 | } | ||
491 | EXPORT_SYMBOL_GPL(dma_buf_vmap); | ||
492 | |||
493 | /** | ||
494 | * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap. | ||
495 | * @dmabuf: [in] buffer to vunmap | ||
496 | */ | ||
497 | void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | ||
498 | { | ||
499 | if (WARN_ON(!dmabuf)) | ||
500 | return; | ||
501 | |||
502 | if (dmabuf->ops->vunmap) | ||
503 | dmabuf->ops->vunmap(dmabuf, vaddr); | ||
504 | } | ||
505 | EXPORT_SYMBOL_GPL(dma_buf_vunmap); | ||