[PATCH 3/3] drm/amdgpu: Avoid HW reset if guilty job already signaled.
Grodzovsky, Andrey
Andrey.Grodzovsky at amd.com
Wed Apr 10 15:05:24 UTC 2019
On 4/10/19 10:41 AM, Christian König wrote:
> Am 10.04.19 um 16:28 schrieb Grodzovsky, Andrey:
>> On 4/10/19 10:06 AM, Christian König wrote:
>>> Am 09.04.19 um 18:42 schrieb Grodzovsky, Andrey:
>>>> On 4/9/19 10:50 AM, Christian König wrote:
>>>>> Am 08.04.19 um 18:08 schrieb Andrey Grodzovsky:
>>>>>> Also reject TDRs if another one already running.
>>>>>>
>>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky at amd.com>
>>>>>> ---
>>>>>> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 94
>>>>>> +++++++++++++++++++++---------
>>>>>> 1 file changed, 67 insertions(+), 27 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> index aabd043..4446892 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>>>>> @@ -3327,10 +3327,12 @@ bool amdgpu_device_should_recover_gpu(struct
>>>>>> amdgpu_device *adev)
>>>>>> static int amdgpu_device_pre_asic_reset(struct amdgpu_device
>>>>>> *adev,
>>>>>> struct amdgpu_job *job,
>>>>>> - bool *need_full_reset_arg)
>>>>>> + bool *need_full_reset_arg,
>>>>>> + bool *job_signaled)
>>>>>> {
>>>>>> int i, r = 0;
>>>>>> bool need_full_reset = *need_full_reset_arg;
>>>>>> + struct amdgpu_ring *job_ring = job ?
>>>>>> to_amdgpu_ring(job->base.sched) : NULL;
>>>>>> /* block all schedulers and reset given job's ring */
>>>>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
>>>>>> @@ -3341,6 +3343,17 @@ static int
>>>>>> amdgpu_device_pre_asic_reset(struct
>>>>>> amdgpu_device *adev,
>>>>>> drm_sched_stop(&ring->sched, &job->base);
>>>>>> + /*
>>>>>> + * Must check guilty signal here since after this point
>>>>>> all old
>>>>>> + * HW fences are force signaled.
>>>>>> + *
>>>>>> + * job->base holds a reference to parent fence
>>>>>> + */
>>>>>> + if (job_signaled && job && ring == job_ring &&
>>>>>> + job->base.s_fence->parent &&
>>>>>> + dma_fence_is_signaled(job->base.s_fence->parent))
>>>>>> + *job_signaled = true;
>>>>>> +
>>>>> That won't work correctly. See when the guilty job is not on the
>>>>> first
>>>>> scheduler, you would already have force completed some before getting
>>>>> here.
>>>>>
>>>>> Better to stop all schedulers first and then do the check.
>>>>>
>>>>> Christian.
>>>> What do you mean by first scheduler ? There is one scheduler object
>>>> per
>>>> ring so I am not clear what 'first' means here.
>>> Well for example if the guilty job is from a compute ring the we have
>>> already force signaled the gfx ring here.
>>>
>>> Same is true for other devices in the same hive, so it would probably
>>> be a good idea to move the force signaling and the IP reset somewhere
>>> else and this check up a layer.
>>>
>>> Christian.
>>
>> Let me see if I understand you correctly - you want to AVOID ANY force
>> signaling in case we are not going to HW reset and so you want to have
>> the check if guilty is signaled BEFORE any ring fences are force
>> signaled. Correct ?
>
> Correct.
>
> Basically we should do the following:
> 1. Stop all schedulers to make sure that nothing is going on.
> 2. Check the guilty job once more to make sure that it hasn't signaled
> in the meantime.
> 3. Start our reset procedure, with force complete, soft reset
> eventually hard reset etc etc..
> 4. Resubmit all not yet completed jobs.
> 5. Start the schedulers again.
>
> Christian.
Why not just always ensure the guilty job's ring is always checked
first and then do the rest of the rings - inside
amdgpu_device_pre_asic_reset. Seems to me like a much smaller change
with less impact to current code structure.
Andrey
>
>>
>> Andrey
>>
>>>> Andrey
>>>>
>>>>
>>>>>> /* after all hw jobs are reset, hw fence is
>>>>>> meaningless, so
>>>>>> force_completion */
>>>>>> amdgpu_fence_driver_force_completion(ring);
>>>>>> }
>>>>>> @@ -3358,7 +3371,8 @@ static int amdgpu_device_pre_asic_reset(struct
>>>>>> amdgpu_device *adev,
>>>>>> - if (!amdgpu_sriov_vf(adev)) {
>>>>>> + /* Don't suspend on bare metal if we are not going to HW reset
>>>>>> the ASIC */
>>>>>> + if (!amdgpu_sriov_vf(adev) && !(*job_signaled)) {
>>>>>> if (!need_full_reset)
>>>>>> need_full_reset =
>>>>>> amdgpu_device_ip_need_full_reset(adev);
>>>>>> @@ -3495,7 +3509,7 @@ static int amdgpu_do_asic_reset(struct
>>>>>> amdgpu_hive_info *hive,
>>>>>> return r;
>>>>>> }
>>>>>> -static void amdgpu_device_post_asic_reset(struct amdgpu_device
>>>>>> *adev)
>>>>>> +static void amdgpu_device_post_asic_reset(struct amdgpu_device
>>>>>> *adev, bool job_signaled)
>>>>>> {
>>>>>> int i;
>>>>>> @@ -3505,7 +3519,8 @@ static void
>>>>>> amdgpu_device_post_asic_reset(struct amdgpu_device *adev)
>>>>>> if (!ring || !ring->sched.thread)
>>>>>> continue;
>>>>>> - if (!adev->asic_reset_res)
>>>>>> + /* No point to resubmit jobs if we didn't HW reset*/
>>>>>> + if (!adev->asic_reset_res && !job_signaled)
>>>>>> drm_sched_resubmit_jobs(&ring->sched);
>>>>>> drm_sched_start(&ring->sched, !adev->asic_reset_res);
>>>>>> @@ -3518,14 +3533,21 @@ static void
>>>>>> amdgpu_device_post_asic_reset(struct amdgpu_device *adev)
>>>>>> adev->asic_reset_res = 0;
>>>>>> }
>>>>>> -static void amdgpu_device_lock_adev(struct amdgpu_device *adev)
>>>>>> +static bool amdgpu_device_lock_adev(struct amdgpu_device *adev,
>>>>>> bool
>>>>>> trylock)
>>>>>> {
>>>>>> - mutex_lock(&adev->lock_reset);
>>>>>> + if (trylock) {
>>>>>> + if (!mutex_trylock(&adev->lock_reset))
>>>>>> + return false;
>>>>>> + } else
>>>>>> + mutex_lock(&adev->lock_reset);
>>>>>> +
>>>>>> atomic_inc(&adev->gpu_reset_counter);
>>>>>> adev->in_gpu_reset = 1;
>>>>>> /* Block kfd: SRIOV would do it separately */
>>>>>> if (!amdgpu_sriov_vf(adev))
>>>>>> amdgpu_amdkfd_pre_reset(adev);
>>>>>> +
>>>>>> + return true;
>>>>>> }
>>>>>> static void amdgpu_device_unlock_adev(struct amdgpu_device
>>>>>> *adev)
>>>>>> @@ -3555,29 +3577,44 @@ int amdgpu_device_gpu_recover(struct
>>>>>> amdgpu_device *adev,
>>>>>> {
>>>>>> int r;
>>>>>> struct amdgpu_hive_info *hive = NULL;
>>>>>> - bool need_full_reset = false;
>>>>>> struct amdgpu_device *tmp_adev = NULL;
>>>>>> struct list_head device_list, *device_list_handle = NULL;
>>>>>> + bool xgmi_topology_present, need_full_reset, job_signaled;
>>>>>> + need_full_reset = job_signaled = false;
>>>>>> INIT_LIST_HEAD(&device_list);
>>>>>> dev_info(adev->dev, "GPU reset begin!\n");
>>>>>> + hive = amdgpu_get_xgmi_hive(adev, 0);
>>>>>> + xgmi_topology_present = hive &&
>>>>>> adev->gmc.xgmi.num_physical_nodes > 1;
>>>>>> +
>>>>>> /*
>>>>>> - * In case of XGMI hive disallow concurrent resets to be
>>>>>> triggered
>>>>>> - * by different nodes. No point also since the one node already
>>>>>> executing
>>>>>> - * reset will also reset all the other nodes in the hive.
>>>>>> + * Here we trylock to avoid chain of resets executing from
>>>>>> + * either trigger by jobs on different adevs in XGMI hive or
>>>>>> jobs on
>>>>>> + * different schedulers for same device while this tdr is
>>>>>> running.
>>>>>> + * We always reset all schedulers for device and all devices
>>>>>> for
>>>>>> XGMI
>>>>>> + * hive so that should take care of them too.
>>>>>> */
>>>>>> - hive = amdgpu_get_xgmi_hive(adev, 0);
>>>>>> - if (hive && adev->gmc.xgmi.num_physical_nodes > 1 &&
>>>>>> - !mutex_trylock(&hive->reset_lock))
>>>>>> +
>>>>>> + if (xgmi_topology_present &&
>>>>>> !mutex_trylock(&hive->reset_lock)) {
>>>>>> + DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as
>>>>>> another already in progress",
>>>>>> + job->base.id, hive->hive_id);
>>>>>> return 0;
>>>>>> + }
>>>>>> /* Start with adev pre asic reset first for soft reset
>>>>>> check.*/
>>>>>> - amdgpu_device_lock_adev(adev);
>>>>>> + if (!amdgpu_device_lock_adev(adev, !xgmi_topology_present)) {
>>>>>> + DRM_INFO("Bailing on TDR for s_job:%llx, as another already
>>>>>> in progress",
>>>>>> + job->base.id);
>>>>>> + return 0;
>>>>>> + }
>>>>>> +
>>>>>> + /* Guilty job will be freed after this*/
>>>>>> r = amdgpu_device_pre_asic_reset(adev,
>>>>>> job,
>>>>>> - &need_full_reset);
>>>>>> + &need_full_reset,
>>>>>> + &job_signaled);
>>>>>> if (r) {
>>>>>> /*TODO Should we stop ?*/
>>>>>> DRM_ERROR("GPU pre asic reset failed with err, %d for
>>>>>> drm
>>>>>> dev, %s ",
>>>>>> @@ -3609,10 +3646,11 @@ int amdgpu_device_gpu_recover(struct
>>>>>> amdgpu_device *adev,
>>>>>> if (tmp_adev == adev)
>>>>>> continue;
>>>>>> - amdgpu_device_lock_adev(tmp_adev);
>>>>>> + amdgpu_device_lock_adev(tmp_adev, false);
>>>>>> r = amdgpu_device_pre_asic_reset(tmp_adev,
>>>>>> NULL,
>>>>>> - &need_full_reset);
>>>>>> + &need_full_reset,
>>>>>> + &job_signaled);
>>>>>> /*TODO Should we stop ?*/
>>>>>> if (r) {
>>>>>> DRM_ERROR("GPU pre asic reset failed with err, %d
>>>>>> for
>>>>>> drm dev, %s ",
>>>>>> @@ -3623,19 +3661,21 @@ int amdgpu_device_gpu_recover(struct
>>>>>> amdgpu_device *adev,
>>>>>> /* Actual ASIC resets if needed.*/
>>>>>> /* TODO Implement XGMI hive reset logic for SRIOV */
>>>>>> - if (amdgpu_sriov_vf(adev)) {
>>>>>> - r = amdgpu_device_reset_sriov(adev, job ? false : true);
>>>>>> - if (r)
>>>>>> - adev->asic_reset_res = r;
>>>>>> - } else {
>>>>>> - r = amdgpu_do_asic_reset(hive, device_list_handle,
>>>>>> &need_full_reset);
>>>>>> - if (r && r == -EAGAIN)
>>>>>> - goto retry;
>>>>>> + if (!job || !job_signaled) {
>>>>>> + if (amdgpu_sriov_vf(adev)) {
>>>>>> + r = amdgpu_device_reset_sriov(adev, job ? false :
>>>>>> true);
>>>>>> + if (r)
>>>>>> + adev->asic_reset_res = r;
>>>>>> + } else {
>>>>>> + r = amdgpu_do_asic_reset(hive, device_list_handle,
>>>>>> &need_full_reset);
>>>>>> + if (r && r == -EAGAIN)
>>>>>> + goto retry;
>>>>>> + }
>>>>>> }
>>>>>> /* Post ASIC reset for all devs .*/
>>>>>> list_for_each_entry(tmp_adev, device_list_handle,
>>>>>> gmc.xgmi.head) {
>>>>>> - amdgpu_device_post_asic_reset(tmp_adev);
>>>>>> + amdgpu_device_post_asic_reset(tmp_adev, job_signaled);
>>>>>> if (r) {
>>>>>> /* bad news, how to tell it to userspace ? */
>>>>>> @@ -3648,7 +3688,7 @@ int amdgpu_device_gpu_recover(struct
>>>>>> amdgpu_device *adev,
>>>>>> amdgpu_device_unlock_adev(tmp_adev);
>>>>>> }
>>>>>> - if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
>>>>>> + if (xgmi_topology_present)
>>>>>> mutex_unlock(&hive->reset_lock);
>>>>>> if (r)
>>>> _______________________________________________
>>>> 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
>
More information about the dri-devel
mailing list