From: Asahi Lina <lina@xxxxxxxxxxxxx> Allow a GEM object to share another object's DMA reservation, for use with drm_gpuvm. To keep memory safety, we hold a reference to the GEM object owning the resv, and drop it when the child object is freed. Signed-off-by: Asahi Lina <lina@xxxxxxxxxxxxx> Signed-off-by: Daniel Almeida <daniel.almeida@xxxxxxxxxxxxx> --- rust/kernel/drm/gem/shmem.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index fdf7dd7f2408bd2857f5b72027ef48e29c9dd9e3..e026b26a4895daea0534b93296da9a33683aa432 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -17,7 +17,7 @@ slice, }; -use gem::BaseObject; +use gem::{BaseObject, IntoGEMObject}; /// Trait which must be implemented by drivers using shmem-backed GEM objects. pub trait DriverObject: gem::BaseDriverObject<Object<Self>> { @@ -72,6 +72,8 @@ pub struct Object<T: DriverObject> { // The DRM core ensures the Device exists as long as its objects exist, so we don't need to // manage the reference count here. dev: *const bindings::drm_device, + // Parent object that owns this object's DMA reservation object + parent_resv_obj: *const bindings::drm_gem_object, #[pin] inner: T, } @@ -101,6 +103,7 @@ unsafe impl init::Zeroable for bindings::drm_gem_shmem_object {} // SAFETY: GEM ensures the device lives as long as its objects live inner <- T::new(unsafe { device::Device::borrow(dev)}, size), dev, + parent_resv_obj: core::ptr::null(), }); // SAFETY: p is a valid pointer to an uninitialized Object<T>. @@ -135,6 +138,15 @@ unsafe impl init::Zeroable for bindings::drm_gem_shmem_object {} core::ptr::drop_in_place(&mut (*p).inner); } + // SAFETY: parent_resv_obj is either NULL or a valid reference to the + // GEM object owning the DMA reservation for this object, which we drop + // here. + unsafe { + if !(*p).parent_resv_obj.is_null() { + bindings::drm_gem_object_put((*p).parent_resv_obj as *const _ as *mut _); + } + } + // SAFETY: This pointer has to be valid, since p is valid unsafe { bindings::drm_gem_shmem_free(&mut (*p).obj); @@ -236,6 +248,25 @@ pub fn vmap(&self) -> Result<VMap<T>> { pub fn set_wc(&mut self, map_wc: bool) { self.obj.set_map_wc(map_wc); } + + /// Share the dma_resv object from another GEM object. + /// + /// Should be called before the object is used/shared. Can only be called once. + pub fn share_dma_resv(&mut self, from_object: &impl IntoGEMObject) -> Result { + let from_obj = from_object.gem_obj(); + if !self.parent_resv_obj.is_null() { + Err(EBUSY) + } else { + // SAFETY: from_obj is a valid object pointer per the trait Invariant. + unsafe { + bindings::drm_gem_object_get(from_obj as *const _ as *mut _); + } + self.parent_resv_obj = from_obj; + let gem = self.mut_gem_obj(); + gem.resv = from_obj.resv; + Ok(()) + } + } } impl<T: DriverObject> Deref for Object<T> { -- 2.48.1