Skip to content

Commit 22685d8

Browse files
hoshinolinajannau
authored andcommitted
drm/asahi: Add robust_isolation kernel parameter
This only allows binding one VM context at once, which serializes GPU usage between VMs and therefore prevents one faulting VM from affecting others. Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent a062c37 commit 22685d8

3 files changed

Lines changed: 45 additions & 13 deletions

File tree

drivers/gpu/drm/asahi/asahi.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,10 @@ kernel::module_platform_driver! {
4646
permissions: 0o644,
4747
description: "Initial TVB size in blocks",
4848
},
49+
robust_isolation: bool {
50+
default: false,
51+
permissions: 0o644,
52+
description: "Fully isolate GPU contexts (limits performance)",
53+
},
4954
},
5055
}

drivers/gpu/drm/asahi/mmu.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
use core::fmt::Debug;
1414
use core::mem::size_of;
15+
use core::num::NonZeroUsize;
1516
use core::ops::Range;
1617
use core::ptr::NonNull;
1718
use core::sync::atomic::{fence, AtomicU32, AtomicU64, AtomicU8, Ordering};
@@ -1463,6 +1464,17 @@ impl Uat {
14631464
if binding.binding.is_none() {
14641465
assert_eq!(binding.active_users, 0);
14651466

1467+
let isolation = {
1468+
let lock = crate::THIS_MODULE.kernel_param_lock();
1469+
*crate::robust_isolation.read(&lock)
1470+
};
1471+
1472+
self.slots.set_limit(if isolation {
1473+
NonZeroUsize::new(1)
1474+
} else {
1475+
None
1476+
});
1477+
14661478
let slot = self.slots.get(binding.bind_token)?;
14671479
if slot.changed() {
14681480
mod_pr_debug!("Vm Bind [{}]: bind_token={:?}\n", vm.id, slot.token(),);

drivers/gpu/drm/asahi/slotalloc.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! of serious system contention most allocation requests will be immediately fulfilled from the
1616
//! previous slot without doing an LRU scan.
1717
18+
use core::num::NonZeroUsize;
1819
use core::ops::{Deref, DerefMut};
1920
use kernel::{
2021
error::{code::*, Result},
@@ -107,6 +108,7 @@ struct SlotAllocatorInner<T: SlotItem> {
107108
slots: KVec<Option<Entry<T>>>,
108109
get_count: u64,
109110
drop_count: u64,
111+
slot_limit: usize,
110112
}
111113

112114
/// A single slot allocator instance.
@@ -155,6 +157,7 @@ impl<T: SlotItem> SlotAllocator<T> {
155157
slots,
156158
get_count: 0,
157159
drop_count: 0,
160+
slot_limit: usize::MAX,
158161
};
159162

160163
let alloc = Arc::pin_init(
@@ -176,6 +179,13 @@ impl<T: SlotItem> SlotAllocator<T> {
176179
cb(&mut inner.data)
177180
}
178181

182+
/// Set the slot limit for this allocator. New bindings will not use slots above
183+
/// this threshold.
184+
pub(crate) fn set_limit(&self, limit: Option<NonZeroUsize>) {
185+
let mut inner = self.0.inner.lock();
186+
inner.slot_limit = limit.unwrap_or(NonZeroUsize::MAX).get();
187+
}
188+
179189
/// Gets a fresh slot, optionally reusing a previous allocation if a `SlotToken` is provided.
180190
///
181191
/// Blocks if no slots are free.
@@ -199,18 +209,20 @@ impl<T: SlotItem> SlotAllocator<T> {
199209
let mut inner = self.0.inner.lock();
200210

201211
if let Some(token) = token {
202-
let slot = &mut inner.slots[token.slot as usize];
203-
if slot.is_some() {
204-
let count = slot.as_ref().unwrap().get_time;
205-
if count == token.time {
206-
let mut guard = Guard {
207-
item: Some(slot.take().unwrap().item),
208-
token,
209-
changed: false,
210-
alloc: self.0.clone(),
211-
};
212-
cb(&mut inner.data, &mut guard)?;
213-
return Ok(guard);
212+
if (token.slot as usize) < inner.slot_limit {
213+
let slot = &mut inner.slots[token.slot as usize];
214+
if slot.is_some() {
215+
let count = slot.as_ref().unwrap().get_time;
216+
if count == token.time {
217+
let mut guard = Guard {
218+
item: Some(slot.take().unwrap().item),
219+
token,
220+
changed: false,
221+
alloc: self.0.clone(),
222+
};
223+
cb(&mut inner.data, &mut guard)?;
224+
return Ok(guard);
225+
}
214226
}
215227
}
216228
}
@@ -221,6 +233,9 @@ impl<T: SlotItem> SlotAllocator<T> {
221233
let mut oldest_slot = 0u32;
222234

223235
for (i, slot) in inner.slots.iter().enumerate() {
236+
if i >= inner.slot_limit {
237+
break;
238+
}
224239
if let Some(slot) = slot.as_ref() {
225240
if slot.drop_time < oldest_time {
226241
oldest_slot = i as u32;
@@ -230,7 +245,7 @@ impl<T: SlotItem> SlotAllocator<T> {
230245
}
231246

232247
if oldest_time == u64::MAX {
233-
if first {
248+
if first && inner.slot_limit == usize::MAX {
234249
pr_warn!(
235250
"{}: out of slots, blocking\n",
236251
core::any::type_name::<Self>()

0 commit comments

Comments
 (0)