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 | |
| 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
| -rw-r--r-- | Documentation/dma-buf-sharing.txt | 109 | ||||
| -rw-r--r-- | drivers/base/dma-buf.c | 99 | ||||
| -rw-r--r-- | include/linux/dma-buf.h | 33 |
3 files changed, 233 insertions, 8 deletions
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt index 3bbd5c51605a..ad86fb86c9a0 100644 --- a/Documentation/dma-buf-sharing.txt +++ b/Documentation/dma-buf-sharing.txt | |||
| @@ -29,13 +29,6 @@ The buffer-user | |||
| 29 | in memory, mapped into its own address space, so it can access the same area | 29 | in memory, mapped into its own address space, so it can access the same area |
| 30 | of memory. | 30 | of memory. |
| 31 | 31 | ||
| 32 | *IMPORTANT*: [see https://lkml.org/lkml/2011/12/20/211 for more details] | ||
| 33 | For this first version, A buffer shared using the dma_buf sharing API: | ||
| 34 | - *may* be exported to user space using "mmap" *ONLY* by exporter, outside of | ||
| 35 | this framework. | ||
| 36 | - with this new iteration of the dma-buf api cpu access from the kernel has been | ||
| 37 | enable, see below for the details. | ||
| 38 | |||
| 39 | dma-buf operations for device dma only | 32 | dma-buf operations for device dma only |
| 40 | -------------------------------------- | 33 | -------------------------------------- |
| 41 | 34 | ||
| @@ -300,6 +293,17 @@ Access to a dma_buf from the kernel context involves three steps: | |||
| 300 | Note that these calls need to always succeed. The exporter needs to complete | 293 | Note that these calls need to always succeed. The exporter needs to complete |
| 301 | any preparations that might fail in begin_cpu_access. | 294 | any preparations that might fail in begin_cpu_access. |
| 302 | 295 | ||
| 296 | For some cases the overhead of kmap can be too high, a vmap interface | ||
| 297 | is introduced. This interface should be used very carefully, as vmalloc | ||
| 298 | space is a limited resources on many architectures. | ||
| 299 | |||
| 300 | Interfaces: | ||
| 301 | void *dma_buf_vmap(struct dma_buf *dmabuf) | ||
| 302 | void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | ||
| 303 | |||
| 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. | ||
| 306 | |||
| 303 | 3. Finish access | 307 | 3. Finish access |
| 304 | 308 | ||
| 305 | When the importer is done accessing the range specified in begin_cpu_access, | 309 | When the importer is done accessing the range specified in begin_cpu_access, |
| @@ -313,6 +317,83 @@ Access to a dma_buf from the kernel context involves three steps: | |||
| 313 | enum dma_data_direction dir); | 317 | enum dma_data_direction dir); |
| 314 | 318 | ||
| 315 | 319 | ||
| 320 | Direct Userspace Access/mmap Support | ||
| 321 | ------------------------------------ | ||
| 322 | |||
| 323 | Being able to mmap an export dma-buf buffer object has 2 main use-cases: | ||
| 324 | - CPU fallback processing in a pipeline and | ||
| 325 | - supporting existing mmap interfaces in importers. | ||
| 326 | |||
| 327 | 1. CPU fallback processing in a pipeline | ||
| 328 | |||
| 329 | In many processing pipelines it is sometimes required that the cpu can access | ||
| 330 | the data in a dma-buf (e.g. for thumbnail creation, snapshots, ...). To avoid | ||
| 331 | the need to handle this specially in userspace frameworks for buffer sharing | ||
| 332 | it's ideal if the dma_buf fd itself can be used to access the backing storage | ||
| 333 | from userspace using mmap. | ||
| 334 | |||
| 335 | Furthermore Android's ION framework already supports this (and is otherwise | ||
| 336 | rather similar to dma-buf from a userspace consumer side with using fds as | ||
| 337 | handles, too). So it's beneficial to support this in a similar fashion on | ||
| 338 | dma-buf to have a good transition path for existing Android userspace. | ||
| 339 | |||
| 340 | No special interfaces, userspace simply calls mmap on the dma-buf fd. | ||
| 341 | |||
| 342 | 2. Supporting existing mmap interfaces in exporters | ||
| 343 | |||
| 344 | Similar to the motivation for kernel cpu access it is again important that | ||
| 345 | the userspace code of a given importing subsystem can use the same interfaces | ||
| 346 | with a imported dma-buf buffer object as with a native buffer object. This is | ||
| 347 | especially important for drm where the userspace part of contemporary OpenGL, | ||
| 348 | X, and other drivers is huge, and reworking them to use a different way to | ||
| 349 | mmap a buffer rather invasive. | ||
| 350 | |||
| 351 | The assumption in the current dma-buf interfaces is that redirecting the | ||
| 352 | initial mmap is all that's needed. A survey of some of the existing | ||
| 353 | subsystems shows that no driver seems to do any nefarious thing like syncing | ||
| 354 | up with outstanding asynchronous processing on the device or allocating | ||
| 355 | special resources at fault time. So hopefully this is good enough, since | ||
| 356 | adding interfaces to intercept pagefaults and allow pte shootdowns would | ||
| 357 | increase the complexity quite a bit. | ||
| 358 | |||
| 359 | Interface: | ||
| 360 | int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, | ||
| 361 | unsigned long); | ||
| 362 | |||
| 363 | If the importing subsystem simply provides a special-purpose mmap call to set | ||
| 364 | up a mapping in userspace, calling do_mmap with dma_buf->file will equally | ||
| 365 | achieve that for a dma-buf object. | ||
| 366 | |||
| 367 | 3. Implementation notes for exporters | ||
| 368 | |||
| 369 | Because dma-buf buffers have invariant size over their lifetime, the dma-buf | ||
| 370 | core checks whether a vma is too large and rejects such mappings. The | ||
| 371 | exporter hence does not need to duplicate this check. | ||
| 372 | |||
| 373 | Because existing importing subsystems might presume coherent mappings for | ||
| 374 | userspace, the exporter needs to set up a coherent mapping. If that's not | ||
| 375 | possible, it needs to fake coherency by manually shooting down ptes when | ||
| 376 | leaving the cpu domain and flushing caches at fault time. Note that all the | ||
| 377 | dma_buf files share the same anon inode, hence the exporter needs to replace | ||
| 378 | the dma_buf file stored in vma->vm_file with it's own if pte shootdown is | ||
| 379 | requred. This is because the kernel uses the underlying inode's address_space | ||
| 380 | for vma tracking (and hence pte tracking at shootdown time with | ||
| 381 | unmap_mapping_range). | ||
| 382 | |||
| 383 | If the above shootdown dance turns out to be too expensive in certain | ||
| 384 | scenarios, we can extend dma-buf with a more explicit cache tracking scheme | ||
| 385 | for userspace mappings. But the current assumption is that using mmap is | ||
| 386 | always a slower path, so some inefficiencies should be acceptable. | ||
| 387 | |||
| 388 | Exporters that shoot down mappings (for any reasons) shall not do any | ||
| 389 | synchronization at fault time with outstanding device operations. | ||
| 390 | Synchronization is an orthogonal issue to sharing the backing storage of a | ||
| 391 | buffer and hence should not be handled by dma-buf itself. This is explictly | ||
| 392 | mentioned here because many people seem to want something like this, but if | ||
| 393 | different exporters handle this differently, buffer sharing can fail in | ||
| 394 | interesting ways depending upong the exporter (if userspace starts depending | ||
| 395 | upon this implicit synchronization). | ||
| 396 | |||
| 316 | Miscellaneous notes | 397 | Miscellaneous notes |
| 317 | ------------------- | 398 | ------------------- |
| 318 | 399 | ||
| @@ -336,6 +417,20 @@ Miscellaneous notes | |||
| 336 | the exporting driver to create a dmabuf fd must provide a way to let | 417 | the exporting driver to create a dmabuf fd must provide a way to let |
| 337 | userspace control setting of O_CLOEXEC flag passed in to dma_buf_fd(). | 418 | userspace control setting of O_CLOEXEC flag passed in to dma_buf_fd(). |
| 338 | 419 | ||
| 420 | - If an exporter needs to manually flush caches and hence needs to fake | ||
| 421 | coherency for mmap support, it needs to be able to zap all the ptes pointing | ||
| 422 | at the backing storage. Now linux mm needs a struct address_space associated | ||
| 423 | with the struct file stored in vma->vm_file to do that with the function | ||
| 424 | unmap_mapping_range. But the dma_buf framework only backs every dma_buf fd | ||
| 425 | with the anon_file struct file, i.e. all dma_bufs share the same file. | ||
| 426 | |||
| 427 | Hence exporters need to setup their own file (and address_space) association | ||
| 428 | by setting vma->vm_file and adjusting vma->vm_pgoff in the dma_buf mmap | ||
| 429 | callback. In the specific case of a gem driver the exporter could use the | ||
| 430 | shmem file already provided by gem (and set vm_pgoff = 0). Exporters can then | ||
| 431 | zap ptes by unmapping the corresponding range of the struct address_space | ||
| 432 | associated with their own file. | ||
| 433 | |||
| 339 | References: | 434 | References: |
| 340 | [1] struct dma_buf_ops in include/linux/dma-buf.h | 435 | [1] struct dma_buf_ops in include/linux/dma-buf.h |
| 341 | [2] All interfaces mentioned above defined in include/linux/dma-buf.h | 436 | [2] All interfaces mentioned above defined in include/linux/dma-buf.h |
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); | ||
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 3efbfc2145c3..eb48f3816df9 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h | |||
| @@ -61,6 +61,13 @@ struct dma_buf_attachment; | |||
| 61 | * This Callback must not sleep. | 61 | * This Callback must not sleep. |
| 62 | * @kmap: maps a page from the buffer into kernel address space. | 62 | * @kmap: maps a page from the buffer into kernel address space. |
| 63 | * @kunmap: [optional] unmaps a page from the buffer. | 63 | * @kunmap: [optional] unmaps a page from the buffer. |
| 64 | * @mmap: used to expose the backing storage to userspace. Note that the | ||
| 65 | * mapping needs to be coherent - if the exporter doesn't directly | ||
| 66 | * support this, it needs to fake coherency by shooting down any ptes | ||
| 67 | * when transitioning away from the cpu domain. | ||
| 68 | * @vmap: [optional] creates a virtual mapping for the buffer into kernel | ||
| 69 | * address space. Same restrictions as for vmap and friends apply. | ||
| 70 | * @vunmap: [optional] unmaps a vmap from the buffer | ||
| 64 | */ | 71 | */ |
| 65 | struct dma_buf_ops { | 72 | struct dma_buf_ops { |
| 66 | int (*attach)(struct dma_buf *, struct device *, | 73 | int (*attach)(struct dma_buf *, struct device *, |
| @@ -92,6 +99,11 @@ struct dma_buf_ops { | |||
| 92 | void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *); | 99 | void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *); |
| 93 | void *(*kmap)(struct dma_buf *, unsigned long); | 100 | void *(*kmap)(struct dma_buf *, unsigned long); |
| 94 | void (*kunmap)(struct dma_buf *, unsigned long, void *); | 101 | void (*kunmap)(struct dma_buf *, unsigned long, void *); |
| 102 | |||
| 103 | int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); | ||
| 104 | |||
| 105 | void *(*vmap)(struct dma_buf *); | ||
| 106 | void (*vunmap)(struct dma_buf *, void *vaddr); | ||
| 95 | }; | 107 | }; |
| 96 | 108 | ||
| 97 | /** | 109 | /** |
| @@ -167,6 +179,11 @@ void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long); | |||
| 167 | void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *); | 179 | void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *); |
| 168 | void *dma_buf_kmap(struct dma_buf *, unsigned long); | 180 | void *dma_buf_kmap(struct dma_buf *, unsigned long); |
| 169 | void dma_buf_kunmap(struct dma_buf *, unsigned long, void *); | 181 | void dma_buf_kunmap(struct dma_buf *, unsigned long, void *); |
| 182 | |||
| 183 | int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, | ||
| 184 | unsigned long); | ||
| 185 | void *dma_buf_vmap(struct dma_buf *); | ||
| 186 | void dma_buf_vunmap(struct dma_buf *, void *vaddr); | ||
| 170 | #else | 187 | #else |
| 171 | 188 | ||
| 172 | static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | 189 | static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, |
| @@ -248,6 +265,22 @@ static inline void dma_buf_kunmap(struct dma_buf *dmabuf, | |||
| 248 | unsigned long pnum, void *vaddr) | 265 | unsigned long pnum, void *vaddr) |
| 249 | { | 266 | { |
| 250 | } | 267 | } |
| 268 | |||
| 269 | static inline int dma_buf_mmap(struct dma_buf *dmabuf, | ||
| 270 | struct vm_area_struct *vma, | ||
| 271 | unsigned long pgoff) | ||
| 272 | { | ||
| 273 | return -ENODEV; | ||
| 274 | } | ||
| 275 | |||
| 276 | static inline void *dma_buf_vmap(struct dma_buf *dmabuf) | ||
| 277 | { | ||
| 278 | return NULL; | ||
| 279 | } | ||
| 280 | |||
| 281 | static inline void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | ||
| 282 | { | ||
| 283 | } | ||
| 251 | #endif /* CONFIG_DMA_SHARED_BUFFER */ | 284 | #endif /* CONFIG_DMA_SHARED_BUFFER */ |
| 252 | 285 | ||
| 253 | #endif /* __DMA_BUF_H__ */ | 286 | #endif /* __DMA_BUF_H__ */ |
