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__ */ |