disable_scheduling_deregister() waits for any pending scheduling operation to complete before destroying an exec queue.
For a disable completion, handle_sched_done() can wake the waiter before clearing pending_disable, or not wake it at all. The waiter can then miss a completed operation and expire after five seconds. This causes a spurious GT reset and immediate TDR. Clear pending_disable before waking the waitqueue on every completion path. Sample the destroyed state before clearing the pending state, as required by the existing destroy protocol. Also wake CT waiters after a suspend completion. The queue remains alive until deregistration completes, so waking waiters before sending the deregister request does not release it. Cc: Matthew Brost <[email protected]> Cc: Thomas Hellström <[email protected]> Cc: Himal Prasad Ghimiray <[email protected]> Cc: Rodrigo Vivi <[email protected]> Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Arvind Yadav <[email protected]> --- drivers/gpu/drm/xe/xe_guc_submit.c | 42 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index f3ba8abfc228..ca24a77dfb26 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -3265,26 +3265,32 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, if (q->guc->suspend_pending) { clear_exec_queue_pending_disable(q); suspend_fence_signal(q); + + /* + * Publish the cleared state before waking waiters. + */ + smp_wmb(); + wake_up_all(&guc->ct.wq); } else { - if (exec_queue_banned(q)) { - smp_wmb(); - wake_up_all(&guc->ct.wq); - } - if (exec_queue_destroyed(q)) { - /* - * Make sure to clear the pending_disable only - * after sampling the destroyed state. We want - * to ensure we don't trigger the unregister too - * early with something intending to only - * disable scheduling. The caller doing the - * destroy must wait for an ongoing - * pending_disable before marking as destroyed. - */ - clear_exec_queue_pending_disable(q); + bool destroyed = exec_queue_destroyed(q); + + /* + * Make sure to clear pending_disable only after sampling + * the destroyed state. The caller doing the destroy must + * wait for an ongoing disable before marking the queue + * destroyed. + */ + clear_exec_queue_pending_disable(q); + + /* + * Publish the cleared state before waking waiters. + */ + smp_wmb(); + wake_up_all(&guc->ct.wq); + + /* The queue remains alive until DEREGISTER_DONE. */ + if (destroyed) deregister_exec_queue(guc, q); - } else { - clear_exec_queue_pending_disable(q); - } } } } -- 2.43.0
