[PATCH] [RFC]drm: add syncobj timeline support v5

Christian König christian.koenig at amd.com
Fri Sep 14 18:27:43 UTC 2018


Am 14.09.2018 um 20:24 schrieb Daniel Vetter:
> On Fri, Sep 14, 2018 at 6:43 PM, Christian König
> <christian.koenig at amd.com> wrote:
>> Am 14.09.2018 um 18:10 schrieb Daniel Vetter:
>>> On Fri, Sep 14, 2018 at 12:49:45PM +0200, Christian König wrote:
>>>> Am 14.09.2018 um 12:37 schrieb Chunming Zhou:
>>>>> This patch is for VK_KHR_timeline_semaphore extension, semaphore is
>>>>> called syncobj in kernel side:
>>>>> This extension introduces a new type of syncobj that has an integer
>>>>> payload
>>>>> identifying a point in a timeline. Such timeline syncobjs support the
>>>>> following operations:
>>>>>       * CPU query - A host operation that allows querying the payload of
>>>>> the
>>>>>         timeline syncobj.
>>>>>       * CPU wait - A host operation that allows a blocking wait for a
>>>>>         timeline syncobj to reach a specified value.
>>>>>       * Device wait - A device operation that allows waiting for a
>>>>>         timeline syncobj to reach a specified value.
>>>>>       * Device signal - A device operation that allows advancing the
>>>>>         timeline syncobj 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. syncobj 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)
>>>>>
>>>>> v3:
>>>>> 1. replace normal syncobj with timeline implemenation. (Vetter and
>>>>> Christian)
>>>>>        a. normal syncobj signal op will create a signal PT to tail of
>>>>> signal pt list.
>>>>>        b. normal syncobj wait op will create a wait pt with last signal
>>>>> point, and this wait PT is only signaled by related signal point PT.
>>>>> 2. many bug fix and clean up
>>>>> 3. stub fence moving is moved to other patch.
>>>>>
>>>>> v4:
>>>>> 1. fix RB tree loop with while(node=rb_first(...)). (Christian)
>>>>> 2. fix syncobj lifecycle. (Christian)
>>>>> 3. only enable_signaling when there is wait_pt. (Christian)
>>>>> 4. fix timeline path issues.
>>>>> 5. write a timeline test in libdrm
>>>>>
>>>>> v5: (Christian)
>>>>> 1. semaphore is called syncobj in kernel side.
>>>>> 2. don't need 'timeline' characters in some function name.
>>>>> 3. keep syncobj cb
>>>>>
>>>>> normal syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore*
>>>>> timeline syncobj is tested by ./amdgpu_test -s 9
>>>>>
>>>>> 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>
>>>> At least on first glance that looks like it should work, going to do a
>>>> detailed review on Monday.
>>> Just for my understanding, it's all condensed down to 1 patch now? I kinda
>>> didn't follow the detailed discussion last few days at all :-/
>>
>> I've already committed all the cleanup/fix prerequisites to drm-misc-next.
>>
>> The driver specific implementation needs to come on top and maybe a new CPU
>> wait IOCTL.
>>
>> But essentially this patch is just the core of the kernel implementation.
> Ah cool, missed that.
>
>>> Also, is there a testcase, igt highly preferred (because then we'll run it
>>> in our intel-gfx CI, and a bunch of people outside of intel have already
>>> discovered that and are using it).
>>
>> libdrm patches and I think amdgpu based test cases where already published
>> as well.
>>
>> Not sure about igt testcases.
> I guess we can write them when the intel implementation shows up. Just
> kinda still hoping that we'd have a more unfified test suite. And not
> really well-kept secret: We do have an amdgpu in our CI, in the form
> of kbl-g :-) But unfortunately it's not running the full test set for
> patches (only for drm-tip). But we could perhaps run more of the
> amdgpu tests somehow, if there's serious interest.

Well I wouldn't mind if we sooner or later get rid of the amdgpu unit 
tests in libdrm.

They are more or less just a really bloody mess.

Christian.

>
> Cheers, Daniel
>
>
>> Christian.
>>
>>
>>> Thanks, Daniel
>>>
>>>> Christian.
>>>>
>>>>> ---
>>>>>     drivers/gpu/drm/drm_syncobj.c              | 294
>>>>> ++++++++++++++++++---
>>>>>     drivers/gpu/drm/i915/i915_gem_execbuffer.c |   4 +-
>>>>>     include/drm/drm_syncobj.h                  |  62 +++--
>>>>>     include/uapi/drm/drm.h                     |   1 +
>>>>>     4 files changed, 292 insertions(+), 69 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/drm_syncobj.c
>>>>> b/drivers/gpu/drm/drm_syncobj.c
>>>>> index e9ce623d049e..e78d076f2703 100644
>>>>> --- a/drivers/gpu/drm/drm_syncobj.c
>>>>> +++ b/drivers/gpu/drm/drm_syncobj.c
>>>>> @@ -56,6 +56,9 @@either
>>>>>     #include "drm_internal.h"
>>>>>     #include <drm/drm_syncobj.h>
>>>>> +/* merge normal syncobj to timeline syncobj, the point interval is 1 */
>>>>> +#define DRM_SYNCOBJ_NORMAL_POINT 1
>>>>> +
>>>>>     struct drm_syncobj_stub_fence {
>>>>>          struct dma_fence base;
>>>>>          spinlock_t lock;
>>>>> @@ -82,6 +85,11 @@ static const struct dma_fence_ops
>>>>> drm_syncobj_stub_fence_ops = {
>>>>>          .release = drm_syncobj_stub_fence_release,
>>>>>     };
>>>>> +struct drm_syncobj_signal_pt {
>>>>> +       struct dma_fence_array *base;
>>>>> +       u64    value;
>>>>> +       struct list_head list;
>>>>> +};
>>>>>     /**
>>>>>      * drm_syncobj_find - lookup and reference a sync object.
>>>>> @@ -124,7 +132,7 @@ static int
>>>>> drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
>>>>>     {
>>>>>          int ret;
>>>>> -       *fence = drm_syncobj_fence_get(syncobj);
>>>>> +       ret = drm_syncobj_search_fence(syncobj, 0, 0, fence);
>>>>>          if (*fence)
>>>>>                  return 1;
>>>>> @@ -133,10 +141,10 @@ static int
>>>>> drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
>>>>>           * have the lock, try one more time just to be sure we don't add
>>>>> a
>>>>>           * callback when a fence has already been set.
>>>>>           */
>>>>> -       if (syncobj->fence) {
>>>>> -               *fence =
>>>>> dma_fence_get(rcu_dereference_protected(syncobj->fence,
>>>>> -
>>>>> lockdep_is_held(&syncobj->lock)));
>>>>> -               ret = 1;
>>>>> +       if (fence) {
>>>>> +               drm_syncobj_search_fence(syncobj, 0, 0, fence);
>>>>> +               if (*fence)
>>>>> +                       ret = 1;
>>>>>          } else {
>>>>>                  *fence = NULL;
>>>>>                  drm_syncobj_add_callback_locked(syncobj, cb, func);
>>>>> @@ -164,6 +172,151 @@ void drm_syncobj_remove_callback(struct
>>>>> drm_syncobj *syncobj,
>>>>>          spin_unlock(&syncobj->lock);
>>>>>     }
>>>>> +static void drm_syncobj_timeline_init(struct drm_syncobj *syncobj,
>>>>> +                                     struct drm_syncobj_timeline
>>>>> *syncobj_timeline)
>>>>> +{
>>>>> +       spin_lock(&syncobj->lock);
>>>>> +       syncobj_timeline->timeline_context = dma_fence_context_alloc(1);
>>>>> +       syncobj_timeline->timeline = 0;
>>>>> +       syncobj_timeline->signal_point = 0;
>>>>> +       init_waitqueue_head(&syncobj_timeline->wq);
>>>>> +
>>>>> +       INIT_LIST_HEAD(&syncobj_timeline->signal_pt_list);
>>>>> +       spin_unlock(&syncobj->lock);
>>>>> +}
>>>>> +
>>>>> +static void drm_syncobj_timeline_fini(struct drm_syncobj *syncobj,
>>>>> +                                     struct drm_syncobj_timeline
>>>>> *syncobj_timeline)
>>>>> +{
>>>>> +       struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
>>>>> +
>>>>> +       spin_lock(&syncobj->lock);
>>>>> +       list_for_each_entry_safe(signal_pt, tmp,
>>>>> +                                &syncobj_timeline->signal_pt_list,
>>>>> list) {
>>>>> +               list_del(&signal_pt->list);
>>>>> +               dma_fence_put(&signal_pt->base->base);
>>>>> +               kfree(signal_pt);
>>>>> +       }
>>>>> +       spin_unlock(&syncobj->lock);
>>>>> +}
>>>>> +
>>>>> +static struct dma_fence
>>>>> +*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
>>>>> +                                     uint64_t point)
>>>>> +{
>>>>> +       struct drm_syncobj_timeline *timeline =
>>>>> &syncobj->syncobj_timeline;
>>>>> +       struct drm_syncobj_signal_pt *signal_pt;
>>>>> +
>>>>> +       if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
>>>>> +           (point <= timeline->timeline)) {
>>>>> +               struct drm_syncobj_stub_fence *fence =
>>>>> +                       kzalloc(sizeof(struct drm_syncobj_stub_fence),
>>>>> +                               GFP_KERNEL);
>>>>> +
>>>>> +               if (!fence)
>>>>> +                       return NULL;
>>>>> +               spin_lock_init(&fence->lock);
>>>>> +               dma_fence_init(&fence->base,
>>>>> +                              &drm_syncobj_stub_fence_ops,
>>>>> +                              &fence->lock,
>>>>> +
>>>>> syncobj->syncobj_timeline.timeline_context,
>>>>> +                              point);
>>>>> +
>>>>> +               dma_fence_signal(&fence->base);
>>>>> +               return &fence->base;
>>>>> +       }
>>>>> +
>>>>> +       list_for_each_entry(signal_pt, &timeline->signal_pt_list, list)
>>>>> {
>>>>> +               if (point > signal_pt->value)
>>>>> +                       continue;
>>>>> +               if ((syncobj->type == DRM_SYNCOBJ_TYPE_NORMAL) &&
>>>>> +                   (point != signal_pt->value))
>>>>> +                       continue;
>>>>> +               return dma_fence_get(&signal_pt->base->base);
>>>>> +       }
>>>>> +       return NULL;
>>>>> +}
>>>>> +
>>>>> +static int drm_syncobj_create_signal_pt(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 **fences;
>>>>> +       int num_fences = 0;
>>>>> +       int ret = 0, i;
>>>>> +
>>>>> +       if (!signal_pt)
>>>>> +               return -ENOMEM;
>>>>> +       if (syncobj->syncobj_timeline.signal_point >= point) {
>>>>> +               DRM_WARN("A later signal is ready!");
>>>>> +               goto out;
>>>>> +       }
>>>>> +       if (!fence)
>>>>> +               goto out;
>>>>> +
>>>>> +       fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
>>>>> +       if (!fences)
>>>>> +               goto out;
>>>>> +       fences[num_fences++] = dma_fence_get(fence);
>>>>> +       /* timeline syncobj must take this dependency */
>>>>> +       if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
>>>>> +               spin_lock(&syncobj->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);
>>>>> +                       fences[num_fences++] =
>>>>> dma_fence_get(&tail_pt->base->base);
>>>>> +               }
>>>>> +               spin_unlock(&syncobj->lock);
>>>>> +       }
>>>>> +       signal_pt->base = dma_fence_array_create(num_fences, fences,
>>>>> +
>>>>> syncobj->syncobj_timeline.timeline_context,
>>>>> +                                                point, false);
>>>>> +       if (!signal_pt->base)
>>>>> +               goto fail;
>>>>> +
>>>>> +       spin_lock(&syncobj->lock);
>>>>> +       signal_pt->value = point;
>>>>> +       INIT_LIST_HEAD(&signal_pt->list);
>>>>> +       list_add_tail(&signal_pt->list,
>>>>> &syncobj->syncobj_timeline.signal_pt_list);
>>>>> +       syncobj->syncobj_timeline.signal_point = point;
>>>>> +       spin_unlock(&syncobj->lock);
>>>>> +       wake_up_all(&syncobj->syncobj_timeline.wq);
>>>>> +
>>>>> +       return 0;
>>>>> +fail:
>>>>> +       for (i = 0; i < num_fences; i++)
>>>>> +               dma_fence_put(fences[i]);
>>>>> +       kfree(fences);
>>>>> +out:
>>>>> +       kfree(signal_pt);
>>>>> +       return ret;
>>>>> +}
>>>>> +
>>>>> +static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
>>>>> +{
>>>>> +       struct drm_syncobj_timeline *timeline =
>>>>> &syncobj->syncobj_timeline;
>>>>> +       struct drm_syncobj_signal_pt *signal_pt, *tmp;
>>>>> +
>>>>> +       spin_lock(&syncobj->lock);
>>>>> +       list_for_each_entry_safe(signal_pt, tmp,
>>>>> +                                &timeline->signal_pt_list, list) {
>>>>> +               if (dma_fence_is_signaled(&signal_pt->base->base)) {
>>>>> +                       timeline->timeline = signal_pt->value;
>>>>> +                       list_del(&signal_pt->list);
>>>>> +                       dma_fence_put(&signal_pt->base->base);
>>>>> +                       kfree(signal_pt);
>>>>> +               } else {
>>>>> +                       /*signal_pt is in order in list, from small to
>>>>> big, so
>>>>> +                        * the later must not be signal either */
>>>>> +                       break;
>>>>> +               }
>>>>> +       }
>>>>> +
>>>>> +       spin_unlock(&syncobj->lock);
>>>>> +}
>>>>>     /**
>>>>>      * drm_syncobj_replace_fence - replace fence in a sync object.
>>>>>      * @syncobj: Sync object to replace fence in
>>>>> @@ -176,28 +329,37 @@ void drm_syncobj_replace_fence(struct drm_syncobj
>>>>> *syncobj,
>>>>>                                 u64 point,
>>>>>                                 struct dma_fence *fence)
>>>>>     {
>>>>> -       struct dma_fence *old_fence;
>>>>> -       struct drm_syncobj_cb *cur, *tmp;
>>>>> -
>>>>> -       if (fence)
>>>>> -               dma_fence_get(fence);
>>>>> -
>>>>> -       spin_lock(&syncobj->lock);
>>>>> -
>>>>> -       old_fence = rcu_dereference_protected(syncobj->fence,
>>>>> -
>>>>> lockdep_is_held(&syncobj->lock));
>>>>> -       rcu_assign_pointer(syncobj->fence, fence);
>>>>> +       drm_syncobj_garbage_collection(syncobj);
>>>>> +       if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
>>>>> +               if (fence)
>>>>> +                       drm_syncobj_create_signal_pt(syncobj, fence,
>>>>> point);
>>>>> +       } else if (syncobj->type == DRM_SYNCOBJ_TYPE_NORMAL) {
>>>>> +               u64 pt_value;
>>>>> +
>>>>> +               if (!fence) {
>>>>> +                       drm_syncobj_timeline_fini(syncobj,
>>>>> +
>>>>> &syncobj->syncobj_timeline);
>>>>> +                       drm_syncobj_timeline_init(syncobj,
>>>>> +
>>>>> &syncobj->syncobj_timeline);
>>>>> +                       return;
>>>>> +               }
>>>>> +               pt_value = syncobj->syncobj_timeline.signal_point +
>>>>> +                       DRM_SYNCOBJ_NORMAL_POINT;
>>>>> +               drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
>>>>> +       } else {
>>>>> +               DRM_ERROR("the syncobj type isn't support\n");
>>>>> +               return;
>>>>> +       }
>>>>> +       if (fence) {
>>>>> +               struct drm_syncobj_cb *cur, *tmp;
>>>>> -       if (fence != old_fence) {
>>>>> +               spin_lock(&syncobj->lock);
>>>>>                  list_for_each_entry_safe(cur, tmp, &syncobj->cb_list,
>>>>> node) {
>>>>>                          list_del_init(&cur->node);
>>>>>                          cur->func(syncobj, cur);
>>>>>                  }
>>>>> +               spin_unlock(&syncobj->lock);
>>>>>          }
>>>>> -
>>>>> -       spin_unlock(&syncobj->lock);
>>>>> -
>>>>> -       dma_fence_put(old_fence);
>>>>>     }
>>>>>     EXPORT_SYMBOL(drm_syncobj_replace_fence);
>>>>> @@ -220,6 +382,25 @@ static int drm_syncobj_assign_null_handle(struct
>>>>> drm_syncobj *syncobj)
>>>>>          return 0;
>>>>>     }
>>>>> +static struct dma_fence *
>>>>> +drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64
>>>>> flags)
>>>>> +{
>>>>> +       struct dma_fence *fence;
>>>>> +       int ret = 0;
>>>>> +
>>>>> +       if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
>>>>> +               ret = wait_event_timeout(syncobj->syncobj_timeline.wq,
>>>>> +                                       point <=
>>>>> syncobj->syncobj_timeline.signal_point,
>>>>> +                                       msecs_to_jiffies(10000)); /*
>>>>> wait 10s */
>>>>> +               if (ret <= 0)
>>>>> +                       return NULL;
>>>>> +       }
>>>>> +       spin_lock(&syncobj->lock);
>>>>> +       fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
>>>>> +       spin_unlock(&syncobj->lock);
>>>>> +       return fence;
>>>>> +}
>>>>> +
>>>>>     /**
>>>>>      * drm_syncobj_find_fence - lookup and reference the fence in a sync
>>>>> object
>>>>>      * @file_private: drm file private pointer
>>>>> @@ -234,20 +415,46 @@ static int drm_syncobj_assign_null_handle(struct
>>>>> drm_syncobj *syncobj)
>>>>>      * contains a reference to the fence, which must be released by
>>>>> calling
>>>>>      * dma_fence_put().
>>>>>      */
>>>>> -int drm_syncobj_find_fence(struct drm_file *file_private,
>>>>> -                          u32 handle, u64 point,
>>>>> -                          struct dma_fence **fence)
>>>>> +int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
>>>>> +                            u64 flags, struct dma_fence **fence)
>>>>>     {
>>>>> -       struct drm_syncobj *syncobj = drm_syncobj_find(file_private,
>>>>> handle);
>>>>>          int ret = 0;
>>>>>          if (!syncobj)
>>>>>                  return -ENOENT;
>>>>> -       *fence = drm_syncobj_fence_get(syncobj);
>>>>> +       drm_syncobj_garbage_collection(syncobj);
>>>>> +       if (syncobj->type == DRM_SYNCOBJ_TYPE_NORMAL) {
>>>>> +               /*NORMAL syncobj always wait on last pt */
>>>>> +               u64 tail_pt_value =
>>>>> syncobj->syncobj_timeline.signal_point;
>>>>> +
>>>>> +               if (tail_pt_value == 0)
>>>>> +                       tail_pt_value += DRM_SYNCOBJ_NORMAL_POINT;
>>>>> +               /* NORMAL syncobj doesn't care point value */
>>>>> +               WARN_ON(point != 0);
>>>>> +               *fence = drm_syncobj_point_get(syncobj, tail_pt_value,
>>>>> +                                                       flags);
>>>>> +       } else if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
>>>>> +               *fence = drm_syncobj_point_get(syncobj, point,
>>>>> +                                                       flags);
>>>>> +       } else {
>>>>> +               DRM_ERROR("Don't support this type syncobj\n");
>>>>> +               *fence = NULL;
>>>>> +       }
>>>>>          if (!*fence) {
>>>>>                  ret = -EINVAL;
>>>>>          }
>>>>> +       return ret;
>>>>> +}
>>>>> +EXPORT_SYMBOL(drm_syncobj_search_fence);
>>>>> +int drm_syncobj_find_fence(struct drm_file *file_private,
>>>>> +                          u32 handle, u64 point,
>>>>> +                          struct dma_fence **fence) {
>>>>> +       struct drm_syncobj *syncobj = drm_syncobj_find(file_private,
>>>>> handle);
>>>>> +
>>>>> +       int ret = drm_syncobj_search_fence(syncobj, point,
>>>>> +
>>>>> DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
>>>>> +                                       fence);
>>>>>          drm_syncobj_put(syncobj);
>>>>>          return ret;
>>>>>     }
>>>>> @@ -264,7 +471,7 @@ void drm_syncobj_free(struct kref *kref)
>>>>>          struct drm_syncobj *syncobj = container_of(kref,
>>>>>                                                     struct drm_syncobj,
>>>>>                                                     refcount);
>>>>> -       drm_syncobj_replace_fence(syncobj, 0, NULL);
>>>>> +       drm_syncobj_timeline_fini(syncobj, &syncobj->syncobj_timeline);
>>>>>          kfree(syncobj);
>>>>>     }
>>>>>     EXPORT_SYMBOL(drm_syncobj_free);
>>>>> @@ -294,6 +501,11 @@ 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;
>>>>> +       else
>>>>> +               syncobj->type = DRM_SYNCOBJ_TYPE_NORMAL;
>>>>> +       drm_syncobj_timeline_init(syncobj, &syncobj->syncobj_timeline);
>>>>>          if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
>>>>>                  ret = drm_syncobj_assign_null_handle(syncobj);
>>>>> @@ -576,7 +788,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev,
>>>>> void *data,
>>>>>                  return -ENODEV;
>>>>>          /* no valid flags yet */
>>>>> -       if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
>>>>> +       if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
>>>>> +                           DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
>>>>>                  return -EINVAL;
>>>>>          return drm_syncobj_create_as_handle(file_private,
>>>>> @@ -669,9 +882,8 @@ static void syncobj_wait_syncobj_func(struct
>>>>> drm_syncobj *syncobj,
>>>>>          struct syncobj_wait_entry *wait =
>>>>>                  container_of(cb, struct syncobj_wait_entry, syncobj_cb);
>>>>> -       /* This happens inside the syncobj lock */
>>>>> -       wait->fence =
>>>>> dma_fence_get(rcu_dereference_protected(syncobj->fence,
>>>>> -
>>>>> lockdep_is_held(&syncobj->lock)));
>>>>> +       drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
>>>>> +
>>>>>          wake_up_process(wait->task);
>>>>>     }
>>>>> @@ -698,7 +910,8 @@ static signed long
>>>>> drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
>>>>>          signaled_count = 0;
>>>>>          for (i = 0; i < count; ++i) {
>>>>>                  entries[i].task = current;
>>>>> -               entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
>>>>> +               ret = drm_syncobj_search_fence(syncobjs[i], 0, 0,
>>>>> +                                              &entries[i].fence);
>>>>>                  if (!entries[i].fence) {
>>>>>                          if (flags &
>>>>> DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
>>>>>                                  continue;
>>>>> @@ -970,12 +1183,21 @@ drm_syncobj_reset_ioctl(struct drm_device *dev,
>>>>> void *data,
>>>>>          if (ret < 0)
>>>>>                  return ret;
>>>>> -       for (i = 0; i < args->count_handles; i++)
>>>>> -               drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
>>>>> -
>>>>> +       for (i = 0; i < args->count_handles; i++) {
>>>>> +               if (syncobjs[i]->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
>>>>> +                       DRM_ERROR("timeline syncobj cannot reset!\n");
>>>>> +                       ret = -EINVAL;
>>>>> +                       goto out;
>>>>> +               }
>>>>> +               drm_syncobj_timeline_fini(syncobjs[i],
>>>>> +
>>>>> &syncobjs[i]->syncobj_timeline);
>>>>> +               drm_syncobj_timeline_init(syncobjs[i],
>>>>> +
>>>>> &syncobjs[i]->syncobj_timeline);
>>>>> +       }
>>>>> +out:
>>>>>          drm_syncobj_array_free(syncobjs, args->count_handles);
>>>>> -       return 0;
>>>>> +       return ret;
>>>>>     }
>>>>>     int
>>>>> diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
>>>>> b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
>>>>> index 0a8d2d64f380..579e91a5858b 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
>>>>> @@ -2137,7 +2137,9 @@ await_fence_array(struct i915_execbuffer *eb,
>>>>>                  if (!(flags & I915_EXEC_FENCE_WAIT))
>>>>>                          continue;
>>>>> -               fence = drm_syncobj_fence_get(syncobj);
>>>>> +               drm_syncobj_search_fence(syncobj, 0,
>>>>> +
>>>>> DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
>>>>> +                                        &fence);
>>>>>                  if (!fence)
>>>>>                          return -EINVAL;
>>>>> diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
>>>>> index 425432b85a87..9535521e6623 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.
>>>>>      *
>>>>> @@ -41,19 +60,19 @@ struct drm_syncobj {
>>>>>           */
>>>>>          struct kref refcount;
>>>>>          /**
>>>>> -        * @fence:
>>>>> -        * NULL or a pointer to the fence bound to this object.
>>>>> -        *
>>>>> -        * This field should not be used directly. Use
>>>>> drm_syncobj_fence_get()
>>>>> -        * and drm_syncobj_replace_fence() instead.
>>>>> +        * @type: indicate syncobj type
>>>>>           */
>>>>> -       struct dma_fence __rcu *fence;
>>>>> +       enum drm_syncobj_type type;
>>>>>          /**
>>>>> -        * @cb_list: List of callbacks to call when the &fence gets
>>>>> replaced.
>>>>> +        * @syncobj_timeline: timeline
>>>>>           */
>>>>> +       struct drm_syncobj_timeline syncobj_timeline;
>>>>> +       /**
>>>>> +         * @cb_list: List of callbacks to call when the &fence gets
>>>>> replaced.
>>>>> +         */
>>>>>          struct list_head cb_list;
>>>>>          /**
>>>>> -        * @lock: Protects &cb_list and write-locks &fence.
>>>>> +        * @lock: Protects syncobj list and write-locks &fence.
>>>>>           */
>>>>>          spinlock_t lock;
>>>>>          /**
>>>>> @@ -68,7 +87,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj
>>>>> *syncobj,
>>>>>     /**
>>>>>      * struct drm_syncobj_cb - callback for drm_syncobj_add_callback
>>>>>      * @node: used by drm_syncob_add_callback to append this struct to
>>>>> - *       &drm_syncobj.cb_list
>>>>> + *       &drm_syncobj.cb_list
>>>>>      * @func: drm_syncobj_func_t to call
>>>>>      *
>>>>>      * This struct will be initialized by drm_syncobj_add_callback,
>>>>> additional
>>>>> @@ -106,29 +125,6 @@ drm_syncobj_put(struct drm_syncobj *obj)
>>>>>          kref_put(&obj->refcount, drm_syncobj_free);
>>>>>     }
>>>>> -/**
>>>>> - * drm_syncobj_fence_get - get a reference to a fence in a sync object
>>>>> - * @syncobj: sync object.
>>>>> - *
>>>>> - * This acquires additional reference to &drm_syncobj.fence contained
>>>>> in @obj,
>>>>> - * if not NULL. It is illegal to call this without already holding a
>>>>> reference.
>>>>> - * No locks required.
>>>>> - *
>>>>> - * Returns:
>>>>> - * Either the fence of @obj or NULL if there's none.
>>>>> - */
>>>>> -static inline struct dma_fence *
>>>>> -drm_syncobj_fence_get(struct drm_syncobj *syncobj)
>>>>> -{
>>>>> -       struct dma_fence *fence;
>>>>> -
>>>>> -       rcu_read_lock();
>>>>> -       fence = dma_fence_get_rcu_safe(&syncobj->fence);
>>>>> -       rcu_read_unlock();
>>>>> -
>>>>> -       return fence;
>>>>> -}
>>>>> -
>>>>>     struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
>>>>>                                       u32 handle);
>>>>>     void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64
>>>>> point,
>>>>> @@ -142,5 +138,7 @@ int drm_syncobj_create(struct drm_syncobj
>>>>> **out_syncobj, uint32_t flags,
>>>>>     int drm_syncobj_get_handle(struct drm_file *file_private,
>>>>>                             struct drm_syncobj *syncobj, u32 *handle);
>>>>>     int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd);
>>>>> +int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
>>>>> +                            u64 flags, struct dma_fence **fence);
>>>>>     #endif
>>>>> 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;
>>>>>     };
>>
>
>



More information about the amd-gfx mailing list