mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
drm/amdgpu/gfx: defer per-queue helper_end until after MES resume
amdgpu_gfx_reset_mes_compute() runs amdgpu_mes_suspend(adev, 0) to quiesce all gangs, resets the offending queue(s), then resumes. The existing amdgpu_gfx_mes_reset_queue() called amdgpu_ring_reset_helper_end() right after unmap/restore/map of the reset queue, which re-emits backed-up commands and rings the doorbell. That doorbell hits a still-suspended CP: on the subsequent resume the queue partially wedges -- the first new IB after the reset may execute but later submissions stall, which surfaces as repeated timeouts on the same ring under concurrent workloads. Split out amdgpu_gfx_mes_reset_queue_start() (backup + MES reset + unmap/restore/map only) and defer helper_end. amdgpu_gfx_reset_mes_compute() collects the (ring, fence) pair for every queue it resets and runs helper_end on each after amdgpu_mes_resume(), so the re-emit doorbells land on a running CP. amdgpu_gfx_reset_mes_kcq() now reports the matched ring/fence back to the caller for the same reason. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Jesse Zhang <jesse.zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
bb2baf1dc9
commit
a4e4d945cb
|
|
@ -1989,10 +1989,10 @@ static ssize_t amdgpu_gfx_get_compute_reset_mask(struct device *dev,
|
||||||
return amdgpu_show_reset_mask(buf, adev->gfx.compute_supported_reset);
|
return amdgpu_show_reset_mask(buf, adev->gfx.compute_supported_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring,
|
static int amdgpu_gfx_mes_reset_queue_start(struct amdgpu_ring *ring,
|
||||||
unsigned int vmid,
|
unsigned int vmid,
|
||||||
struct amdgpu_fence *timedout_fence,
|
struct amdgpu_fence *timedout_fence,
|
||||||
bool use_mmio)
|
bool use_mmio)
|
||||||
{
|
{
|
||||||
struct amdgpu_device *adev = ring->adev;
|
struct amdgpu_device *adev = ring->adev;
|
||||||
bool reinit_queue;
|
bool reinit_queue;
|
||||||
|
|
@ -2026,7 +2026,20 @@ int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring,
|
||||||
|
unsigned int vmid,
|
||||||
|
struct amdgpu_fence *timedout_fence,
|
||||||
|
bool use_mmio)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = amdgpu_gfx_mes_reset_queue_start(ring, vmid, timedout_fence,
|
||||||
|
use_mmio);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2216,24 +2229,37 @@ static void amdgpu_gfx_reset_stop_compute_scheds(struct amdgpu_device *adev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match the MES-reported hung doorbell against a compute ring and run
|
||||||
|
* the reset. On hit, the matched ring and its guilty fence are returned
|
||||||
|
* via *out_ring / *out_fence so the caller can defer reset end until
|
||||||
|
* after MES has resumed all gangs.
|
||||||
|
*/
|
||||||
static int amdgpu_gfx_reset_mes_kcq(struct amdgpu_device *adev,
|
static int amdgpu_gfx_reset_mes_kcq(struct amdgpu_device *adev,
|
||||||
struct amdgpu_ring *guilty_ring,
|
struct amdgpu_ring *guilty_ring,
|
||||||
unsigned int db)
|
unsigned int db,
|
||||||
|
struct amdgpu_ring **out_ring,
|
||||||
|
struct amdgpu_fence **out_fence)
|
||||||
{
|
{
|
||||||
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
|
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
|
||||||
struct amdgpu_fence *fence;
|
struct amdgpu_fence *fence;
|
||||||
struct amdgpu_ring *ring;
|
struct amdgpu_ring *ring;
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
|
*out_ring = NULL;
|
||||||
|
*out_fence = NULL;
|
||||||
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
|
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
|
||||||
ring = &adev->gfx.compute_ring[i];
|
ring = &adev->gfx.compute_ring[i];
|
||||||
if (ring == guilty_ring)
|
if (ring == guilty_ring)
|
||||||
continue;
|
continue;
|
||||||
if (ring->doorbell_index == db) {
|
if (ring->doorbell_index == db) {
|
||||||
fence = amdgpu_ring_find_guilty_fence(ring);
|
fence = amdgpu_ring_find_guilty_fence(ring);
|
||||||
r = amdgpu_gfx_mes_reset_queue(ring, 0, fence, use_mmio);
|
r = amdgpu_gfx_mes_reset_queue_start(ring, 0, fence,
|
||||||
|
use_mmio);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
*out_ring = ring;
|
||||||
|
*out_fence = fence;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2254,6 +2280,8 @@ int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev,
|
||||||
unsigned int num_hung = 0;
|
unsigned int num_hung = 0;
|
||||||
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
|
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
|
||||||
struct mes_remove_queue_input *queue_input = (struct mes_remove_queue_input *)faulty_queue_input;
|
struct mes_remove_queue_input *queue_input = (struct mes_remove_queue_input *)faulty_queue_input;
|
||||||
|
struct amdgpu_gfx_deferred_entry deferred_end[AMDGPU_MAX_COMPUTE_RINGS + 1];
|
||||||
|
int n_deferred = 0;
|
||||||
|
|
||||||
guard(mutex)(&adev->gfx.mec.reset_mutex);
|
guard(mutex)(&adev->gfx.mec.reset_mutex);
|
||||||
/* stop the drm schedulers for all compute queues */
|
/* stop the drm schedulers for all compute queues */
|
||||||
|
|
@ -2278,9 +2306,13 @@ int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev,
|
||||||
fence_reset:
|
fence_reset:
|
||||||
/* reset the queue this came from if specified */
|
/* reset the queue this came from if specified */
|
||||||
if (ring) {
|
if (ring) {
|
||||||
r = amdgpu_gfx_mes_reset_queue(ring, 0, guilty_fence, use_mmio);
|
r = amdgpu_gfx_mes_reset_queue_start(ring, 0, guilty_fence,
|
||||||
|
use_mmio);
|
||||||
if (r)
|
if (r)
|
||||||
goto out;
|
goto out;
|
||||||
|
deferred_end[n_deferred].ring = ring;
|
||||||
|
deferred_end[n_deferred].fence = guilty_fence;
|
||||||
|
n_deferred++;
|
||||||
}
|
}
|
||||||
if (uq) {
|
if (uq) {
|
||||||
r = mes_userq_reset(uq);
|
r = mes_userq_reset(uq);
|
||||||
|
|
@ -2288,15 +2320,24 @@ int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
for (i = 0; i < num_hung; i++) {
|
for (i = 0; i < num_hung; i++) {
|
||||||
|
struct amdgpu_ring *hr = NULL;
|
||||||
|
struct amdgpu_fence *hf = NULL;
|
||||||
|
|
||||||
pipe = hqd_info[i].pipe_index;
|
pipe = hqd_info[i].pipe_index;
|
||||||
queue = hqd_info[i].queue_index;
|
queue = hqd_info[i].queue_index;
|
||||||
queue_type = hqd_info[i].queue_type;
|
queue_type = hqd_info[i].queue_type;
|
||||||
|
|
||||||
/* reset any KCQs */
|
/* reset any KCQs */
|
||||||
r = amdgpu_gfx_reset_mes_kcq(adev, ring,
|
r = amdgpu_gfx_reset_mes_kcq(adev, ring,
|
||||||
adev->gfx.mec.mes_hung_db_array[i]);
|
adev->gfx.mec.mes_hung_db_array[i],
|
||||||
|
&hr, &hf);
|
||||||
if (r)
|
if (r)
|
||||||
goto out;
|
goto out;
|
||||||
|
if (hr) {
|
||||||
|
deferred_end[n_deferred].ring = hr;
|
||||||
|
deferred_end[n_deferred].fence = hf;
|
||||||
|
n_deferred++;
|
||||||
|
}
|
||||||
/* reset any KFD queues */
|
/* reset any KFD queues */
|
||||||
r = amdgpu_amdkfd_reset_mes_queue(adev, 0, queue_type, pipe, queue,
|
r = amdgpu_amdkfd_reset_mes_queue(adev, 0, queue_type, pipe, queue,
|
||||||
adev->gfx.mec.mes_hung_db_array[i]);
|
adev->gfx.mec.mes_hung_db_array[i]);
|
||||||
|
|
@ -2325,6 +2366,17 @@ int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev,
|
||||||
out:
|
out:
|
||||||
/* resume all will enable the non-hung queues */
|
/* resume all will enable the non-hung queues */
|
||||||
amdgpu_mes_resume(adev, 0);
|
amdgpu_mes_resume(adev, 0);
|
||||||
|
|
||||||
|
/* Now CP is running again — replay backed-up commands and ring
|
||||||
|
* doorbells on each reset queue.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < n_deferred; i++) {
|
||||||
|
int er = amdgpu_ring_reset_helper_end(deferred_end[i].ring,
|
||||||
|
deferred_end[i].fence);
|
||||||
|
if (er && !r)
|
||||||
|
r = er;
|
||||||
|
}
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
amdgpu_gfx_reset_start_compute_scheds(adev, ring);
|
amdgpu_gfx_reset_start_compute_scheds(adev, ring);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -549,6 +549,11 @@ struct amdgpu_gfx {
|
||||||
bool disable_uq;
|
bool disable_uq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct amdgpu_gfx_deferred_entry {
|
||||||
|
struct amdgpu_ring *ring;
|
||||||
|
struct amdgpu_fence *fence;
|
||||||
|
};
|
||||||
|
|
||||||
struct amdgpu_gfx_ras_reg_entry {
|
struct amdgpu_gfx_ras_reg_entry {
|
||||||
struct amdgpu_ras_err_status_reg_entry reg_entry;
|
struct amdgpu_ras_err_status_reg_entry reg_entry;
|
||||||
enum amdgpu_gfx_ras_mem_id_type mem_id_type;
|
enum amdgpu_gfx_ras_mem_id_type mem_id_type;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user