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
Showing the changes to drivers/base (1 of 3 files). Show all
Unified · Split
| @@ -44,8 +44,26 @@ static int dma_buf_release(struct inode *inode, struct file *file) · 43 unmodified lines | ||
| 44 | 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 | 64 | static const struct file_operations dma_buf_fops = { |
| 48 | 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, · 30 unmodified lines | ||
| 82 | 100 | || !ops->unmap_dma_buf |
| 83 | 101 | || !ops->release |
| 84 | 102 | || !ops->kmap_atomic |
| 85 | − || !ops->kmap)) { | |
| 103 | + || !ops->kmap | |
| 104 | + || !ops->mmap)) { | |
| 86 | 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, · 317 unmodified lines | ||
| 406 | 425 | dmabuf->ops->kunmap(dmabuf, page_num, vaddr); |
| 407 | 426 | } |
| 408 | 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); | |