From 2b14d6de45dca21f9ad00065edcf40e69d24011f Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 25 Jan 2025 05:50:58 +0900 Subject: [PATCH] drm/asahi: workqueue: Defer freeing the last completed work item Maybe helps with firmware crashes? Signed-off-by: Asahi Lina (cherry picked from commit 855c62f853cb3a3b50dd4e48d46e2c8663afe7d5) Adaptation: use this tree's workqueue::system_dfl() API in both cleanup enqueue sites, matching the existing workqueue call. Assisted-by: LLM Signed-off-by: Ryan Murray --- drivers/gpu/drm/asahi/workqueue.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/asahi/workqueue.rs b/drivers/gpu/drm/asahi/workqueue.rs index 6281ef684e251..c42d467b9a61e 100644 --- a/drivers/gpu/drm/asahi/workqueue.rs +++ b/drivers/gpu/drm/asahi/workqueue.rs @@ -243,6 +243,7 @@ struct WorkQueueInner { size: u32, wptr: u32, pending: KVec>>, + last_completed_work: Option>>, last_token: Option, pending_jobs: usize, last_submitted: Option, @@ -740,6 +741,7 @@ impl WorkQueue::ver { size, wptr: 0, pending: KVec::new(), + last_completed_work: None, last_token: None, event: None, priority, @@ -933,6 +935,8 @@ impl WorkQueue for WorkQueue::ver { let last_wptr = inner.pending[completed_commands - 1].inner.wptr(); let pipe_type = inner.pipe_type; + let mut last_cmd = inner.last_completed_work.take(); + for mut cmd in inner.pending.drain(..completed_commands) { mod_pr_debug!( "WorkQueue({:?}): Queueing command @ {:?} for cleanup\n", @@ -940,9 +944,13 @@ impl WorkQueue for WorkQueue::ver { cmd.inner.gpu_va() ); cmd.as_mut().inner_mut().complete(); - workqueue::system_dfl().enqueue(cmd); + if let Some(last_cmd) = last_cmd.replace(cmd) { + workqueue::system_dfl().enqueue(last_cmd); + } } + inner.last_completed_work = last_cmd; + mod_pr_debug!( "WorkQueue({:?}): Completed {} commands, left pending {}, ls {:#x?}, lc {:#x?}\n", inner.pipe_type, @@ -1039,3 +1047,12 @@ impl WorkQueue for WorkQueue::ver { } } } + +#[versions(AGX)] +impl Drop for WorkQueueInner::ver { + fn drop(&mut self) { + if let Some(last_cmd) = self.last_completed_work.take() { + workqueue::system_dfl().enqueue(last_cmd); + } + } +}