[PATCH v5 1/2] drm/sched: Refactor ring mirror list handling.

Christian König ckoenig.leichtzumerken at gmail.com
Wed Jan 9 10:22:23 UTC 2019


Am 07.01.19 um 20:47 schrieb Grodzovsky, Andrey:
>
> On 01/07/2019 09:13 AM, Christian König wrote:
>> Am 03.01.19 um 18:42 schrieb Grodzovsky, Andrey:
>>> On 01/03/2019 11:20 AM, Grodzovsky, Andrey wrote:
>>>> On 01/03/2019 03:54 AM, Koenig, Christian wrote:
>>>>> Am 21.12.18 um 21:36 schrieb Grodzovsky, Andrey:
>>>>>> On 12/21/2018 01:37 PM, Christian König wrote:
>>>>>>> Am 20.12.18 um 20:23 schrieb Andrey Grodzovsky:
>>>>>>>> Decauple sched threads stop and start and ring mirror
>>>>>>>> list handling from the policy of what to do about the
>>>>>>>> guilty jobs.
>>>>>>>> When stoppping the sched thread and detaching sched fences
>>>>>>>> from non signaled HW fenes wait for all signaled HW fences
>>>>>>>> to complete before rerunning the jobs.
>>>>>>>>
>>>>>>>> v2: Fix resubmission of guilty job into HW after refactoring.
>>>>>>>>
>>>>>>>> v4:
>>>>>>>> Full restart for all the jobs, not only from guilty ring.
>>>>>>>> Extract karma increase into standalone function.
>>>>>>>>
>>>>>>>> v5:
>>>>>>>> Rework waiting for signaled jobs without relying on the job
>>>>>>>> struct itself as those might already be freed for non 'guilty'
>>>>>>>> job's schedulers.
>>>>>>>> Expose karma increase to drivers.
>>>>>>>>
>>>>>>>> Suggested-by: Christian Koenig <Christian.Koenig at amd.com>
>>>>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky at amd.com>
>>>>>>>> ---
>>>>>>>>        drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |  18 +--
>>>>>>>>        drivers/gpu/drm/etnaviv/etnaviv_sched.c    |  11 +-
>>>>>>>>        drivers/gpu/drm/scheduler/sched_main.c     | 188
>>>>>>>> +++++++++++++++++++----------
>>>>>>>>        drivers/gpu/drm/v3d/v3d_sched.c            |  12 +-
>>>>>>>>        include/drm/gpu_scheduler.h                |  10 +-
>>>>>>>>        5 files changed, 151 insertions(+), 88 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>>> index 8a078f4..a4bd2d3 100644
>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>>>> @@ -3298,12 +3298,10 @@ static int
>>>>>>>> amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
>>>>>>>>                if (!ring || !ring->sched.thread)
>>>>>>>>                    continue;
>>>>>>>>        -        kthread_park(ring->sched.thread);
>>>>>>>> +        drm_sched_stop(&ring->sched, job ? &job->base : NULL);
>>>>>>>>        -        if (job && job->base.sched != &ring->sched)
>>>>>>>> -            continue;
>>>>>>>> -
>>>>>>>> -        drm_sched_hw_job_reset(&ring->sched, job ? &job->base :
>>>>>>>> NULL);
>>>>>>>> +        if(job)
>>>>>>>> + drm_sched_increase_karma(&job->base);
>>>>>>> Since we dropped the "job && job->base.sched != &ring->sched" check
>>>>>>> above this will now increase the jobs karma multiple times.
>>>>>>>
>>>>>>> Maybe just move that outside of the loop.
>>>>>>>
>>>>>>>>                  /* after all hw jobs are reset, hw fence is
>>>>>>>> meaningless,
>>>>>>>> so force_completion */
>>>>>>>> amdgpu_fence_driver_force_completion(ring);
>>>>>>>> @@ -3454,14 +3452,10 @@ static void
>>>>>>>> amdgpu_device_post_asic_reset(struct amdgpu_device *adev,
>>>>>>>>                if (!ring || !ring->sched.thread)
>>>>>>>>                    continue;
>>>>>>>>        -        /* only need recovery sched of the given job's ring
>>>>>>>> -         * or all rings (in the case @job is NULL)
>>>>>>>> -         * after above amdgpu_reset accomplished
>>>>>>>> -         */
>>>>>>>> -        if ((!job || job->base.sched == &ring->sched) &&
>>>>>>>> !adev->asic_reset_res)
>>>>>>>> - drm_sched_job_recovery(&ring->sched);
>>>>>>>> +        if (!adev->asic_reset_res)
>>>>>>>> + drm_sched_resubmit_jobs(&ring->sched);
>>>>>>>>        -        kthread_unpark(ring->sched.thread);
>>>>>>>> +        drm_sched_start(&ring->sched, !adev->asic_reset_res);
>>>>>>>>            }
>>>>>>>>              if (!amdgpu_device_has_dc_support(adev)) {
>>>>>>>> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
>>>>>>>> b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
>>>>>>>> index 49a6763..6f1268f 100644
>>>>>>>> --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
>>>>>>>> +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
>>>>>>>> @@ -109,16 +109,19 @@ static void etnaviv_sched_timedout_job(struct
>>>>>>>> drm_sched_job *sched_job)
>>>>>>>>            }
>>>>>>>>              /* block scheduler */
>>>>>>>> -    kthread_park(gpu->sched.thread);
>>>>>>>> -    drm_sched_hw_job_reset(&gpu->sched, sched_job);
>>>>>>>> +    drm_sched_stop(&gpu->sched, sched_job);
>>>>>>>> +
>>>>>>>> +    if(sched_job)
>>>>>>>> +        drm_sched_increase_karma(sched_job);
>>>>>>>>              /* get the GPU back into the init state */
>>>>>>>>            etnaviv_core_dump(gpu);
>>>>>>>>            etnaviv_gpu_recover_hang(gpu);
>>>>>>>>        + drm_sched_resubmit_jobs(&gpu->sched);
>>>>>>>> +
>>>>>>>>            /* restart scheduler after GPU is usable again */
>>>>>>>> -    drm_sched_job_recovery(&gpu->sched);
>>>>>>>> -    kthread_unpark(gpu->sched.thread);
>>>>>>>> +    drm_sched_start(&gpu->sched, true);
>>>>>>>>        }
>>>>>>>>          static void etnaviv_sched_free_job(struct drm_sched_job
>>>>>>>> *sched_job)
>>>>>>>> diff --git a/drivers/gpu/drm/scheduler/sched_main.c
>>>>>>>> b/drivers/gpu/drm/scheduler/sched_main.c
>>>>>>>> index dbb6906..b5c5bee 100644
>>>>>>>> --- a/drivers/gpu/drm/scheduler/sched_main.c
>>>>>>>> +++ b/drivers/gpu/drm/scheduler/sched_main.c
>>>>>>>> @@ -60,8 +60,6 @@
>>>>>>>>          static void drm_sched_process_job(struct dma_fence *f,
>>>>>>>> struct
>>>>>>>> dma_fence_cb *cb);
>>>>>>>>        -static void drm_sched_expel_job_unlocked(struct
>>>>>>>> drm_sched_job
>>>>>>>> *s_job);
>>>>>>>> -
>>>>>>>>        /**
>>>>>>>>         * drm_sched_rq_init - initialize a given run queue struct
>>>>>>>>         *
>>>>>>>> @@ -335,6 +333,42 @@ static void drm_sched_job_timedout(struct
>>>>>>>> work_struct *work)
>>>>>>>> spin_unlock_irqrestore(&sched->job_list_lock, flags);
>>>>>>>>        }
>>>>>>> Kernel doc here would be nice to have.
>>>>>>>
>>>>>>>> +void drm_sched_increase_karma(struct drm_sched_job *bad)
>>>>>>>> +{
>>>>>>>> +    int i;
>>>>>>>> +    struct drm_sched_entity *tmp;
>>>>>>>> +    struct drm_sched_entity *entity;
>>>>>>>> +    struct drm_gpu_scheduler *sched = bad->sched;
>>>>>>>> +
>>>>>>>> +    /* don't increase @bad's karma if it's from KERNEL RQ,
>>>>>>>> +     * because sometimes GPU hang would cause kernel jobs (like VM
>>>>>>>> updating jobs)
>>>>>>>> +     * corrupt but keep in mind that kernel jobs always considered
>>>>>>>> good.
>>>>>>>> +     */
>>>>>>>> +    if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
>>>>>>>> +        atomic_inc(&bad->karma);
>>>>>>>> +        for (i = DRM_SCHED_PRIORITY_MIN; i <
>>>>>>>> DRM_SCHED_PRIORITY_KERNEL;
>>>>>>>> +             i++) {
>>>>>>>> +            struct drm_sched_rq *rq = &sched->sched_rq[i];
>>>>>>>> +
>>>>>>>> +            spin_lock(&rq->lock);
>>>>>>>> +            list_for_each_entry_safe(entity, tmp, &rq->entities,
>>>>>>>> list) {
>>>>>>>> +                if (bad->s_fence->scheduled.context ==
>>>>>>>> +                    entity->fence_context) {
>>>>>>>> +                    if (atomic_read(&bad->karma) >
>>>>>>>> +                        bad->sched->hang_limit)
>>>>>>>> +                        if (entity->guilty)
>>>>>>>> + atomic_set(entity->guilty, 1);
>>>>>>>> +                    break;
>>>>>>>> +                }
>>>>>>>> +            }
>>>>>>>> +            spin_unlock(&rq->lock);
>>>>>>>> +            if (&entity->list != &rq->entities)
>>>>>>>> +                break;
>>>>>>>> +        }
>>>>>>>> +    }
>>>>>>>> +}
>>>>>>>> +EXPORT_SYMBOL(drm_sched_increase_karma);
>>>>>>>> +
>>>>>>>>        /**
>>>>>>>>         * drm_sched_hw_job_reset - stop the scheduler if it
>>>>>>>> contains the
>>>>>>>> bad job
>>>>>>>>         *
>>>>>>>> @@ -342,13 +376,22 @@ static void drm_sched_job_timedout(struct
>>>>>>>> work_struct *work)
>>>>>>>>         * @bad: bad scheduler job
>>>>>>>>         *
>>>>>>>>         */
>>>>>>>> -void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched,
>>>>>>>> struct
>>>>>>>> drm_sched_job *bad)
>>>>>>>> +void drm_sched_stop(struct drm_gpu_scheduler *sched, struct
>>>>>>>> drm_sched_job *bad)
>>>>>>>>        {
>>>>>>>> -    struct drm_sched_job *s_job;
>>>>>>>> -    struct drm_sched_entity *entity, *tmp;
>>>>>>>> +    struct drm_sched_job *s_job, *last_job;
>>>>>>>>            unsigned long flags;
>>>>>>>> -    int i;
>>>>>>>> +    struct dma_fence *wait_fence =  NULL;
>>>>>>>> +    int r;
>>>>>>>> +
>>>>>>>> +    kthread_park(sched->thread);
>>>>>>>>        +    /*
>>>>>>>> +     * Verify all the signaled jobs in mirror list are removed
>>>>>>>> from
>>>>>>>> the ring
>>>>>>>> +     * by waiting for their respective scheduler fences to signal.
>>>>>>>> +     * Continually  repeat traversing the ring mirror list
>>>>>>>> until no
>>>>>>>> more signaled
>>>>>>>> +     * fences are found
>>>>>>>> +     */
>>>>>>>> +retry_wait:
>>>>>>>> spin_lock_irqsave(&sched->job_list_lock, flags);
>>>>>>>>            list_for_each_entry_reverse(s_job,
>>>>>>>> &sched->ring_mirror_list,
>>>>>>>> node) {
>>>>>>>>                if (s_job->s_fence->parent &&
>>>>>>>> @@ -357,35 +400,45 @@ void drm_sched_hw_job_reset(struct
>>>>>>>> drm_gpu_scheduler *sched, struct drm_sched_jo
>>>>>>>> dma_fence_put(s_job->s_fence->parent);
>>>>>>>>                    s_job->s_fence->parent = NULL;
>>>>>>>> atomic_dec(&sched->hw_rq_count);
>>>>>>>> +        } else {
>>>>>>>> +             wait_fence =
>>>>>>>> dma_fence_get(&s_job->s_fence->finished);
>>>>>>>> +             last_job = s_job;
>>>>>>>> +             break;
>>>>>>>>                }
>>>>>>>>            }
>>>>>>>> - spin_unlock_irqrestore(&sched->job_list_lock, flags);
>>>>>>>>        -    if (bad && bad->s_priority !=
>>>>>>>> DRM_SCHED_PRIORITY_KERNEL) {
>>>>>>>> -        atomic_inc(&bad->karma);
>>>>>>>> -        /* don't increase @bad's karma if it's from KERNEL RQ,
>>>>>>>> -         * becuase sometimes GPU hang would cause kernel jobs
>>>>>>>> (like
>>>>>>>> VM updating jobs)
>>>>>>>> -         * corrupt but keep in mind that kernel jobs always
>>>>>>>> considered good.
>>>>>>>> -         */
>>>>>>>> -        for (i = DRM_SCHED_PRIORITY_MIN; i <
>>>>>>>> DRM_SCHED_PRIORITY_KERNEL; i++ ) {
>>>>>>>> -            struct drm_sched_rq *rq = &sched->sched_rq[i];
>>>>>>>> +    /* No signaled jobs in the ring, its safe to proceed to ASIC
>>>>>>>> reset */
>>>>>>>> +    if (!wait_fence) {
>>>>>>>> + spin_unlock_irqrestore(&sched->job_list_lock, flags);
>>>>>>>> +        goto done;
>>>>>>>> +    }
>>>>>>>>        -            spin_lock(&rq->lock);
>>>>>>>> -            list_for_each_entry_safe(entity, tmp, &rq->entities,
>>>>>>>> list) {
>>>>>>>> -                if (bad->s_fence->scheduled.context ==
>>>>>>>> entity->fence_context) {
>>>>>>>> -                    if (atomic_read(&bad->karma) >
>>>>>>>> bad->sched->hang_limit)
>>>>>>>> -                        if (entity->guilty)
>>>>>>>> - atomic_set(entity->guilty, 1);
>>>>>>>> -                    break;
>>>>>>>> -                }
>>>>>>>> -            }
>>>>>>>> -            spin_unlock(&rq->lock);
>>>>>>>> -            if (&entity->list != &rq->entities)
>>>>>>>> -                break;
>>>>>>>> +    /* Restore removed cb since removing again already removed
>>>>>>>> cb is
>>>>>>>> undefined */
>>>>>>>> +    list_for_each_entry_reverse(s_job, &sched->ring_mirror_list,
>>>>>>>> node) {
>>>>>>>> +        if(s_job == last_job)
>>>>>>>> +            break;
>>>>>>> Need to double check after the holidays, but you should be able
>>>>>>> to use
>>>>>>> list_for_each_entry_continue here.
>>>>>> I think it should work - kind of traversing back on all the jobs
>>>>>> we just
>>>>>> removed their callbacks.
>>>>> Wrapping your head around stuff again after the holidays sometimes
>>>>> shows
>>>>> new problems we have completely missed :)
>>>>>
>>>>> Adding the callbacks again won't work because we have freed up our
>>>>> reference to the hardware fence above:
>>>>>> dma_fence_put(s_job->s_fence->parent);
>>>>>>                    s_job->s_fence->parent = NULL;
>>>>> We need to drop this or we would never be able to re-add the fences
>>>> Yea, that a big miss on my side...
>>>>
>>>>> .
>>>>>
>>>>> But I'm still not sure if we shouldn't rely on the correct order of
>>>>> signaling and simplify this instead.
>>>> As you said before, once we switched to signaling the parent from the
>>>> interrupt context instead of scheduled work no danger of race there
>>> Correction here - once we switched removing the job from mirror_ring
>>> list directly in interrupt context instead later from scheduled work
>> Ok, so let's stick with the approach of only waiting for the first
>> signaled one found.
>>
>> But we need to remove setting the parent fence to NULL or otherwise we
>> won't be able to add the callback ever again.
>>
>> Christian.
> But we will not be adding the cb back in drm_sched_stop anymore, now we
> are only going to add back the cb in drm_sched_startr after rerunning
> those jobs in drm_sched_resubmit_jobs and assign them a new parent there
> anyway.

Yeah, but when we find that we don't need to reset anything anymore then 
adding the callbacks again won't be possible any more.

Christian.

>
> Andrey
>
>>> Andrey
>>>
>>>> , so
>>>> what if we submit job A and after it job B and B completes before A
>>>> (like the sync dependency test in libdrm amdgpu tests but without
>>>> adding
>>>> explicit dependency to the second command on the first) I believe that
>>>> still in this case job B's parent (HW) fence will not be signaled
>>>> before
>>>> job A completes since EOP event is not signaled until the entire pipe
>>>> completed and flushed it's cashes including job A. So from this
>>>> seems to
>>>> me that indeed it's enough to wait for the last inserted job's parent
>>>> (HW) fence in ring mirror list to signal.
>>>> Let me know what you think on that.
>>>>
>>>> P.S V5 is not the last iteration and there was V6 series.
>>>>
>>>> Andrey
>>>>
>>>>> Regards,
>>>>> Christian.
>>>>>
>>>>>> Andrey
>>>>>>
>>>>>>>> +
>>>>>>>> +        if (s_job->s_fence->parent) {
>>>>>>>> +            r = dma_fence_add_callback(s_job->s_fence->parent,
>>>>>>>> + &s_job->s_fence->cb,
>>>>>>>> +                           drm_sched_process_job);
>>>>>>>> +            if (r)
>>>>>>>> +                DRM_ERROR("fence restore callback failed (%d)\n",
>>>>>>>> +                                      r);
>>>>>>> When you fail to add the callback this means that you need to call
>>>>>>> call drm_sched_process_job manually here.
>>>>>>>
>>>>>>>>                }
>>>>>>>>            }
>>>>>>>> + spin_unlock_irqrestore(&sched->job_list_lock, flags);
>>>>>>>> +
>>>>>>>> +    dma_fence_wait(wait_fence, false);
>>>>>>>> +    dma_fence_put(wait_fence);
>>>>>>>> +    wait_fence = NULL;
>>>>>>>> +
>>>>>>>> +    goto retry_wait;
>>>>>>>> +
>>>>>>>> +done:
>>>>>>>> +    return;
>>>>>>> Drop the done: label and return directly above.
>>>>>>>
>>>>>>> Apart from all those nit picks that starts to look like it should
>>>>>>> work,
>>>>>>> Christian.
>>>>>>>
>>>>>>>>        }
>>>>>>>> -EXPORT_SYMBOL(drm_sched_hw_job_reset);
>>>>>>>> +EXPORT_SYMBOL(drm_sched_stop);
>>>>>>>>          /**
>>>>>>>>         * drm_sched_job_recovery - recover jobs after a reset
>>>>>>>> @@ -393,33 +446,21 @@ EXPORT_SYMBOL(drm_sched_hw_job_reset);
>>>>>>>>         * @sched: scheduler instance
>>>>>>>>         *
>>>>>>>>         */
>>>>>>>> -void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
>>>>>>>> +void drm_sched_start(struct drm_gpu_scheduler *sched, bool
>>>>>>>> full_recovery)
>>>>>>>>        {
>>>>>>>>            struct drm_sched_job *s_job, *tmp;
>>>>>>>> -    bool found_guilty = false;
>>>>>>>>            unsigned long flags;
>>>>>>>>            int r;
>>>>>>>>        +    if (!full_recovery)
>>>>>>>> +        goto unpark;
>>>>>>>> +
>>>>>>>> spin_lock_irqsave(&sched->job_list_lock, flags);
>>>>>>>>            list_for_each_entry_safe(s_job, tmp,
>>>>>>>> &sched->ring_mirror_list,
>>>>>>>> node) {
>>>>>>>>                struct drm_sched_fence *s_fence = s_job->s_fence;
>>>>>>>> -        struct dma_fence *fence;
>>>>>>>> -        uint64_t guilty_context;
>>>>>>>> -
>>>>>>>> -        if (!found_guilty && atomic_read(&s_job->karma) >
>>>>>>>> sched->hang_limit) {
>>>>>>>> -            found_guilty = true;
>>>>>>>> -            guilty_context = s_job->s_fence->scheduled.context;
>>>>>>>> -        }
>>>>>>>> -
>>>>>>>> -        if (found_guilty && s_job->s_fence->scheduled.context ==
>>>>>>>> guilty_context)
>>>>>>>> - dma_fence_set_error(&s_fence->finished, -ECANCELED);
>>>>>>>> -
>>>>>>>> - spin_unlock_irqrestore(&sched->job_list_lock, flags);
>>>>>>>> -        fence = sched->ops->run_job(s_job);
>>>>>>>> -        atomic_inc(&sched->hw_rq_count);
>>>>>>>> +        struct dma_fence *fence = s_job->s_fence->parent;
>>>>>>>>                  if (fence) {
>>>>>>>> -            s_fence->parent = dma_fence_get(fence);
>>>>>>>>                    r = dma_fence_add_callback(fence, &s_fence->cb,
>>>>>>>> drm_sched_process_job);
>>>>>>>>                    if (r == -ENOENT)
>>>>>>>> @@ -427,18 +468,47 @@ void drm_sched_job_recovery(struct
>>>>>>>> drm_gpu_scheduler *sched)
>>>>>>>>                    else if (r)
>>>>>>>>                        DRM_ERROR("fence add callback failed (%d)\n",
>>>>>>>>                              r);
>>>>>>>> -            dma_fence_put(fence);
>>>>>>>> -        } else {
>>>>>>>> -            if (s_fence->finished.error < 0)
>>>>>>>> -                drm_sched_expel_job_unlocked(s_job);
>>>>>>>> +        } else
>>>>>>>>                    drm_sched_process_job(NULL, &s_fence->cb);
>>>>>>>> -        }
>>>>>>>> - spin_lock_irqsave(&sched->job_list_lock, flags);
>>>>>>>>            }
>>>>>>>> +
>>>>>>>>            drm_sched_start_timeout(sched);
>>>>>>>> spin_unlock_irqrestore(&sched->job_list_lock, flags);
>>>>>>>> +
>>>>>>>> +unpark:
>>>>>>>> +    kthread_unpark(sched->thread);
>>>>>>>> +}
>>>>>>>> +EXPORT_SYMBOL(drm_sched_start);
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * drm_sched_resubmit_jobs - helper to relunch job from mirror
>>>>>>>> ring
>>>>>>>> list
>>>>>>>> + *
>>>>>>>> + * @sched: scheduler instance
>>>>>>>> + *
>>>>>>>> + */
>>>>>>>> +void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
>>>>>>>> +{
>>>>>>>> +    struct drm_sched_job *s_job, *tmp;
>>>>>>>> +    uint64_t guilty_context;
>>>>>>>> +    bool found_guilty = false;
>>>>>>>> +
>>>>>>>> +    /*TODO DO we need spinlock here ? */
>>>>>>>> +    list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list,
>>>>>>>> node) {
>>>>>>>> +        struct drm_sched_fence *s_fence = s_job->s_fence;
>>>>>>>> +
>>>>>>>> +        if (!found_guilty && atomic_read(&s_job->karma) >
>>>>>>>> sched->hang_limit) {
>>>>>>>> +            found_guilty = true;
>>>>>>>> +            guilty_context = s_job->s_fence->scheduled.context;
>>>>>>>> +        }
>>>>>>>> +
>>>>>>>> +        if (found_guilty && s_job->s_fence->scheduled.context ==
>>>>>>>> guilty_context)
>>>>>>>> + dma_fence_set_error(&s_fence->finished, -ECANCELED);
>>>>>>>> +
>>>>>>>> +        s_job->s_fence->parent = sched->ops->run_job(s_job);
>>>>>>>> +        atomic_inc(&sched->hw_rq_count);
>>>>>>>> +    }
>>>>>>>>        }
>>>>>>>> -EXPORT_SYMBOL(drm_sched_job_recovery);
>>>>>>>> +EXPORT_SYMBOL(drm_sched_resubmit_jobs);
>>>>>>>>          /**
>>>>>>>>         * drm_sched_job_init - init a scheduler job
>>>>>>>> @@ -634,26 +704,14 @@ static int drm_sched_main(void *param)
>>>>>>>>                        DRM_ERROR("fence add callback failed (%d)\n",
>>>>>>>>                              r);
>>>>>>>>                    dma_fence_put(fence);
>>>>>>>> -        } else {
>>>>>>>> -            if (s_fence->finished.error < 0)
>>>>>>>> - drm_sched_expel_job_unlocked(sched_job);
>>>>>>>> +        } else
>>>>>>>>                    drm_sched_process_job(NULL, &s_fence->cb);
>>>>>>>> -        }
>>>>>>>>                  wake_up(&sched->job_scheduled);
>>>>>>>>            }
>>>>>>>>            return 0;
>>>>>>>>        }
>>>>>>>>        -static void drm_sched_expel_job_unlocked(struct
>>>>>>>> drm_sched_job *s_job)
>>>>>>>> -{
>>>>>>>> -    struct drm_gpu_scheduler *sched = s_job->sched;
>>>>>>>> -
>>>>>>>> -    spin_lock(&sched->job_list_lock);
>>>>>>>> -    list_del_init(&s_job->node);
>>>>>>>> -    spin_unlock(&sched->job_list_lock);
>>>>>>>> -}
>>>>>>>> -
>>>>>>>>        /**
>>>>>>>>         * drm_sched_init - Init a gpu scheduler instance
>>>>>>>>         *
>>>>>>>> diff --git a/drivers/gpu/drm/v3d/v3d_sched.c
>>>>>>>> b/drivers/gpu/drm/v3d/v3d_sched.c
>>>>>>>> index 445b2ef..f76d9ed 100644
>>>>>>>> --- a/drivers/gpu/drm/v3d/v3d_sched.c
>>>>>>>> +++ b/drivers/gpu/drm/v3d/v3d_sched.c
>>>>>>>> @@ -178,18 +178,22 @@ v3d_job_timedout(struct drm_sched_job
>>>>>>>> *sched_job)
>>>>>>>>            for (q = 0; q < V3D_MAX_QUEUES; q++) {
>>>>>>>>                struct drm_gpu_scheduler *sched =
>>>>>>>> &v3d->queue[q].sched;
>>>>>>>>        -        kthread_park(sched->thread);
>>>>>>>> -        drm_sched_hw_job_reset(sched, (sched_job->sched == sched ?
>>>>>>>> +        drm_sched_stop(sched, (sched_job->sched == sched ?
>>>>>>>>                                   sched_job : NULL));
>>>>>>>> +
>>>>>>>> +        if(sched_job)
>>>>>>>> +            drm_sched_increase_karma(sched_job);
>>>>>>>>            }
>>>>>>>>              /* get the GPU back into the init state */
>>>>>>>>            v3d_reset(v3d);
>>>>>>>>        +    for (q = 0; q < V3D_MAX_QUEUES; q++)
>>>>>>>> +        drm_sched_resubmit_jobs(sched_job->sched);
>>>>>>>> +
>>>>>>>>            /* Unblock schedulers and restart their jobs. */
>>>>>>>>            for (q = 0; q < V3D_MAX_QUEUES; q++) {
>>>>>>>> - drm_sched_job_recovery(&v3d->queue[q].sched);
>>>>>>>> - kthread_unpark(v3d->queue[q].sched.thread);
>>>>>>>> +        drm_sched_start(&v3d->queue[q].sched, true);
>>>>>>>>            }
>>>>>>>>              mutex_unlock(&v3d->reset_lock);
>>>>>>>> diff --git a/include/drm/gpu_scheduler.h
>>>>>>>> b/include/drm/gpu_scheduler.h
>>>>>>>> index 47e1979..5ab2d97 100644
>>>>>>>> --- a/include/drm/gpu_scheduler.h
>>>>>>>> +++ b/include/drm/gpu_scheduler.h
>>>>>>>> @@ -175,6 +175,7 @@ struct drm_sched_fence
>>>>>>>> *to_drm_sched_fence(struct
>>>>>>>> dma_fence *f);
>>>>>>>>         *               finished to remove the job from the
>>>>>>>>         * @drm_gpu_scheduler.ring_mirror_list.
>>>>>>>>         * @node: used to append this struct to the
>>>>>>>> @drm_gpu_scheduler.ring_mirror_list.
>>>>>>>> + * @finish_node: used in a list to wait on before resetting the
>>>>>>>> scheduler
>>>>>>>>         * @id: a unique id assigned to each job scheduled on the
>>>>>>>> scheduler.
>>>>>>>>         * @karma: increment on every hang caused by this job. If
>>>>>>>> this
>>>>>>>> exceeds the hang
>>>>>>>>         *         limit of the scheduler then the job is marked
>>>>>>>> guilty and
>>>>>>>> will not
>>>>>>>> @@ -193,6 +194,7 @@ struct drm_sched_job {
>>>>>>>>            struct dma_fence_cb        finish_cb;
>>>>>>>>            struct work_struct        finish_work;
>>>>>>>>            struct list_head        node;
>>>>>>>> +    struct list_head        finish_node;
>>>>>>>>            uint64_t            id;
>>>>>>>>            atomic_t            karma;
>>>>>>>>            enum drm_sched_priority        s_priority;
>>>>>>>> @@ -298,9 +300,11 @@ int drm_sched_job_init(struct drm_sched_job
>>>>>>>> *job,
>>>>>>>>                       void *owner);
>>>>>>>>        void drm_sched_job_cleanup(struct drm_sched_job *job);
>>>>>>>>        void drm_sched_wakeup(struct drm_gpu_scheduler *sched);
>>>>>>>> -void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched,
>>>>>>>> -                struct drm_sched_job *job);
>>>>>>>> -void drm_sched_job_recovery(struct drm_gpu_scheduler *sched);
>>>>>>>> +void drm_sched_stop(struct drm_gpu_scheduler *sched,
>>>>>>>> +            struct drm_sched_job *job);
>>>>>>>> +void drm_sched_start(struct drm_gpu_scheduler *sched, bool
>>>>>>>> full_recovery);
>>>>>>>> +void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched);
>>>>>>>> +void drm_sched_increase_karma(struct drm_sched_job *bad);
>>>>>>>>        bool drm_sched_dependency_optimized(struct dma_fence* fence,
>>>>>>>>                            struct drm_sched_entity *entity);
>>>>>>>>        void drm_sched_fault(struct drm_gpu_scheduler *sched);
>>>>>>> _______________________________________________
>>>>>>> amd-gfx mailing list
>>>>>>> amd-gfx at lists.freedesktop.org
>>>>>>> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
>>>>> _______________________________________________
>>>>> amd-gfx mailing list
>>>>> amd-gfx at lists.freedesktop.org
>>>>> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
>>>> _______________________________________________
>>>> dri-devel mailing list
>>>> dri-devel at lists.freedesktop.org
>>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx



More information about the amd-gfx mailing list