Hi Laura,

It’s been a while since I wrote this, and I now see this could use some
improvements.

I think the first problem is that this conflates "MappedBo" with "the MappedBo
backing the shared region". As soon as we try to add more users, this will be a
problem. I propose that we split this into two types that build upon each other:

a) a generic layer MappedBo, which remains roughly as-is:

gem.rs:

pub(crate) struct MappedBo<'drm> {
  vmap: shmem::VMapOwned<BoData>,
  bo: KernelBo<'drm>,
}

impl<'drm> MappedBo<'drm> {
  // pub(crate) API:

  // no Arc, McuMappedBo has to hold it by value, otherwise a second holder
  // could write around the claims.
  fn new(bo: KernelBo<'drm>) -> Result<Self>
  fn va_range(...) -> ...
  fn vmap(...) -> ...
}

impl Deref for MappedBo<'_> { type Target = Bo ... }


b) A MCU-specific BO type with the claims + offset logic:

fw/mcu_bo.rs:

pub(super) struct McuVa(...) + related McuVa impls.

#[pin_data]
pub(super) struct McuMappedBo<'drm> {
  bo: MappedBo<'drm>, // private, no accessor

  #[pin]
  claims: Mutex<KVec<Range<u64>>>
}

impl<'drm> McuMappedBo<'drm> {
  // pub super API

  // builds its own MappedBo, checks the 32-bit range before allocating and
  // copies the section data from the fw binary before any view can exist.
  new(ddev, mcu_vm: Arc<Vm<'drm>>, va: McuVa, size: u64, flags: VmMapFlags,
      data: &[u8]) -> Result<impl PinInit<Self,Error>> {...}

  // views borrow: &'a self instead of self: &Arc<Self>
  fn try_view<'a>(&'a self, va: McuVa, len: u64, reach: u64)
      -> Result<McuView<'a>>
  fn try_view_mut<'a>(&'a self, va: McuVa, len: u64, reach: u64)
      -> Result<McuViewMut<'a>>
}

c) Views get renamed to McuView, McuViewMut:

#[derive(Clone)]
pub(super) struct McuView<'a> {
  vmap: &'a VMapOwned<BoData>,
  base: u64,
  range: Range<u64>,
  reach: u64, // <———— Store this
}

pub(super) struct McuViewMut<'a> {
  view: McuView<'a>,
  claims: &'a Mutex<KVec<Range<u64>>>,
}

impl<'a> Deref for McuViewMut<'a> {
  type Target = McuView<'a>;
  fn deref(&self) -> &Self::Target {
    &self.view
  }
}

impl Drop for McuViewMut<'_> {
  // return claim here.
}


> 
> +// SAFETY: `MappedBo` may move between threads: the CPU mapping's address is
> +// valid from any thread; `KernelBo`'s teardown (GPU unmap through `Arc<Vm>`
> +// and the GEM object release) goes through thread-safe C APIs; and the only
> +// interior mutability (`claims`) is mutex-protected.
> +unsafe impl Send for MappedBo<'_> {}
> +// SAFETY: `&MappedBo` exposes the mutex-protected claims table, the `Deref`
> +// surface to the GEM object (thread-safe C APIs), and the mapping itself,
> +// whose contents are only ever accessed through volatile operations. The
> +// memory is shared with the MCU by design, so concurrent access is part of
> +// the model rather than a race the type system must rule out.
> +unsafe impl Sync for MappedBo<'_> {}


I don’t think we need a manual implementation here.

The rest of the patch looks good to me.

— Daniel


Reply via email to