1: dma_dence_init
void
dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
spinlock_t *lock, u64 context, unsigned seqno)
{
BUG_ON(!lock);
BUG_ON(!ops || !ops->wait || !ops->enable_signaling ||
!ops->get_driver_name || !ops->get_timeline_name);
kref_init(&fence->refcount);
fence->ops = ops;
INIT_LIST_HEAD(&fence->cb_list);
fence->lock = lock;
fence->context = context;
fence->seqno = seqno;
fence->flags = 0UL;
fence->error = 0;
trace_dma_fence_init(fence);
}
EXPORT_SYMBOL(dma_fence_init);
参数:
struct dma_fence *fence - 要初始化的fence
const struct dma_fence_ops *ops - 用于该fence的操作函数
spinlock_t *lock - 该fence的自旋锁
u64 context - 在这个fence运行的执行上下文中
unsigned seqno - 针对此上下文的一个递增序列号
作用:
本质上就是为fence结构的成员进行赋值
2:dma fence 完成函数
dma_fence_signal
int dma_fence_signal(struct dma_fence *fence)
{
unsigned long flags;
if (!fence)
return -EINVAL;
/*设置fence状态标记为SIGNEALED,其余接口通过查询此状态标记检查fence是否处于out-fence状态*/
if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
return -EINVAL;
fence->timestamp = ktime_get();
set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
trace_dma_fence_signaled(fence);
if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) {
struct dma_fence_cb *cur, *tmp;
spin_lock_irqsave(fence->lock, flags);
/*对fence感兴趣的其它模块通过向cb_list添加回调函数,可以让fence在完成后执行该回调。这里就是fence完成后的回调*/
list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
list_del_init(&cur->node); // 从fence链表中删除cur节点
cur->func(fence, cur);//执行回调函数
}
spin_unlock_irqrestore(fence->lock, flags);
}
return 0;
}
EXPORT_SYMBOL(dma_fence_signal);
dma_fence_signal_locked
int dma_fence_signal_locked(struct dma_fence *fence)
{
struct dma_fence_cb *cur, *tmp;
int ret = 0;
lockdep_assert_held(fence->lock); //判定锁是否处于锁定状态。就是锁必须在此处被持有,否则就通过打印警告信息
if (WARN_ON(!fence)) //fence为空,打印告警信息
return -EINVAL;
/*设置fence状态标记为SIGNEALED,其余接口通过查询此状态标记检查fence是否处于out-fence状态*/
if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { //置位,并返回原来这个位的值
ret = -EINVAL; //如果原本得fence已经被置位,返回错误
/*
* we might have raced with the unlocked dma_fence_signal,
* still run through all callbacks
*/
} else {
fence->timestamp = ktime_get(); //获取内核时间赋值给fence的时间戳
set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); //把时间戳标志位置位
trace_dma_fence_signaled(fence);
}
/*对fence感兴趣的其它模块通过向cb_list添加回调函数,可以让fence在完成后执行该回调。这里就是fence完成后的回调*/
list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
list_del_init(&cur->node);
cur->func(fence, cur); //执行回调函数
}
return ret;
}
EXPORT_SYMBOL(dma_fence_signal_locked);
与dma_fence_signal不同,这个函数必须在持有fence->lock的情况下被调用。
3:fence使用的含义
分两个视角看,cpu侧和gpu侧。 当cpu需要gpu执行渲染命令时,会把渲染命令放到buffer中去,告知GPU去哪里操作,以及有多少。然后在最后会在命令buffer中放一个指令EOP,这个用于告知GPU,当渲染完成后怎么通知cpu,这里指令的数据内容是让GPU向一个地址写入指定数据的。当cpu检测到这个地址有这个数据时,就可以知道gpu完成了什么渲染命令。
这一切需要在驱动需要用fence来表示。cpu下发渲染指令会创建一个fence用来标记这个job,当GPU完成工作,在指定地址写入数据,触发中断。在中断例程函数中会通过dma_fence_signal修改fence的状态为完成态。用于表示下发渲染指令被执行的状态。并执行fence内部回调函数链表下的各个函数。