[PATCH 5/5] drm: add syncobj timeline support v2
Christian König
ckoenig.leichtzumerken at gmail.com
Thu Aug 23 11:05:55 UTC 2018
Am 23.08.2018 um 11:58 schrieb zhoucm1:
>
>
> On 2018年08月23日 17:15, Christian König wrote:
>> Am 23.08.2018 um 10:25 schrieb Chunming Zhou:
>>> VK_KHR_timeline_semaphore:
>>> This extension introduces a new type of semaphore that has an
>>> integer payload
>>> identifying a point in a timeline. Such timeline semaphores support the
>>> following operations:
>>> * Host query - A host operation that allows querying the payload
>>> of the
>>> timeline semaphore.
>>> * Host wait - A host operation that allows a blocking wait for a
>>> timeline semaphore to reach a specified value.
>>
>> I think I have a idea what "Host" means in this context, but it would
>> probably be better to describe it.
>
> How about "CPU"?
Yeah, that's probably better.
>
>>> * Device wait - A device operation that allows waiting for a
>>> timeline semaphore to reach a specified value.
>>> * Device signal - A device operation that allows advancing the
>>> timeline semaphore to a specified value.
>>>
>>> Since it's a timeline, that means the front time point(PT) always is
>>> signaled before the late PT.
>>> a. signal PT design:
>>> Signal PT fence N depends on PT[N-1] fence and signal opertion
>>> fence, when PT[N] fence is signaled,
>>> the timeline will increase to value of PT[N].
>>> b. wait PT design:
>>> Wait PT fence is signaled by reaching timeline point value, when
>>> timeline is increasing, will compare
>>> wait PTs value with new timeline value, if PT value is lower than
>>> timeline value, then wait PT will be
>>> signaled, otherwise keep in list. semaphore wait operation can wait
>>> on any point of timeline,
>>> so need a RB tree to order them. And wait PT could ahead of signal
>>> PT, we need a sumission fence to
>>> perform that.
>>>
>>> v2:
>>> 1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian)
>>> 2. move unexposed denitions to .c file. (Daniel Vetter)
>>> 3. split up the change to drm_syncobj_find_fence() in a separate
>>> patch. (Christian)
>>> 4. split up the change to drm_syncobj_replace_fence() in a separate
>>> patch.
>>> 5. drop the submission_fence implementation and instead use
>>> wait_event() for that. (Christian)
>>> 6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter)
>>
>> I really liked Daniels idea to handle the classic syncobj like a
>> timeline synobj with just 1 entry. That can probably simplify the
>> implementation quite a bit.
> Yeah, after timeline, seems we can remove old syncobj->fence, right?
> will try to unify them in additional patch.
I think we could do something like the following:
1. When drm_syncobj_find_fence is called with point zero then we return
the last added one.
2. When drm_syncobj_find_fence is called with point zero we add the new
fence as with N+1 to the list.
This way syncobj should keep it's functionality as is with the timeline
support added on top.
Regards,
Christian.
>
> Thanks,
> David Zhou
>>
>> Additional to that an amdgpu patch which shows how the interface is
>> to be used is probably something Daniel will want to see as well.
>>
>> Christian.
>>
>>>
>>> TODO:
>>> 1. CPU query and wait on timeline semaphore.
>>> 2. test application (Daniel Vetter)
>>>
>>> Signed-off-by: Chunming Zhou <david1.zhou at amd.com>
>>> Cc: Christian Konig <christian.koenig at amd.com>
>>> Cc: Dave Airlie <airlied at redhat.com>
>>> Cc: Daniel Rakos <Daniel.Rakos at amd.com>
>>> Cc: Daniel Vetter <daniel at ffwll.ch>
>>> ---
>>> drivers/gpu/drm/drm_syncobj.c | 383
>>> +++++++++++++++++++++++++++++++++++++++---
>>> include/drm/drm_syncobj.h | 28 +++
>>> include/uapi/drm/drm.h | 1 +
>>> 3 files changed, 389 insertions(+), 23 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/drm_syncobj.c
>>> b/drivers/gpu/drm/drm_syncobj.c
>>> index 6227df2cc0a4..f738d78edf65 100644
>>> --- a/drivers/gpu/drm/drm_syncobj.c
>>> +++ b/drivers/gpu/drm/drm_syncobj.c
>>> @@ -56,6 +56,44 @@
>>> #include "drm_internal.h"
>>> #include <drm/drm_syncobj.h>
>>> +struct drm_syncobj_stub_fence {
>>> + struct dma_fence base;
>>> + spinlock_t lock;
>>> +};
>>> +
>>> +static const char *drm_syncobj_stub_fence_get_name(struct dma_fence
>>> *fence)
>>> +{
>>> + return "syncobjstub";
>>> +}
>>> +
>>> +static bool drm_syncobj_stub_fence_enable_signaling(struct
>>> dma_fence *fence)
>>> +{
>>> + return !dma_fence_is_signaled(fence);
>>> +}
>>> +
>>> +static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
>>> + .get_driver_name = drm_syncobj_stub_fence_get_name,
>>> + .get_timeline_name = drm_syncobj_stub_fence_get_name,
>>> + .enable_signaling = drm_syncobj_stub_fence_enable_signaling,
>>> + .release = NULL,
>>> +};
>>> +
>>> +struct drm_syncobj_wait_pt {
>>> + struct drm_syncobj_stub_fence base;
>>> + u64 value;
>>> + struct rb_node node;
>>> +};
>>> +struct drm_syncobj_signal_pt {
>>> + struct drm_syncobj_stub_fence base;
>>> + struct dma_fence *signal_fence;
>>> + struct dma_fence *pre_pt_base;
>>> + struct dma_fence_cb signal_cb;
>>> + struct dma_fence_cb pre_pt_cb;
>>> + struct drm_syncobj *syncobj;
>>> + u64 value;
>>> + struct list_head list;
>>> +};
>>> +
>>> /**
>>> * drm_syncobj_find - lookup and reference a sync object.
>>> * @file_private: drm file private pointer
>>> @@ -137,6 +175,150 @@ void drm_syncobj_remove_callback(struct
>>> drm_syncobj *syncobj,
>>> spin_unlock(&syncobj->lock);
>>> }
>>> +static void drm_syncobj_timeline_signal_wait_pts(struct
>>> drm_syncobj *syncobj)
>>> +{
>>> + struct rb_node *node = NULL;
>>> + struct drm_syncobj_wait_pt *wait_pt = NULL;
>>> +
>>> + spin_lock(&syncobj->lock);
>>> + for(node = rb_first(&syncobj->syncobj_timeline.wait_pt_tree);
>>> + node != NULL; ) {
>>> + wait_pt = rb_entry(node, struct drm_syncobj_wait_pt, node);
>>> + node = rb_next(node);
>>> + if (wait_pt->value <= syncobj->syncobj_timeline.timeline) {
>>> + dma_fence_signal(&wait_pt->base.base);
>>> + rb_erase(&wait_pt->node,
>>> + &syncobj->syncobj_timeline.wait_pt_tree);
>>> + RB_CLEAR_NODE(&wait_pt->node);
>>> + /* kfree(wait_pt) is excuted by fence put */
>>> + dma_fence_put(&wait_pt->base.base);
>>> + } else {
>>> + /* the loop is from left to right, the later entry
>>> value is
>>> + * bigger, so don't need to check any more */
>>> + break;
>>> + }
>>> + }
>>> + spin_unlock(&syncobj->lock);
>>> +}
>>> +
>>> +
>>> +static void pt_fence_cb(struct drm_syncobj_signal_pt *signal_pt)
>>> +{
>>> + struct dma_fence *fence = NULL;
>>> + struct drm_syncobj *syncobj;
>>> +
>>> + fence = signal_pt->signal_fence;
>>> + signal_pt->signal_fence = NULL;
>>> + dma_fence_put(fence);
>>> + fence = signal_pt->pre_pt_base;
>>> + signal_pt->pre_pt_base = NULL;
>>> + dma_fence_put(fence);
>>> +
>>> + syncobj = signal_pt->syncobj;
>>> + spin_lock(&syncobj->lock);
>>> + list_del(&signal_pt->list);
>>> + syncobj->syncobj_timeline.timeline = signal_pt->value;
>>> + spin_unlock(&syncobj->lock);
>>> + /* kfree(signal_pt) will be executed by below fence put */
>>> + dma_fence_put(&signal_pt->base.base);
>>> + drm_syncobj_timeline_signal_wait_pts(syncobj);
>>> +}
>>> +static void pt_signal_fence_func(struct dma_fence *fence,
>>> + struct dma_fence_cb *cb)
>>> +{
>>> + struct drm_syncobj_signal_pt *signal_pt =
>>> + container_of(cb, struct drm_syncobj_signal_pt, signal_cb);
>>> +
>>> + if (signal_pt->pre_pt_base &&
>>> + !dma_fence_is_signaled(signal_pt->pre_pt_base))
>>> + return;
>>> +
>>> + pt_fence_cb(signal_pt);
>>> +}
>>> +static void pt_pre_fence_func(struct dma_fence *fence,
>>> + struct dma_fence_cb *cb)
>>> +{
>>> + struct drm_syncobj_signal_pt *signal_pt =
>>> + container_of(cb, struct drm_syncobj_signal_pt, pre_pt_cb);
>>> +
>>> + if (signal_pt->signal_fence &&
>>> + !dma_fence_is_signaled(signal_pt->pre_pt_base))
>>> + return;
>>> +
>>> + pt_fence_cb(signal_pt);
>>> +}
>>> +
>>> +static int drm_syncobj_timeline_replace_fence(struct drm_syncobj
>>> *syncobj,
>>> + struct dma_fence *fence,
>>> + u64 point)
>>> +{
>>> + struct drm_syncobj_signal_pt *signal_pt =
>>> + kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
>>> + struct drm_syncobj_signal_pt *tail_pt;
>>> + struct dma_fence *tail_pt_fence = NULL;
>>> + int ret = 0;
>>> +
>>> + if (!signal_pt)
>>> + return -ENOMEM;
>>> + if (syncobj->syncobj_timeline.signal_point >= point) {
>>> + DRM_WARN("A later signal is ready!");
>>> + goto out;
>>> + }
>>> + if (fence)
>>> + dma_fence_get(fence);
>>> + spin_lock(&syncobj->lock);
>>> + spin_lock_init(&signal_pt->base.lock);
>>> + dma_fence_init(&signal_pt->base.base,
>>> + &drm_syncobj_stub_fence_ops,
>>> + &signal_pt->base.lock,
>>> + syncobj->syncobj_timeline.timeline_context, point);
>>> + signal_pt->signal_fence =
>>> + rcu_dereference_protected(fence,
>>> + lockdep_is_held(&fence->lock));
>>> + if (!list_empty(&syncobj->syncobj_timeline.signal_pt_list)) {
>>> + tail_pt =
>>> list_last_entry(&syncobj->syncobj_timeline.signal_pt_list,
>>> + struct drm_syncobj_signal_pt, list);
>>> + tail_pt_fence = &tail_pt->base.base;
>>> + if (dma_fence_is_signaled(tail_pt_fence))
>>> + tail_pt_fence = NULL;
>>> + }
>>> + if (tail_pt_fence)
>>> + signal_pt->pre_pt_base =
>>> + dma_fence_get(rcu_dereference_protected(tail_pt_fence,
>>> + lockdep_is_held(&tail_pt_fence->lock)));
>>> +
>>> + signal_pt->value = point;
>>> + syncobj->syncobj_timeline.signal_point = point;
>>> + signal_pt->syncobj = syncobj;
>>> + INIT_LIST_HEAD(&signal_pt->list);
>>> + list_add_tail(&signal_pt->list,
>>> &syncobj->syncobj_timeline.signal_pt_list);
>>> + spin_unlock(&syncobj->lock);
>>> + wake_up_all(&syncobj->syncobj_timeline.wq);
>>> + /**
>>> + * Every pt is depending on signal fence and previous pt fence,
>>> add
>>> + * callbacks to them
>>> + */
>>> + if (!dma_fence_is_signaled(signal_pt->signal_fence))
>>> + dma_fence_add_callback(signal_pt->signal_fence,
>>> + &signal_pt->signal_cb,
>>> + pt_signal_fence_func);
>>> + else
>>> + pt_signal_fence_func(signal_pt->signal_fence,
>>> + &signal_pt->signal_cb);
>>> + if (signal_pt->pre_pt_base &&
>>> !dma_fence_is_signaled(signal_pt->pre_pt_base))
>>> + dma_fence_add_callback(signal_pt->pre_pt_base,
>>> + &signal_pt->pre_pt_cb,
>>> + pt_pre_fence_func);
>>> + else
>>> + pt_pre_fence_func(signal_pt->pre_pt_base,
>>> &signal_pt->pre_pt_cb);
>>> +
>>> +
>>> + return 0;
>>> +out:
>>> + kfree(signal_pt);
>>> + return ret;
>>> +}
>>> +
>>> /**
>>> * drm_syncobj_replace_fence - replace fence in a sync object.
>>> * @syncobj: Sync object to replace fence in
>>> @@ -152,6 +334,11 @@ void drm_syncobj_replace_fence(struct
>>> drm_syncobj *syncobj,
>>> struct dma_fence *old_fence;
>>> struct drm_syncobj_cb *cur, *tmp;
>>> + if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
>>> + drm_syncobj_timeline_replace_fence(syncobj, fence,
>>> + point);
>>> + return;
>>> + }
>>> if (fence)
>>> dma_fence_get(fence);
>>> @@ -174,28 +361,6 @@ void drm_syncobj_replace_fence(struct
>>> drm_syncobj *syncobj,
>>> }
>>> EXPORT_SYMBOL(drm_syncobj_replace_fence);
>>> -struct drm_syncobj_stub_fence {
>>> - struct dma_fence base;
>>> - spinlock_t lock;
>>> -};
>>> -
>>> -static const char *drm_syncobj_stub_fence_get_name(struct dma_fence
>>> *fence)
>>> -{
>>> - return "syncobjstub";
>>> -}
>>> -
>>> -static bool drm_syncobj_stub_fence_enable_signaling(struct
>>> dma_fence *fence)
>>> -{
>>> - return !dma_fence_is_signaled(fence);
>>> -}
>>> -
>>> -static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
>>> - .get_driver_name = drm_syncobj_stub_fence_get_name,
>>> - .get_timeline_name = drm_syncobj_stub_fence_get_name,
>>> - .enable_signaling = drm_syncobj_stub_fence_enable_signaling,
>>> - .release = NULL,
>>> -};
>>> -
>>> static int drm_syncobj_assign_null_handle(struct drm_syncobj
>>> *syncobj)
>>> {
>>> struct drm_syncobj_stub_fence *fence;
>>> @@ -215,6 +380,121 @@ static int
>>> drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
>>> return 0;
>>> }
>>> +static struct drm_syncobj_wait_pt *
>>> +drm_syncobj_timeline_lookup_wait_pt(struct drm_syncobj *syncobj,
>>> u64 point)
>>> +{
>>> + struct rb_node *node =
>>> syncobj->syncobj_timeline.wait_pt_tree.rb_node;
>>> + struct drm_syncobj_wait_pt *wait_pt = NULL;
>>> +
>>> +
>>> + spin_lock(&syncobj->lock);
>>> + while(node) {
>>> + int result = point - wait_pt->value;
>>> +
>>> + wait_pt = rb_entry(node, struct drm_syncobj_wait_pt, node);
>>> + if (result < 0)
>>> + node = node->rb_left;
>>> + else if (result > 0)
>>> + node = node->rb_right;
>>> + else
>>> + break;
>>> + }
>>> + spin_unlock(&syncobj->lock);
>>> +
>>> + return wait_pt;
>>> +}
>>> +
>>> +static struct drm_syncobj_wait_pt *
>>> +drm_syncobj_timeline_create_wait_pt(struct drm_syncobj *syncobj,
>>> u64 point)
>>> +{
>>> + struct drm_syncobj_wait_pt *wait_pt;
>>> + struct rb_node **new =
>>> &(syncobj->syncobj_timeline.wait_pt_tree.rb_node), *parent = NULL;
>>> +
>>> + wait_pt = kzalloc(sizeof(*wait_pt), GFP_KERNEL);
>>> + if (!wait_pt)
>>> + return NULL;
>>> + spin_lock_init(&wait_pt->base.lock);
>>> + dma_fence_init(&wait_pt->base.base,
>>> + &drm_syncobj_stub_fence_ops,
>>> + &wait_pt->base.lock,
>>> + syncobj->syncobj_timeline.timeline_context, point);
>>> + wait_pt->value = point;
>>> +
>>> + /* wait pt must be in an order, so that we can easily lookup
>>> and signal
>>> + * it */
>>> + spin_lock(&syncobj->lock);
>>> + if (point <= syncobj->syncobj_timeline.timeline)
>>> + dma_fence_signal(&wait_pt->base.base);
>>> + while(*new) {
>>> + struct drm_syncobj_wait_pt *this =
>>> + rb_entry(*new, struct drm_syncobj_wait_pt, node);
>>> + int result = wait_pt->value - this->value;
>>> +
>>> + parent = *new;
>>> + if (result < 0)
>>> + new = &((*new)->rb_left);
>>> + else if (result > 0)
>>> + new = &((*new)->rb_right);
>>> + else
>>> + goto exist;
>>> + }
>>> +
>>> + rb_link_node(&wait_pt->node, parent, new);
>>> + rb_insert_color(&wait_pt->node,
>>> &syncobj->syncobj_timeline.wait_pt_tree);
>>> + spin_unlock(&syncobj->lock);
>>> + return wait_pt;
>>> +exist:
>>> + spin_unlock(&syncobj->lock);
>>> + dma_fence_put(&wait_pt->base.base);
>>> + wait_pt = drm_syncobj_timeline_lookup_wait_pt(syncobj, point);
>>> + return wait_pt;
>>> +}
>>> +
>>> +static struct dma_fence *
>>> +drm_syncobj_timeline_point_get(struct drm_syncobj *syncobj, u64
>>> point, u64 flag)
>>> +{
>>> + struct drm_syncobj_wait_pt *wait_pt;
>>> +
>>> + /* already signaled, simply return a signaled stub fence */
>>> + if (point <= syncobj->syncobj_timeline.timeline) {
>>> + struct drm_syncobj_stub_fence *fence;
>>> +
>>> + fence = kzalloc(sizeof(*fence), GFP_KERNEL);
>>> + if (fence == NULL)
>>> + return NULL;
>>> +
>>> + spin_lock_init(&fence->lock);
>>> + dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops,
>>> + &fence->lock, 0, 0);
>>> + dma_fence_signal(&fence->base);
>>> + return &fence->base;
>>> + }
>>> +
>>> + /* check if the wait pt exists */
>>> + wait_pt = drm_syncobj_timeline_lookup_wait_pt(syncobj, point);
>>> + if (!wait_pt) {
>>> + /* This is a new wait pt, so create it */
>>> + wait_pt = drm_syncobj_timeline_create_wait_pt(syncobj, point);
>>> + if (!wait_pt)
>>> + return NULL;
>>> + }
>>> + if (wait_pt) {
>>> + struct dma_fence *fence;
>>> + int ret =
>>> + wait_event_interruptible_timeout(syncobj->syncobj_timeline.wq,
>>> + wait_pt->value <=
>>> syncobj->syncobj_timeline.signal_point,
>>> + msecs_to_jiffies(10000)); /* wait 10s */
>>> +
>>> + if (ret <= 0)
>>> + return NULL;
>>> + rcu_read_lock();
>>> + fence = dma_fence_get_rcu(&wait_pt->base.base);
>>> + rcu_read_unlock();
>>> + return fence;
>>> + }
>>> + return NULL;
>>> +}
>>> +
>>> /**
>>> * drm_syncobj_find_fence - lookup and reference the fence in a
>>> sync object
>>> * @file_private: drm file private pointer
>>> @@ -240,7 +520,17 @@ int drm_syncobj_find_fence(struct drm_file
>>> *file_private,
>>> if (!syncobj)
>>> return -ENOENT;
>>> - *fence = drm_syncobj_fence_get(syncobj);
>>> + if (syncobj->type == DRM_SYNCOBJ_TYPE_NORMAL) {
>>> + /* NORMAL syncobj doesn't care point value */
>>> + WARN_ON(point != 0);
>>> + *fence = drm_syncobj_fence_get(syncobj);
>>> + } else if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
>>> + *fence = drm_syncobj_timeline_point_get(syncobj, point,
>>> + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT);
>>> + } else {
>>> + DRM_ERROR("Don't support this type syncobj\n");
>>> + *fence = NULL;
>>> + }
>>> if (!*fence) {
>>> ret = -EINVAL;
>>> }
>>> @@ -249,6 +539,34 @@ int drm_syncobj_find_fence(struct drm_file
>>> *file_private,
>>> }
>>> EXPORT_SYMBOL(drm_syncobj_find_fence);
>>> +static void drm_syncobj_timeline_fini(struct drm_syncobj *syncobj,
>>> + struct drm_syncobj_timeline *syncobj_timeline)
>>> +{
>>> + struct rb_node *node = NULL;
>>> + struct drm_syncobj_wait_pt *wait_pt = NULL;
>>> + struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
>>> +
>>> + spin_lock(&syncobj->lock);
>>> + for(node = rb_first(&syncobj_timeline->wait_pt_tree);
>>> + node != NULL; ) {
>>> + wait_pt = rb_entry(node, struct drm_syncobj_wait_pt, node);
>>> + node = rb_next(node);
>>> + rb_erase(&wait_pt->node,
>>> + &syncobj_timeline->wait_pt_tree);
>>> + RB_CLEAR_NODE(&wait_pt->node);
>>> + /* kfree(wait_pt) is excuted by fence put */
>>> + dma_fence_put(&wait_pt->base.base);
>>> + }
>>> + list_for_each_entry_safe(signal_pt, tmp,
>>> + &syncobj_timeline->signal_pt_list, list) {
>>> + list_del(&signal_pt->list);
>>> + dma_fence_put(signal_pt->signal_fence);
>>> + dma_fence_put(signal_pt->pre_pt_base);
>>> + dma_fence_put(&signal_pt->base.base);
>>> + }
>>> + spin_unlock(&syncobj->lock);
>>> +}
>>> +
>>> /**
>>> * drm_syncobj_free - free a sync object.
>>> * @kref: kref to free.
>>> @@ -261,10 +579,23 @@ void drm_syncobj_free(struct kref *kref)
>>> struct drm_syncobj,
>>> refcount);
>>> drm_syncobj_replace_fence(syncobj, NULL, 0);
>>> + drm_syncobj_timeline_fini(syncobj, &syncobj->syncobj_timeline);
>>> kfree(syncobj);
>>> }
>>> EXPORT_SYMBOL(drm_syncobj_free);
>>> +static void drm_syncobj_timeline_init(struct drm_syncobj_timeline
>>> + *syncobj_timeline)
>>> +{
>>> + syncobj_timeline->timeline_context = dma_fence_context_alloc(1);
>>> + syncobj_timeline->timeline = 0;
>>> + syncobj_timeline->signal_point = 0;
>>> + init_waitqueue_head(&syncobj_timeline->wq);
>>> +
>>> + syncobj_timeline->wait_pt_tree = RB_ROOT;
>>> + INIT_LIST_HEAD(&syncobj_timeline->signal_pt_list);
>>> +}
>>> +
>>> /**
>>> * drm_syncobj_create - create a new syncobj
>>> * @out_syncobj: returned syncobj
>>> @@ -290,6 +621,12 @@ int drm_syncobj_create(struct drm_syncobj
>>> **out_syncobj, uint32_t flags,
>>> kref_init(&syncobj->refcount);
>>> INIT_LIST_HEAD(&syncobj->cb_list);
>>> spin_lock_init(&syncobj->lock);
>>> + if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) {
>>> + syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
>>> + drm_syncobj_timeline_init(&syncobj->syncobj_timeline);
>>> + } else {
>>> + syncobj->type = DRM_SYNCOBJ_TYPE_NORMAL;
>>> + }
>>> if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
>>> ret = drm_syncobj_assign_null_handle(syncobj);
>>> diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
>>> index 335ec501001a..342b3ced3e56 100644
>>> --- a/include/drm/drm_syncobj.h
>>> +++ b/include/drm/drm_syncobj.h
>>> @@ -30,6 +30,25 @@
>>> struct drm_syncobj_cb;
>>> +enum drm_syncobj_type {
>>> + DRM_SYNCOBJ_TYPE_NORMAL,
>>> + DRM_SYNCOBJ_TYPE_TIMELINE
>>> +};
>>> +
>>> +struct drm_syncobj_timeline {
>>> + wait_queue_head_t wq;
>>> + u64 timeline_context;
>>> + /**
>>> + * @timeline: syncobj timeline
>>> + */
>>> + u64 timeline;
>>> + u64 signal_point;
>>> +
>>> +
>>> + struct rb_root wait_pt_tree;
>>> + struct list_head signal_pt_list;
>>> +};
>>> +
>>> /**
>>> * struct drm_syncobj - sync object.
>>> *
>>> @@ -40,6 +59,15 @@ struct drm_syncobj {
>>> * @refcount: Reference count of this object.
>>> */
>>> struct kref refcount;
>>> + /**
>>> + * @type: indicate syncobj type
>>> + */
>>> + enum drm_syncobj_type type;
>>> + /**
>>> + * @syncobj_timeline: timeline
>>> + */
>>> + struct drm_syncobj_timeline syncobj_timeline;
>>> +
>>> /**
>>> * @fence:
>>> * NULL or a pointer to the fence bound to this object.
>>> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
>>> index 300f336633f2..cebdb2541eb7 100644
>>> --- a/include/uapi/drm/drm.h
>>> +++ b/include/uapi/drm/drm.h
>>> @@ -717,6 +717,7 @@ struct drm_prime_handle {
>>> struct drm_syncobj_create {
>>> __u32 handle;
>>> #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
>>> +#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1)
>>> __u32 flags;
>>> };
>>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list