Wednesday, November 4, 2015

DMA Buffer Sharing

The need to share DMA buffers between drivers and applications is common in multimedia platforms.  Android's gralloc and Ion driver provide this and some other goodies, but Linaro's dmabuf buffer sharing driver provides a ligher-weight alternative which is plenty good for many situations. Here's a good comparison of Ion and dmabuf.

I'm a visual person and relate to diagrams more than I do to textual descriptions.  I use diagrams to quickly create a mental model of a subject-matter I'm learning, and use text to understand the fine details if I decide to dive in.  Towards this end I created the sequence diagrams below, to complement the dmabuf documentation and help me follow to interactions between the importer, exporter and application.  The kernel documentation is clear and concise, so I'm not adding further explanations, lest I detract more than I add.  Hopefully these diagram will help you, too.

I've used MSC Generator to generate the diagrams and I'm providing the source for that as well. Enjoy ;-)

dma-buf operations for device dma only
Kernel cpu access to a dma-buf buffer object

# dma-buf operations for device dma only
application, importer, dmabuf_driver, exporter;
msc = modern_blue;
hscale=auto;
..: exporter exports buffer {
exporter->dmabuf_driver: dma_buf_export;
activate exporter;
exporter<<dmabuf_driver: dmabuf : dma_buf*;
deactivate exporter;
};
...:\i;
..: app gets buffer as file descriptor {
application->exporter: <<get buffer>>;
activate application;
exporter->dmabuf_driver:dma_buf_fd(dmabuf);
dmabuf_driver>>exporter:fd : int;
exporter>>application: fd;
deactivate application;
};
...:\i;
..: importer attaches to buffer {
application->importer: <<use this buffer (fd)>>;
activate application;
importer->dmabuf_driver: dma_buf_get(fd);
dmabuf_driver>>importer: dmabuf : dma_buf*;
importer->dmabuf_driver: dma_buf_attach(dmabuf, dev);
dmabuf_driver->exporter: dma_buf_ops->alloc(dmabuf, dev, attachment);
dmabuf_driver>>importer: attachment: dma_buf_attachment *;
deactivate application;
};
...:\i;
application..exporter: Transfer control of the buffer to the device
(start of DMA) {
importer->dmabuf_driver: dma_buf_map_attachment
(attachment, dma_direction);
activate importer;
dmabuf_driver->exporter:dma_buf_ops->map_dma_buf(attachment, dma_direction);
dmabuf_driver>>importer: sg_table : sg_table*;
deactivate importer;
};
...:\iimporter device uses the DMA buffer;
application..exporter: Transfer control of the buffer back to the CPU
(end of DMA) {
importer->dmabuf_driver: dma_buf_unmap_attachment
(attachment, sg_table);
activate importer;
dmabuf_driver->exporter: dma_buf_ops->unmap_dma_buf(attachment, sg_table);
deactivate importer;
};
...:\i;
application..exporter: detach from the buffer {
activate importer;
importer->dmabuf_driver:dma_buf_detach(dmabuf, attachment);;
dmabuf_driver->exporter: dma_buf_ops->detach(dmabuf, attachment);
deactivate importer;
};

git clone
# Kernel cpu access to a dma-buf buffer object
kernel_driver, dmabuf_driver, exporter;
msc = modern_blue;
hscale=auto;
..: prepare buffer for kernel access {
kernel_driver->dmabuf_driver: dma_buf_begin_cpu_acces;
dmabuf_driver->exporter: begin_cpu_access;
};
..: access the buffer {
kernel_driver->dmabuf_driver: dma_buf_kmap(dmabuf, pagenum);
dmabuf_driver->exporter: kmap(dmabuf, pagenum);
dmabuf_driver>>kernel_driver: vaddr : void*;
};
...:\iimporting kernel driver accesses the DMA buffer from CPU;
..:finish accessing the buffer {
kernel_driver->dmabuf_driver: dma_buf_kunmap(dmabuf, pagenum, vaddr);
dmabuf_driver->exporter: kunmap(dmabuf, pagenum, vaddr);
kernel_driver->dmabuf_driver: dma_buf_end_cpu_access(dmabuf, start, len, dir);
dmabuf_driver->exporter: end_cpu_access(dmabuf, start, len, dir);
};
git clone

No comments:

Post a Comment