Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions drivers/gpu/drm/asahi/g17/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ pub(crate) struct Context {
scheduler: Arc<KernelObject>,
scheduler_generation: u32,
published: AtomicBool,
/// A kill of this context was published, through a compute queue or on its render pairs'
/// behalf. A context is killed at most once.
kill_published: AtomicBool,
/// Advisory only: publication still checks the physical binding under the
/// device mutex. False skips an inline attempt known to need admission.
compute_binding_hint: AtomicBool,
Expand Down Expand Up @@ -197,6 +200,7 @@ impl Context {
scheduler,
scheduler_generation,
published: AtomicBool::new(false),
kill_published: AtomicBool::new(false),
compute_binding_hint: AtomicBool::new(false),
render_seen: AtomicBool::new(false),
qos,
Expand Down Expand Up @@ -316,6 +320,16 @@ impl Context {
Ok(head)
}

/// Record that a kill of this context was published (see `kill_published`).
pub(crate) fn note_kill_published(&self) {
self.kill_published.store(true, Ordering::Release);
}

/// A kill of this context was published.
pub(crate) fn kill_published(&self) -> bool {
self.kill_published.load(Ordering::Acquire)
}

pub(crate) fn is_published(&self) -> bool {
self.published.load(Ordering::Acquire)
}
Expand Down
35 changes: 29 additions & 6 deletions drivers/gpu/drm/asahi/g17/runtime/compute_exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ fn render_kill_target(listed: u128, own: u128) -> Option<u8> {
(candidates != 0).then(|| candidates.trailing_zeros() as u8)
}

/// A closed context may be killed on its render pairs' behalf once it has been closed for
/// [`RENDER_KILL_DELAY_NS`], it was never killed, a pair of it holds executed but unstamped
/// commands and no compute queue still runs it, switches away from it or killed it. A second kill
/// of a killed context made the firmware fault on the killed pair's own tiling queue within a
/// millisecond of acknowledging it: with the pair's release held back, a context killed through
/// its compute queue still looked like a render-only candidate.
fn render_kill_eligible(age: u64, killed: bool, executed: bool, compute_clear: bool) -> bool {
age >= RENDER_KILL_DELAY_NS && !killed && executed && compute_clear
}

/// The one admission owner of every pair a kill holds, if there is one.
fn hold_owner(owners: impl Iterator<Item = Option<u64>>) -> Option<u64> {
let mut owner = None;
Expand Down Expand Up @@ -296,6 +306,7 @@ impl Firmware {
PRESSED_KILL_NS.store(now.max(1), Ordering::Relaxed);
}
queue.record_exit(cookie, now);
context.note_kill_published();
crate::g17::trace::teardown(3, cookie, u64::from(context.id()), hold | u64::from(beside));
fence(Ordering::SeqCst);
if let Err(error) = queue.announce_exit(now, || self.primary.notify(MSG_CONTROL_NOTIFY)) {
Expand All @@ -315,12 +326,14 @@ impl Firmware {
/// yet those pairs are released only after one: without this the context, its pairs and
/// its memory stay until the processors stop.
fn render_kill_candidate(&self, index: usize, context: &Arc<Context>, age: u64) -> bool {
age >= RENDER_KILL_DELAY_NS
&& !self.queues.teardown.render_kill_published(index)
&& self.queues.render.executed_slots(context) != 0
&& self.queues.compute.iter().flatten().filter_map(|entry| entry.queue.as_deref()).all(|queue| {
render_kill_eligible(
age,
self.queues.teardown.render_kill_published(index) || context.kill_published(),
self.queues.render.executed_slots(context) != 0,
self.queues.compute.iter().flatten().filter_map(|entry| entry.queue.as_deref()).all(|queue| {
queue.idle_for_context(context) && !queue.switching_from(context) && !queue.exit_published(context)
})
}),
)
}

/// Kill a render-only candidate (`render_kill_candidate`). The rules of a failed
Expand Down Expand Up @@ -393,6 +406,7 @@ impl Firmware {
// Publication is irrevocable. The held pairs stay held until this context's
// scheduler release is consumed (`release_killed_slots` at detach).
self.queues.teardown.record_render_kill(index, cookie, now)?;
context.note_kill_published();
record_kill_wait(self.queues.teardown.take_kill_wait(index, now));
if beside {
*pressed = false;
Expand Down Expand Up @@ -491,7 +505,16 @@ impl Firmware {

#[kernel::macros::kunit_tests(asahi_g17_render_kill_target)]
mod render_kill_target_tests {
use super::{hold_owner, render_kill_target};
use super::{hold_owner, render_kill_eligible, render_kill_target, RENDER_KILL_DELAY_NS};

#[test]
fn a_killed_context_is_never_killed_again() {
assert!(render_kill_eligible(RENDER_KILL_DELAY_NS, false, true, true));
assert!(!render_kill_eligible(RENDER_KILL_DELAY_NS, true, true, true));
assert!(!render_kill_eligible(RENDER_KILL_DELAY_NS - 1, false, true, true));
assert!(!render_kill_eligible(RENDER_KILL_DELAY_NS, false, false, true));
assert!(!render_kill_eligible(RENDER_KILL_DELAY_NS, false, true, false));
}

#[test]
fn a_render_kill_holds_pairs_of_one_owner_only() {
Expand Down