LWN: dmabuf, DMA buffer sharing in K3.3

Another good reading is: kernel Documentation/dma-buf-sharing.txt 

From: http://lwn.net/Articles/474819/

Back in August 2011, LWN looked at the DMA buffer sharing patch set posted by Marek Szyprowski. Since then, that patch has been picked up by Sumit Semwal, who modified it considerably in response to comments from a number of developers. The version of this patch that was merged for 3.3 differs enough from its predecessors that it merits another look here.
The core idea remains the same, though: this mechanism allows DMA buffers to be shared between drivers that might otherwise be unaware of each other. The initial target use is sharing buffers between producers and consumers of video streams; a camera device, for example, could acquire a stream of frames into a series of buffers that are shared with the graphics adapter, enabling the capture and display of the data with no copying in the kernel.

In the 3.3 sharing scheme, one driver will set itself up as an exporter of sharable buffers. That requires providing a set of callbacks to the buffer sharing code:

    struct dma_buf_ops {
    int (*attach)(struct dma_buf *buf, struct device *dev,
              struct dma_buf_attachment *dma_attach);
    void (*detach)(struct dma_buf *buf, struct dma_buf_attachment *dma_attach);
    struct sg_table *(*map_dma_buf)(struct dma_buf_attachment *dma_attach,
                    enum dma_data_direction dir);
    void (*unmap_dma_buf)(struct dma_buf_attachment *dma_attach, struct sg_table *sg);
    void (*release)(struct dma_buf *);
    };
Briefly, attach() and detach() inform the exporting driver when others take or release references to the buffer. The map_dma_buf() and unmap_dma_buf() callbacks, instead, cause the buffer to be prepared (or unprepared) for DMA and pass ownership between drivers. A call to release() will be made when the last reference to the buffer is released.

The exporting driver makes the buffer available with a call to:

    struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
                       size_t size, int flags);
Note that the size of the buffer is specified here, but there is no pointer to the buffer itself. In fact, the current version of the interface never passes around CPU-accessible buffer pointers at all. One of the actions performed by dma_buf_export() is the creation of an anonymous file to represent the buffer; flags is used to set the mode bits on that file.

Since the file is anonymous, it is not visible to the rest of the kernel (or user space) in any useful way. Truly exporting the buffer, instead, requires obtaining a file descriptor for it and making that descriptor available to user space. The descriptor can be had with:

    int dma_buf_fd(struct dma_buf *dmabuf);
There is no standardized mechanism for passing that file descriptor to user space, so it seems likely that any subsystem implementing this functionality will add its own special ioctl() operation to get a buffer's file descriptor. The same is true for the act of passing a file descriptor to drivers that will share this buffer; it is something that will happen outside of the buffer-sharing API.

A driver wishing to share a DMA buffer has to go through a series of calls after obtaining the corresponding file descriptor, the first of which is:

    struct dma_buf *dma_buf_get(int fd);
This function obtains a reference to the buffer and returns a dma_buf structure pointer that can be used with the other API calls to refer to the buffer. When the driver is finished with the buffer, it should be returned with a call to dma_buf_put().

The next step is to "attach" to the buffer with:

    struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
                          struct device *dev);
This function will allocate and fill in yet another structure:

    struct dma_buf_attachment {
    struct dma_buf *dmabuf;
    struct device *dev;
    struct list_head node;
    void *priv;
    };
That structure will then be passed to the exporting driver's attach() callback. There seems to be a couple of reasons for the existence of this step, the first of which is simply to let the exporting driver know about the consumers of the buffer. Beyond that, the device structure passed by the calling driver can contain a pointer (in its dma_params field) to one of these structures:

    struct device_dma_parameters {
    unsigned int max_segment_size;
    unsigned long segment_boundary_mask;
    };
The exporting driver should look at these constraints and ensure that the buffer it is exporting can satisfy them; if not, the attach() call should fail. If multiple drivers attach to the buffer, the exporting driver will need to allocate the buffer in a way that satisfies all of their constraints.

The final step is to map the buffer for DMA:

    struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
                        enum dma_data_direction direction);
This call turns into a call to the exporting driver's map_dma_buf() callback. If this call succeeds, the return value will be a scatterlist that can be used to program the DMA operation into the device. A successful return also means that the calling driver's device owns the buffer; it should not be touched by the CPU during this time.

Note that mapping a buffer is an operation that can block for a number of reasons; if the buffer is busy elsewhere, for example. Also worth noting is that, until this call is made, the buffer need not necessarily be allocated anywhere. The exporting driver can wait until others have attached to the buffer so that it can see their DMA constraints and allocate the buffer accordingly. Of course, if the buffer lives in device memory or is otherwise constrained on the exporting side, it can be allocated sooner.

After the DMA operation is completed, the sharing driver should unmap the buffer with:

    void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
                  struct sg_table *sg_table);
That will, in turn, generate a call to the exporting driver's unmap_dma_buf() function. Detaching from the buffer (when it is no longer needed) can be done with:

    void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach);
As might be expected, this function will call the exporting driver's detach() callback.

As of 3.3, there are no users for this interface in the mainline kernel. There seems to be a fair amount of interest in using it, though, so Dave Airlie pushed it into the mainline with the idea that it would make the development of users easier. Some of those users can be seen (in an early form) in Dave's drm-prime repository and Rob Clark's OMAP4 tree.
原文地址:https://www.cnblogs.com/super119/p/2642183.html