Buffer Sharing and Synchronization
本文的标题来自Linux Kernel 5.6.0-rc4文档, dma-buf作为一个内核子系统,它的使用场景不局限于drm “PRIME” multi-GPU支持,它主要由3个组件支撑:
dma_buf
代表sg_table, 暴露给用户FDdma_fence
通知机制dma_resv
管理共享的或专有的fences
DMA-BUF
dma-buf是Linux内核中在上下文间,进程间,设备间,子系统间进行 buffer 共享的一种实现。 它十几年前就已经合入内核了。
1 | commit 3248877ea1796915419fba7c89315fdbf00cb56a |
- exporter调用
1 | /** |
- importer调用
1 | /** |
从上面两个函数的接口看,它们共同涉及3个数据对象:
- drm_device
- dma_buf fd
- drm_gem_object handle
显然两个函数里的dev
一定是不同的drm_device
, dma_buf
fd一定是同一个FD(也即同一个dma-buf, 要不然也不叫共享了),那么handle
呢?肯定也是不同的handle
, 因为handle
其实是对device
而言的,它是一个设备持有的drm_gem_object
的ID. 但这个ID背后的东西(backing storage)可能是同一个东西。
可以打个比方,你去银行要办两种业务,两种业务分别排号,假如你要办的A业务排到7号,B业务也刚好排到7号(注意:号码相同,但是两个号),但是很有可能是同一个业务员为你办理这两种业务,这里的业务就是设备驱动,而那个业务员就是dma-buf(或者它封装的那块显存)。
dma_fence
dma_fence_default_wait
是 dma-fence 默认的 wait 操作。该函数会让当前进程(task) 进入睡眠状态 (可中断睡眠或不可中断睡眠,取决于调用者传入的参数 intr
), 直到 dma-fence 被 signaled 或者设置的超时时间到。
1 | cb.base.func = dma_fence_default_wait_cb; |
dma_resv
classDiagram
dma_resv -- dma_resv_list : *fences
dma_fence -- dma_fence_ops : *ops
dma_resv_list o-- dma_fence: max_fences
class dma_resv{
+ww_mutex lock
+dma_resv_list *fences
}
class dma_resv_list{
-rcu_head rcu
-u32 num_fences
-u32 max_fences
-dma_fence *table[]
}
class dma_fence{
+spinlock_t *lock
+dma_fence_ops *ops
+list_head cb_list
+ktime_t timestamp
+rcu_head rcu
+u64 context
+u64 seqno
+unsigned long flags
+kref refcount
+int error
}
class dma_fence_ops{
+use_64bit_seqno
+get_driver_name(fence) char *
+get_timeline_name(fence) char *
+enable_signaling(fence) bool
+signaled(fence) bool
+wait(fence, intr, timeout) signed long
+release(fence) void
+fence_value_str(fence, char *, size) void
+timeline_value_str(fence, char *, size) void
+set_deadline(fence, deadline) void
}