Skip to content

Commit ed4a812

Browse files
committed
rust: drm: gpuvm: Switch to DRM_GPUVM_IMMEDIATE_MODE
DRM_GPUVM_IMMEDIATE_MODE allows for deferred gpuva unlink and gpuvm bo release. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 400ce61 commit ed4a812

2 files changed

Lines changed: 98 additions & 7 deletions

File tree

rust/helpers/drm_gpuvm.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ struct drm_gpuvm_bo *rust_helper_drm_gpuvm_bo_get(struct drm_gpuvm_bo *vm_bo)
2525
return drm_gpuvm_bo_get(vm_bo);
2626
}
2727

28+
bool rust_helper_drm_gpuvm_immediate_mode(struct drm_gpuvm *gpuvm)
29+
{
30+
return drm_gpuvm_immediate_mode(gpuvm);
31+
}
32+
2833
bool rust_helper_drm_gpuvm_is_extobj(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj)
2934
{
3035
return drm_gpuvm_is_extobj(gpuvm, obj);

rust/kernel/drm/gpuvm.rs

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
use crate::{
1010
bindings, drm,
11-
drm::device,
11+
drm::{device, gem::BaseObject},
1212
error::{
1313
code::{EINVAL, ENOMEM},
1414
from_result, to_result, Error, Result,
@@ -177,7 +177,9 @@ impl<T: DriverGpuVm> OpMap<T> {
177177
return Err(Pin::new_unchecked(KBox::from_raw(p)));
178178
};
179179
// SAFETY: This takes a new reference to the gpuvmbo.
180+
gpuvmbo.lock_gpuva();
180181
bindings::drm_gpuva_link(&mut p.gpuva, &gpuvmbo.bo as *const _ as *mut _);
182+
gpuvmbo.unlock_gpuva();
181183
}
182184
Ok(())
183185
}
@@ -194,6 +196,12 @@ impl<T: DriverGpuVm> OpUnMap<T> {
194196
Some(unsafe { &*p })
195197
}
196198
pub fn unmap_and_unlink_va(&mut self) -> Option<Pin<KBox<GpuVa<T>>>> {
199+
self.do_unmap_and_unlink_va(false)
200+
}
201+
pub fn unmap_and_unlink_va_defer(&mut self) -> Option<Pin<KBox<GpuVa<T>>>> {
202+
self.do_unmap_and_unlink_va(true)
203+
}
204+
fn do_unmap_and_unlink_va(&mut self, defer: bool) -> Option<Pin<KBox<GpuVa<T>>>> {
197205
if self.0.va.is_null() {
198206
return None;
199207
}
@@ -203,7 +211,11 @@ impl<T: DriverGpuVm> OpUnMap<T> {
203211
// SAFETY: The GpuVa object reference is valid per the op_unmap contract
204212
unsafe {
205213
bindings::drm_gpuva_unmap(&mut self.0);
206-
bindings::drm_gpuva_unlink(self.0.va);
214+
if defer {
215+
bindings::drm_gpuva_unlink_defer(self.0.va);
216+
} else {
217+
bindings::drm_gpuva_unlink(self.0.va);
218+
}
207219
}
208220

209221
// Unlinking/unmapping relinquishes ownership of the GpuVa object,
@@ -287,6 +299,20 @@ impl<T: DriverGpuVm> GpuVmBo<T> {
287299
pub fn inner(&self) -> &T::GpuVmBo {
288300
&self.inner
289301
}
302+
/// Lock the GpuVmBo's gem boject gpuva lock
303+
pub fn lock_gpuva(&self) {
304+
unsafe {
305+
let lock = &raw mut (*self.bo.obj).gpuva.lock;
306+
bindings::mutex_lock(lock);
307+
}
308+
}
309+
/// Unlock the GpuVmBo's gem boject gpuva lock
310+
pub fn unlock_gpuva(&self) {
311+
unsafe {
312+
let lock = &raw mut (*self.bo.obj).gpuva.lock;
313+
bindings::mutex_unlock(lock);
314+
}
315+
}
290316
}
291317

292318
// SAFETY: DRM GpuVmBo objects are always reference counted and the get/put functions
@@ -302,10 +328,9 @@ unsafe impl<T: DriverGpuVm> AlwaysRefCounted for GpuVmBo<T> {
302328
// The drm_gpuvm_put function satisfies the requirements for dec_ref().
303329
// (We do not support custom locks yet.)
304330
unsafe {
305-
let resv = (*obj.as_mut().bo.obj).resv;
306-
bindings::dma_resv_lock(resv, core::ptr::null_mut());
331+
obj.as_mut().lock_gpuva();
307332
bindings::drm_gpuvm_bo_put(&mut obj.as_mut().bo);
308-
bindings::dma_resv_unlock(resv);
333+
obj.as_mut().unlock_gpuva();
309334
}
310335
}
311336
}
@@ -414,7 +439,7 @@ pub(super) unsafe extern "C" fn step_remap_callback<T: DriverGpuVm>(
414439

415440
// SAFETY: We incremented the refcount above, and the Rust reference we took is
416441
// no longer in scope.
417-
unsafe { bindings::drm_gpuvm_bo_put(p_vm_bo) };
442+
unsafe { bindings::drm_gpuvm_bo_put_deferred(p_vm_bo) };
418443

419444
res
420445
}
@@ -461,6 +486,7 @@ impl<T: DriverGpuVm> GpuVm<T> {
461486

462487
pub fn new<E>(
463488
name: &'static CStr,
489+
flags: bindings::drm_gpuvm_flags,
464490
dev: &device::Device<T::Driver>,
465491
r_obj: ARef<<<T::Driver as drm::Driver>::Object as BaseDriverObject>::Object>,
466492
range: Range<u64>,
@@ -480,7 +506,7 @@ impl<T: DriverGpuVm> GpuVm<T> {
480506
bindings::drm_gpuvm_init(
481507
Opaque::cast_into(slot),
482508
name.as_char_ptr(),
483-
0,
509+
flags,
484510
dev.as_raw(),
485511
r_obj.as_raw() as *const _ as *mut _,
486512
range.start,
@@ -560,6 +586,66 @@ impl<T: DriverGpuVm> GpuVm<T> {
560586
// SAFETY: This is safe to call as long as the arguments are valid pointers.
561587
unsafe { bindings::drm_gpuvm_is_extobj(self.gpuvm() as *mut _, gem) }
562588
}
589+
590+
pub fn bo_deferred_cleanup(&self) {
591+
unsafe { bindings::drm_gpuvm_bo_deferred_cleanup(self.gpuvm() as *mut _) }
592+
}
593+
594+
pub fn find_bo(& self,
595+
obj: &<<T::Driver as drm::Driver>::Object as BaseDriverObject>::Object
596+
) -> Option<ARef<GpuVmBo<T>>> {
597+
obj.lock_gpuva();
598+
// SAFETY: drm_gem_object.gpuva.lock was just locked.
599+
let p = unsafe {
600+
bindings::drm_gpuvm_bo_find(
601+
self.gpuvm() as *mut _,
602+
obj.as_raw() as *const _ as *mut _,
603+
)
604+
};
605+
obj.unlock_gpuva();
606+
if p.is_null() {
607+
None
608+
} else {
609+
// SAFETY: All the drm_gpuvm_bo objects in this GpuVm are always allocated by us as GpuVmBo<T>.
610+
let p = unsafe { crate::container_of!(p, GpuVmBo<T>, bo) as *mut GpuVmBo<T> };
611+
// SAFETY: We checked for NULL above, and the types ensure that
612+
// this object was created by vm_bo_alloc_callback<T>.
613+
Some(unsafe { ARef::from_raw(NonNull::new_unchecked(p)) })
614+
}
615+
}
616+
617+
pub fn obtain_bo(& self,
618+
obj: &<<T::Driver as drm::Driver>::Object as BaseDriverObject>::Object) -> Result<ARef<GpuVmBo<T>>> {
619+
obj.lock_gpuva();
620+
// SAFETY: drm_gem_object.gpuva.lock was just locked.
621+
let p = unsafe {
622+
bindings::drm_gpuvm_bo_obtain(
623+
self.gpuvm() as *mut _,
624+
obj.as_raw() as *const _ as *mut _,
625+
)
626+
};
627+
obj.unlock_gpuva();
628+
if p.is_null() {
629+
Err(ENOMEM)
630+
} else {
631+
// SAFETY: Container invariant is guaranteed for GpuVmBo objects for this GpuVm.
632+
let p = unsafe { crate::container_of!(p, GpuVmBo<T>, bo) as *mut GpuVmBo<T> };
633+
// SAFETY: We checked for NULL above, and the types ensure that
634+
// this object was created by vm_bo_alloc_callback<T>.
635+
Ok(unsafe { ARef::from_raw(NonNull::new_unchecked(p)) })
636+
}
637+
}
638+
639+
pub fn bo_unmap(& self, ctx: &mut T::StepContext, bo: &GpuVmBo<T>) -> Result {
640+
let mut ctx = StepContext {
641+
ctx,
642+
gpuvm: self,
643+
};
644+
// SAFETY: LockedGpuVm implies the right locks are held.
645+
to_result(unsafe {
646+
bindings::drm_gpuvm_bo_unmap(&bo.bo as *const _ as *mut _, &mut ctx as *mut _ as *mut _)
647+
})
648+
}
563649
}
564650

565651
// SAFETY: DRM GpuVm objects are always reference counted and the get/put functions

0 commit comments

Comments
 (0)