diff --git a/drivers/gpu/drm/asahi/g17/queue/compute.rs b/drivers/gpu/drm/asahi/g17/queue/compute.rs index 9c4c5c92d049d..b4edec4a7b6c0 100644 --- a/drivers/gpu/drm/asahi/g17/queue/compute.rs +++ b/drivers/gpu/drm/asahi/g17/queue/compute.rs @@ -594,8 +594,9 @@ pub(crate) struct Queue { source_readers: Arc, source_hint: crate::g17::sync_input::ReaderHint, /// The doorbell withheld from publications that had [`WITHHOLD_DEPTH`] - 1 or more - /// unretired commands of this queue ahead of them, the publication of the first, and the - /// compute work slots written at its priority once its slot was. + /// unretired commands of this queue ahead of them, the publication of the first of them + /// that no doorbell has announced, and the compute work slots written at its priority once + /// the last one's slot was. withheld_doorbell: Option<(u64, u64, u64)>, } @@ -628,7 +629,10 @@ impl Queue { } /// The queue has left ordinary retirement: a timeout, kill, quarantine, replay, recovery - /// witness or exit is in progress. + /// witness or exit is in progress, or retirement stopped at a command the firmware + /// finished without a completion record. A front whose record has arrived and that only + /// waits for its stamp is ordinary retirement: [`Self::due_doorbell`] counts it as + /// finished, and ringing at once there rang most withheld doorbells early. fn settling(&self) -> bool { self.quarantined || self.released @@ -636,7 +640,8 @@ impl Queue { || self.replays.len != 0 || self.replay_retirement || self.awaiting_witness - || self.retire_pending + || (self.retire_pending + && self.active.front().is_none_or(|active| active.observed.is_none())) || self.retired_by_teardown || self.spared_quarantine || self.failure_status_pending @@ -1952,6 +1957,8 @@ pub(crate) trait Host { -> Result; fn notify_compute(&mut self, priority: u8, message: u64) -> Result; fn compute_written(&self, priority: u8) -> u64; + /// Compute work slots at `priority` that a doorbell has announced. + fn compute_announced(&self, priority: u8) -> u64; fn note_submission(&mut self) -> Result; } @@ -2303,6 +2310,15 @@ impl Queue { && self.withheld_doorbell.is_none_or(|(withheld, _, _)| withheld == doorbell) { let written = host.compute_written(policy.priority()); + // Once another doorbell announced every slot the withheld one covered, it + // starts over from this publication: it then waits for this command's own + // predecessors rather than for those of slots already announced. + if self + .withheld_doorbell + .is_some_and(|(_, _, last)| host.compute_announced(policy.priority()) >= last) + { + self.withheld_doorbell = None; + } let entry = self.withheld_doorbell.get_or_insert((doorbell, published, written)); entry.2 = written; } else { diff --git a/drivers/gpu/drm/asahi/g17/runtime.rs b/drivers/gpu/drm/asahi/g17/runtime.rs index e04295d576606..bf9399cd87e73 100644 --- a/drivers/gpu/drm/asahi/g17/runtime.rs +++ b/drivers/gpu/drm/asahi/g17/runtime.rs @@ -1396,6 +1396,9 @@ impl compute::Host for ComputeHost<'_> { fn compute_written(&self, priority: u8) -> u64 { self.port.compute_written(priority) } + fn compute_announced(&self, priority: u8) -> u64 { + self.port.compute_announced(priority) + } fn note_submission(&mut self) -> Result { self.effort.submit(); super::Firmware::apply_shared_effort(self.init, self.effort, self.port, super::power::FULL_EFFORT) @@ -1443,6 +1446,9 @@ impl compute::Host for DirectHost<'_> { fn compute_written(&self, priority: u8) -> u64 { self.port.compute_written(priority) } + fn compute_announced(&self, priority: u8) -> u64 { + self.port.compute_announced(priority) + } fn note_submission(&mut self) -> Result { Ok(()) }