Skip to content

Commit fd7ebb2

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 eb6ed04 commit fd7ebb2

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
@@ -48,5 +48,10 @@ module_platform_driver! {
4848
permissions: 0o644,
4949
description: "Initial TVB size in blocks",
5050
},
51+
robust_isolation: bool {
52+
default: false,
53+
permissions: 0o644,
54+
description: "Fully isolate GPU contexts (limits performance)",
55+
},
5156
},
5257
}

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};
@@ -1459,6 +1460,17 @@ impl Uat {
14591460
if binding.binding.is_none() {
14601461
assert_eq!(binding.active_users, 0);
14611462

1463+
let isolation = {
1464+
let lock = crate::THIS_MODULE.kernel_param_lock();
1465+
*crate::robust_isolation.read(&lock)
1466+
};
1467+
1468+
self.slots.set_limit(if isolation {
1469+
NonZeroUsize::new(1)
1470+
} else {
1471+
None
1472+
});
1473+
14621474
let slot = self.slots.get(binding.bind_token)?;
14631475
if slot.changed() {
14641476
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
alloc::{flags::*, vec_ext::VecExt},
@@ -108,6 +109,7 @@ struct SlotAllocatorInner<T: SlotItem> {
108109
slots: Vec<Option<Entry<T>>>,
109110
get_count: u64,
110111
drop_count: u64,
112+
slot_limit: usize,
111113
}
112114

113115
/// A single slot allocator instance.
@@ -156,6 +158,7 @@ impl<T: SlotItem> SlotAllocator<T> {
156158
slots,
157159
get_count: 0,
158160
drop_count: 0,
161+
slot_limit: usize::MAX,
159162
};
160163

161164
let alloc = Arc::pin_init(
@@ -177,6 +180,13 @@ impl<T: SlotItem> SlotAllocator<T> {
177180
cb(&mut inner.data)
178181
}
179182

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

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

224236
for (i, slot) in inner.slots.iter().enumerate() {
237+
if i >= inner.slot_limit {
238+
break;
239+
}
225240
if let Some(slot) = slot.as_ref() {
226241
if slot.drop_time < oldest_time {
227242
oldest_slot = i as u32;
@@ -231,7 +246,7 @@ impl<T: SlotItem> SlotAllocator<T> {
231246
}
232247

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

0 commit comments

Comments
 (0)