缓冲区共享和同步dma_buf 之二
- 数据结构
- dma_buf_sync
- dma_buf_export_sync_file
- dma_buf_import_sync_file
- APIs
- 缓冲区与描述符
- dma_buf_export
- dma_buf_fd
- dma_buf_get
- 链接缓冲区与设备驱动器
- 缓冲区加锁与解锁
- 分散列表与映射
数据结构
dma_buf_sync
与 CPU 访问同步。
struct dma_buf_sync {__u64 flags;
};
flags值 | 意义 |
---|---|
DMA_BUF_SYNC_START | 指示地图访问会话的开始 |
DMA_BUF_SYNC_END | 指示地图访问会话的结束 |
DMA_BUF_SYNC_READ | 表示客户端将通过CPU映射读取映射的DMA缓冲区表示客户端将通过CPU映射读取映射的DMA缓冲区 |
DMA_BUF_SYNC_WRITE | 表示映射的 DMA 缓冲区将由客户端通过 CPU 映射写入 |
DMA_BUF_SYNC_RW | 等同于DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE |
当 CPU 通过 mmap 访问 DMA 缓冲区时,并不总是能够保证 CPU 可见映射和底层内存之间的一致性。为了管理一致性,必须使用 DMA_BUF_IOCTL_SYNC 来包围任何 CPU 访问,以便内核有机会在需要时重新整理内存。
在访问映射之前,客户端必须使用 DMA_BUF_SYNC_START 和适当的读/写标志调用 DMA_BUF_IOCTL_SYNC。访问完成后,客户端应使用 DMA_BUF_SYNC_END 和相同的读/写标志调用 DMA_BUF_IOCTL_SYNC。
通过 DMA_BUF_IOCTL_SYNC 提供的同步仅提供缓存一致性。它不会阻止其他进程或设备同时访问内存。如果需要与 GPU 或其他设备驱动程序同步,则客户端有责任在使用 DMA_BUF_SYNC_START 调用此 ioctl 之前等待缓冲区准备好读取或写入。同样,客户端必须确保在使用 DMA_BUF_SYNC_END 调用此 ioctl 之前,不会将后续工作提交给 GPU 或其他设备驱动程序?
如果与客户端交互的驱动程序或 API 使用隐式同步,则可以通过 DMA 缓冲区文件描述符上的 poll() 来等待先前的工作完成。如果驱动程序或 API 需要显式同步,则客户端可能必须等待 DMA 缓冲区 API 范围之外的sync_file 或其他同步原语。
dma_buf_export_sync_file
struct dma_buf_export_sync_file {__u32 flags;__s32 fd;
};
-
flags
- 必须为 DMA_BUF_SYNC_READ、DMA_BUF_SYNC_WRITE 或两者。
- 如果设置了 DMA_BUF_SYNC_READ,但未设置 DMA_BUF_SYNC_WRITE,则返回的同步文件将等待 dma-buf 的任何写入器完成。等待返回的同步文件相当于 poll() 和 POLLIN。
- 如果设置了 DMA_BUF_SYNC_WRITE,则返回的同步文件将等待 dma-buf(读取或写入)的任何用户完成。等待返回的同步文件相当于 poll() 和 POLLOUT。如果 DMA_BUF_SYNC_WRITE 和 DMA_BUF_SYNC_READ 均被设置,则相当于仅 DMA_BUF_SYNC_WRITE。
-
fd
- 返回的同步文件描述符
可以使用作为一个sync_file的dma-buf 文件描述符, 执行 DMA_BUF_IOCTL_EXPORT_SYNC_FILE,以获得当前围栏集。 CPU 通过 poll() 或其他特定于驱动程序的机制等待围栏,这些围栏在等待开始时,出现在dma-buf上。
预期的使用模式如下:
- 通过 DMA_BUF_IOCTL_EXPORT_SYNC_FILE,导出带有与预期 GPU 使用情况相对应的标志的sync_file。
- 提交使用 dma-buf 的重演工作。该工作应在重演之前等待导出的同步文件,并在完成后,生成另一个sync_file。
- 通过 DMA_BUF_IOCTL_IMPORT_SYNC_FIL,将重演完成的sync_file 导入到 dma-buf 中,该dma-buf带有与 GPU 使用情况相对应的标志。
与通过 GPU 内核驱动程序的 exec ioctl 进行隐式同步不同,上述不是单个原子操作。如果用户空间想要确保通过这些围栏,保证次序,则用户空间有责任使用锁或其他机制来确保没有其他上下文在上述步骤 1 和 3 之间添加围栏或提交工作。
dma_buf_import_sync_file
将sync_file插入到dma-buf中。
struct dma_buf_import_sync_file {__u32 flags;__s32 fd;
};
-
flags
- 必须为 DMA_BUF_SYNC_READ、DMA_BUF_SYNC_WRITE 或两者。
- 如果设置了 DMA_BUF_SYNC_READ, 并且未设置 DMA_BUF_SYNC_WRITE,则会将sync_file 作为只读围栏插入。对此 dma-buf 的任何后续隐式同步写入,都将在此围栏上等待,但读取则不会。
- 如果设置了 DMA_BUF_SYNC_WRITE,则会将sync_file 作为写围栏插入。所有后续对此 dma-buf 的隐式同步访问都将在此栅栏上等待。
-
fd
- 同步文件描述符
为实现与其他 dma-buf 使用者的隐式同步,用户空间可以执行 DMA_BUF_IOCTL_IMPORT_SYNC_FILE 将sync_file 插入到 dma-buf 中。
APIs
缓冲区与描述符
struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info);
int dma_buf_fd(struct dma_buf *dmabuf, int flags);
struct dma_buf *dma_buf_get(int fd);
void dma_buf_put(struct dma_buf *dmabuf);
dma_buf_export
struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
创建一个新的 dma_buf,并将一个匿名文件与该缓冲区关联起来,以便可以将其导出。还将特定的数据和操作分配器连接到缓冲区。此外,为导出者提供字符串名称;在调试中很有用。
const struct dma_buf_export_info *exp_info
[in] 保存导出者提供的所有出口相关信息。
成功,返回一个新创建的 struct dma_buf 对象,该对象封装为 struct dma_buf_ops 提供的私有数据和操作。如果缺少操作或分配 struct dma_buf 时出错,将返回负值错误。
对于大多数情况,创建 exp_info 的最简单方法是使用DEFINE_DMA_BUF_EXPORT_INFO宏。
dma_buf_fd
返回给定 struct dma_buf 的文件描述符。
int dma_buf_fd(struct dma_buf *dmabuf, int flags)
struct dma_buf *dmabuf
[in] 指向需要 fd 的 dma_buf 的指针。
int flags
[in] 给予 fd 的标志
成功,返回关联的“fd”。否则,返回错误。
dma_buf_get
struct dma_buf *dma_buf_get(int fd)
链接缓冲区与设备驱动器
struct dma_buf_attachment *dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, const struct dma_buf_attach_ops *importer_ops, void *importer_priv);
struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, struct device *dev);
void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
缓冲区加锁与解锁
int dma_buf_pin(struct dma_buf_attachment *attach);
void dma_buf_unpin(struct dma_buf_attachment *attach);
// An highlighted block
var foo = 'bar';
分散列表与映射
struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction);
struct sg_table *dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach, enum dma_data_direction direction);
void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, struct sg_table *sg_table, enum dma_data_direction direction);
void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach, struct sg_table *sg_table, enum dma_data_direction direction)