Re: [RFC 3/4] Documentation: move dma-buf documentation to rst

From: Sumit Semwal
Date: Thu Aug 11 2016 - 08:49:49 EST


Hi Markus,

On 11 August 2016 at 17:28, Markus Heiser <markus.heiser@xxxxxxxxxxx> wrote:
> Hi Sumit,
>
> I haven't compiled your patch yet, just my 2cent about the
> reStructuredText (reST) ASCII markup ...
>
Thanks very much for your detailed review comments - highly appreciated!

> Here are some handy links about reST and the Sphinx markup constructs,
> we have not yet added to the documentation (sorry):
>
> * reST primer: http://www.sphinx-doc.org/en/stable/rest.html
> * reST quickref: http://docutils.sourceforge.net/docs/user/rst/quickref.html
> * Sphinx markup constructs: http://www.sphinx-doc.org/en/stable/markup/index.html
> * Sphinx domains: http://www.sphinx-doc.org/en/stable/domains.html
> * Sphinx cross references: http://www.sphinx-doc.org/en/stable/markup/inline.html#cross-referencing-arbitrary-locations
>
> Am 11.08.2016 um 12:47 schrieb Sumit Semwal <sumit.semwal@xxxxxxxxxx>:
>
>> Branch out dma-buf related documentation into its own rst file to allow
>> adding it to the sphinx documentation generated.
>>
>> While at it, move dma-buf-sharing.txt into rst as the dma-buf guide too.
>>
>> Signed-off-by: Sumit Semwal <sumit.semwal@xxxxxxxxxx>
> ...
>> +dma-buf operations for device dma only
>> +======================================
>> +
>> +The dma_buf buffer sharing API usage contains the following steps:
>> +
>> +1. Exporter announces that it wishes to export a buffer
>> +2. Userspace gets the file descriptor associated with the exported buffer, and
>> + passes it around to potential buffer-users based on use case
>> +3. Each buffer-user 'connects' itself to the buffer
>> +4. When needed, buffer-user requests access to the buffer from exporter
>> +5. When finished with its use, the buffer-user notifies end-of-DMA to exporter
>> +6. when buffer-user is done using this buffer completely, it 'disconnects'
>> + itself from the buffer.
>> +
>> +
>> +1. Exporter's announcement of buffer export
>> +-------------------------------------------
>
> I can't recommend numbering the (sub-) sections explicit, even if you here
> wanted to numerate the steps. Most often section numbers are controlled by
> the subordinate toctree directive and this might not fit to the step
> numbers.
>
> * http://www.sphinx-doc.org/en/stable/markup/toctree.html?highlight=toc#the-toc-tree
>
>> +
>> + The buffer exporter announces its wish to export a buffer. In this, it
>> + connects its own private buffer data, provides implementation for operations
>> + that can be performed on the exported :c:type:`dma_buf`, and flags for the file
>> + associated with this buffer. All these fields are filled in struct
>> + :c:type:`dma_buf_export_info`, defined via the DEFINE_DMA_BUF_EXPORT_INFO macro.
>> +
>
> In restructuredText whitespace are markups.
>
> Do not indent if you don't want to create a (indented) block. I recommend to drop
> the two spaces in front of the paragraphs.
>
> IMHO you have to decide if you like to use sectioning (drop the to spaces)
> or stay with the two spaces and use an enumeration list. If you wan't to stay
> with the enumeration write:
>
> |1. Exporter's announcement of buffer export
> |
> | The buffer exporter announces its wish to export a buffer. In this, it
> | connects its own private buffer ..
> | ...
>
>
Understood; will correct.

>> + Interface:
>> + :c:type:`DEFINE_DMA_BUF_EXPORT_INFO(exp_info) <DEFINE_DMA_BUF_EXPORT_INFO>`
>
> If haven't tested your patch, but I guess this will result in a Warning.
>
> the markup ":c:type" is a reference to a typedef description
>
> * http://www.sphinx-doc.org/en/stable/domains.html#role-c:type
>
> If the description is given, you can use the short form
>
> :c:type:`DEFINE_DMA_BUF_EXPORT_INFO`
>
> but I think, this is a function, not a typedef.
>
I did test it before sending out the RFC, and didn't get any warnings.
This, btw, is a macro, so I guess that's why no warning.

While on this topic, in my experimentation, if I just use the short
form, the resultant text doesn't include the "(exp_info)" part as
shown above.

>> +
>> + :c:func:`struct dma_buf *dma_buf_export(struct dma_buf_export_info *exp_info)<dma_buf_export>`
>
> short form to refer
>
> :c:func:`dma_buf_export()`
>
When I last tried the short form, it only gave me a link to the full
definition, and I wanted to have the arguments also shown here, so
that the explanation below was easier. Though I think I tried without
the (), so will try again and let you know.

>> +
>> + If this succeeds, dma_buf_export allocates a dma_buf structure, and
>> + returns a pointer to the same. It also associates an anonymous file with this
>> + buffer, so it can be exported. On failure to allocate the dma_buf object,
>> + it returns NULL.
>> +
>> + 'exp_name' in struct dma_buf_export_info is the name of exporter - to
>> + facilitate information while debugging. It is set to KBUILD_MODNAME by
>
> If you want to render a constant in a monospace font you can use the
> inline markup ``KBUILD_MODNAME``, but if you want.
>
Thanks, will do.

>> + default, so exporters don't have to provide a specific name, if they don't
>> + wish to.
>> +
>> + DEFINE_DMA_BUF_EXPORT_INFO macro defines the struct dma_buf_export_info,
>> + zeroes it out and pre-populates exp_name in it.
>> +
>> +2. Userspace gets a handle to pass around to potential buffer-users
>> +-------------------------------------------------------------------
>> +
>> + Userspace entity requests for a file-descriptor (fd) which is a handle to the
>> + anonymous file associated with the buffer. It can then share the fd with other
>> + drivers and/or processes.
>> +
>> + Interface:
>> + :c:func:`int dma_buf_fd(struct dma_buf *dmabuf, int flags) <dma_buf_fd>`
>> +
>> + This API installs an fd for the anonymous file associated with this buffer;
>> + returns either 'fd', or error.
>
> I recommend to markup source code objects uniform with ``fd``.
>
Ok.
>> +
>> +3. Each buffer-user 'connects' itself to the buffer
>> +---------------------------------------------------
>> +
>> + Each buffer-user now gets a reference to the buffer, using the fd passed to
>> + it.
>> +
>> + Interface:
>> + :c:func:`struct dma_buf *dma_buf_get(int fd) <dma_buf_get>`
>> +
>> + This API will return a reference to the dma_buf, and increment refcount for
>> + it.
>> +
>> + After this, the buffer-user needs to attach its device with the buffer, which
>> + helps the exporter to know of device buffer constraints.
>> +
>> + Interface:
>> + :c:func:`struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, struct device *dev) <dma_buf_attach>`
>> +
>> + This API returns reference to an attachment structure, which is then used
>> + for scatterlist operations. It will optionally call the 'attach' dma_buf
>> + operation, if provided by the exporter.
>> +
>> + The dma-buf sharing framework does the bookkeeping bits related to managing
>> + the list of all attachments to a buffer.
>> +
>> +.. note:: Until this stage, the buffer-exporter has the option to choose not to
>> + actually allocate the backing storage for this buffer, but wait for the
>> + first buffer-user to request use of buffer for allocation.
>
> Use newlines ... which are markups in reST ;)
>
> .. note::
>
> Until this stage, the buffer-exporter has the option to choose not to
> actually allocate the backing storage for this buffer, but wait for the
> first buffer-user to request use of buffer for allocation.
>
>
Ok :), will correct.

>> +6. when buffer-user is done using this buffer, it 'disconnects' itself from the buffer.
>> +---------------------------------------------------------------------------------------
>> +
>> + After the buffer-user has no more interest in using this buffer, it should
>> + disconnect itself from the buffer:
>> +
>> + * it first detaches itself from the buffer.
>> +
>> + Interface:
>> + :c:func:`void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *dmabuf_attach) <dma_buf_detach>`
>> +
>> + This API removes the attachment from the list in dmabuf, and optionally calls
>> + dma_buf->ops->detach(), if provided by exporter, for any housekeeping bits.
>> +
>> + * Then, the buffer-user returns the buffer reference to exporter.
>> +
>> + Interface:
>> + :c:func:`void dma_buf_put(struct dma_buf *dmabuf) <dma_buf_put>`
>> +
>> + This API then reduces the refcount for this buffer.
>> +
>> + If, as a result of this call, the refcount becomes 0, the 'release' file
>> + operation related to this fd is called. It calls the dmabuf->ops->release()
>> + operation in turn, and frees the memory allocated for dmabuf when exported.
>> +
>> +NOTES:
>> +------
>> +
>
> I can't recommend to use colons in titles.
>
Ok, will remove them.

>> +* **Importance of attach-detach and {map,unmap}_dma_buf operation pairs**
>> +
>> + The attach-detach calls allow the exporter to figure out backing-storage
>
> only 2 spaces are needed here ... whitespaces are markups ;)
>
Right, got the message;)

>> + constraints for the currently-interested devices. This allows preferential
>> + allocation, and/or migration of pages across different types of storage
>> + available, if possible.
>> +
>> + Bracketing of DMA access with {map,unmap}_dma_buf operations is essential
>> + to allow just-in-time backing of storage, and migration mid-way through a
>> + use-case.
>
>> +
>> +* **Migration of backing storage if needed**
>> +
>
> I can't recommend this style, using a list and a first bold line to emulate
> something what looks like a subsection .. use subsections or leave the bold line.
>
Yes, that's right; will correct.
>
>
>> + If after
>> +
>> + * at least one map_dma_buf has happened,
>> + * and the backing storage has been allocated for this buffer,
>> +
>> + another new buffer-user intends to attach itself to this buffer, it might
>> + be allowed, if possible for the exporter.
>> +
>> + In case it is allowed by the exporter:
>> +
>> + * if the new buffer-user has stricter 'backing-storage constraints', and the
>> + exporter can handle these constraints, the exporter can just stall on the
>> + map_dma_buf until all outstanding access is completed (as signalled by
>> + unmap_dma_buf).
>> +
>> + * Once all users have finished accessing and have unmapped this buffer, the
>> + exporter could potentially move the buffer to the stricter backing-storage,
>> + and then allow further {map,unmap}_dma_buf operations from any buffer-user
>> + from the migrated backing-storage.
>> +
>> + * If the exporter cannot fulfill the backing-storage constraints of the new
>> + buffer-user device as requested, dma_buf_attach() would return an error to
>> + denote non-compatibility of the new buffer-sharing request with the current
>> + buffer.
>> +
>> +
>> + If the exporter chooses not to allow an attach() operation once a
>> + map_dma_buf() API has been called, it simply returns an error.
>> +
>> +Kernel cpu access to a dma-buf buffer object
>> +============================================
>> +
>> +The motivation to allow cpu access from the kernel to a dma-buf object from the
>> +importers side are:
>> +
>> +* fallback operations, e.g. if the devices is connected to a usb bus and the
>> + kernel needs to shuffle the data around first before sending it away.
>> +* full transparency for existing users on the importer side, i.e. userspace
>> + should not notice the difference between a normal object from that subsystem
>> + and an imported one backed by a dma-buf. This is really important for drm
>> + opengl drivers that expect to still use all the existing upload/download
>> + paths.
>
> I is recommended to separate blocks (in this case the list item blocks) with
> a newline. E.g.
>
> * first lorem
> ipsum
>
> * second lorem
> ipsum
>
> If you have only one-liners, it is OK to write
>
> * first
> * second
>

Understood, good tip for me.
>> +
>> +Access to a dma_buf from the kernel context involves three steps:
>> +
>> +1. Prepare access, which invalidate any necessary caches and make the object
>> + available for cpu access.
>> +2. Access the object page-by-page with the dma_buf map apis
>> +3. Finish access, which will flush any necessary cpu caches and free reserved
>> + resources.
>> +:`void dma_buf_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction dir) <dma_buf_end_cpu_access>`
>> +
>> +
>> +Direct Userspace Access/mmap Support
>> +====================================
>> +
>> +Being able to mmap an export dma-buf buffer object has 2 main use-cases:
>> +* CPU fallback processing in a pipeline and
>> +* supporting existing mmap interfaces in importers.
>> +
>
> Insert a newline in front of the list.
>
Ok.

>> +1. CPU fallback processing in a pipeline
>> +----------------------------------------
>> +
>> + In many processing pipelines it is sometimes required that the cpu can access
>> + the data in a dma-buf (e.g. for thumbnail creation, snapshots, ...). To avoid
>> + the need to handle this specially in userspace frameworks for buffer sharing
>> + it's ideal if the dma_buf fd itself can be used to access the backing storage
>> + from userspace using mmap.
>> +
>> + Furthermore Android's ION framework already supports this (and is otherwise
>> + rather similar to dma-buf from a userspace consumer side with using fds as
>> + handles, too). So it's beneficial to support this in a similar fashion on
>> + dma-buf to have a good transition path for existing Android userspace.
>> +
>> + No special interfaces, userspace simply calls mmap on the dma-buf fd, making
>> + sure that the cache synchronization ioctl (DMA_BUF_IOCTL_SYNC) is *always*
>> + used when the access happens. Note that DMA_BUF_IOCTL_SYNC can fail with
>> + -EAGAIN or -EINTR, in which case it must be restarted.
>> +
>> + Some systems might need some sort of cache coherency management e.g. when
>> + CPU and GPU domains are being accessed through dma-buf at the same time. To
>> + circumvent this problem there are begin/end coherency markers, that forward
>> + directly to existing dma-buf device drivers vfunc hooks. Userspace can make
>> + use of those markers through the DMA_BUF_IOCTL_SYNC ioctl. The sequence
>> + would be used like following:
>> +
>> + * mmap dma-buf fd
>> + * for each drawing/upload cycle in CPU
>> +
>> + 1. SYNC_START ioctl,
>> + 2. read/write to mmap area
>> + 3. SYNC_END ioctl.
>> +
>> + This can be repeated as often as you want (with the new data being
>> + consumed by the GPU or say scanout device)
>> + * munmap once you don't need the buffer any more
>> +
>
> see above, use newline to separate last list item from the one before
>
Ok.
>> + For correctness and optimal performance, it is always required to use
>> + SYNC_START and SYNC_END before and after, respectively, when accessing the
>> + mapped address. Userspace cannot rely on coherent access, even when there
>> + are systems where it just works without calling these ioctls.
>> +
>>
>> +Introduction
>> +------------
>> +
>> +The dma-buf subsystem provides the framework for sharing buffers for
>> +hardware (DMA) access across multiple device drivers and subsystems, and
>> +for synchronizing asynchronous hardware access.
>> +
>> +This is used, for example, by drm "prime" multi-GPU support, but is of
>> +course not limited to GPU use cases.
>> +
>> +The three main components of this are:
>> +
>> +* dma-buf_: represents an sg_table, and is exposed to userspace as a file
>> + descriptor to allow passing between devices,
>> +
>> +* fence_: which provides a mechanism to signal when one device has finished
>> + access, and
>> +
>> +* reservation_: manages the shared or exclusive fence(s) associated with the
>> + buffer.
>> +
>> +Please refer to :ref:`DMA buffer sharing guide <dma-buf-guide>` for more details.
>
> alternative you can use the short form :ref:`dma-buf-guide`, depends on the
> context from which you refer and the targets title.
>
Will try that out.

> But over all, I wan't say: thanks for your work :)
>
Thanks to you too, appreciate you taking time to read through this whole doc! :)
> -- Markus --
>
>
BR,
Sumit.



--
Thanks and regards,

Sumit Semwal
Linaro Mobile Group - Kernel Team Lead
Linaro.org â Open source software for ARM SoCs