dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Alice Ryhl <aliceryhl@google.com>
To: Deborah Brouwer <deborah.brouwer@collabora.com>
Cc: Daniel Almeida <daniel.almeida@collabora.com>,
	Danilo Krummrich <dakr@kernel.org>,
	 David Airlie <airlied@gmail.com>,
	Simona Vetter <simona@ffwll.ch>, Benno Lossin <lossin@kernel.org>,
	 Gary Guo <gary@garyguo.net>,
	dri-devel@lists.freedesktop.org,  linux-kernel@vger.kernel.org,
	rust-for-linux@vger.kernel.org,  boris.brezillon@collabora.com,
	samitolvanen@google.com, acourbot@nvidia.com,
	 alvin.sun@linux.dev, laura.nao@collabora.com,
	work@onurozkan.dev,  beata.michalska@arm.com,
	steven.price@arm.com, lyude@redhat.com
Subject: Re: [PATCH v6 4/7] drm/tyr: add GPU virtual memory (VM) support
Date: Fri, 10 Jul 2026 14:15:09 +0000	[thread overview]
Message-ID: <alD-bUuMS2913WJO@google.com> (raw)
In-Reply-To: <20260709-fw-boot-b4-v6-4-ca391e1a4108@collabora.com>

On Thu, Jul 09, 2026 at 02:36:44PM -0700, Deborah Brouwer wrote:
> From: Boris Brezillon <boris.brezillon@collabora.com>
> 
> Add GPU virtual address space management using the DRM GPUVM framework.
> Each virtual memory (VM) space is backed by ARM64 LPAE Stage 1 page tables
> and can be mapped into hardware address space (AS) slots for GPU execution.
> 
> The implementation provides memory isolation and virtual address
> allocation. VMs support mapping GEM buffer objects with configurable
> protection flags (readonly, noexec, uncached) and handle both 4KB and 2MB
> page sizes. A new_dummy_object() helper is provided to create a dummy GEM
> object for use as a GPUVM root.
> 
> The vm module integrates with the MMU for address space activation and
> provides map/unmap/remap operations with page table synchronization.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> Co-developed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> Co-developed-by: Deborah Brouwer <deborah.brouwer@collabora.com>
> Signed-off-by: Deborah Brouwer <deborah.brouwer@collabora.com>

> +impl core::fmt::Display for VmMapFlags {

Use kernel::fmt instead of core::fmt.

> +impl TryFrom<u32> for VmMapFlags {
> +    type Error = Error;
> +
> +    fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {

Simplifies to Result<Self, Self::Error> without full path.

> +        let valid = (kernel::uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_MAP_READONLY
> +            | kernel::uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC
> +            | kernel::uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED)
> +            as u32;

Simplifies to

	let valid = Self::Readonly as u32 | Self::Noexec as u32 | Self::Uncached as u32;

> +impl Drop for PtUpdateContext<'_, '_> {
> +    fn drop(&mut self) {
> +        if let Err(e) = self.mmu.end_vm_update(self.as_data) {
> +            pr_err!("Failed to end VM update {:?}\n", e);
> +        }
> +
> +        if let Err(e) = self.mmu.flush_vm(self.as_data) {
> +            pr_err!("Failed to flush VM {:?}\n", e);
> +        }

I assume it's not possible for this to run during a VM eviction, right?

> +        let gpuvm_unique = kernel::drm::gpuvm::GpuVm::new::<Error, _>(
> +            c_str!("Tyr::GpuVm"),

This can just be c"Tyr::GpuVm". The macro is only needed in macro
contexts where this rewrite is not possible e.g. because the macro's
caller provides a non-c str literal.

> +        let mut gpuvm_unique = self.gpuvm_unique.lock();
> +
> +        self.exec_op(gpuvm_unique.as_mut().get_mut(), req, &mut resources)?;
> +
> +        // We flush the defer cleanup list now. Things will be different in
> +        // the asynchronous VM_BIND path, where we want the cleanup to
> +        // happen outside the DMA signalling path.
> +        self.gpuvm.deferred_cleanup();

You should probably release the gpuvm_unique mutex before invoking
deferred_cleanup().

(Multiple occurances in this patch.)

> +            if gem_offset > 0 {
> +                // Skip the entire SGT entry if the gem_offset exceeds its length
> +                let skip = sgt_entry_length.min(gem_offset);

Nit: this may just be my idiosyncrasy, but I think this is more readable as:

	usize::min(sgt_entry_length, gem_offset)

(Multiple occurances in this file.)

> +            let segment_mapped = match pt_map(context.pt, iova, paddr, len, prot) {
> +                Ok(segment_mapped) => segment_mapped,
> +                Err(e) => {
> +                    // clean up any successful mappings from previous SGT entries.
> +                    let total_mapped = iova - start_iova;
> +                    if total_mapped > 0 {
> +                        pt_unmap(context.pt, start_iova..(start_iova + total_mapped)).ok();

Nit: the idiomatic way to ignore errors is to write:

	let _ = pt_unmap(context.pt, start_iova..(start_iova + total_mapped));

instead of converting the Result into an Option with .ok() and abusing
the fact that Option is not #[must_use].

> +/// This function selects the largest supported block size (currently 4KB or 2MB)
> +/// that can be used for a mapping at the given address and size, respecting alignment constraints.
> +///
> +/// We can map multiple pages at once but we can't exceed the size of the
> +// table entry itself. So, if mapping 4KB pages, figure out how many pages
> +// can be mapped before we hit the 2MB boundary. Or, if mapping 2MB pages,
> +// figure out how many pages can be mapped before hitting the 1GB boundary
> +// Returns the page size (4KB or 2MB) and the number of pages that can be mapped at that size.
> +fn get_pgsize(addr: u64, size: u64) -> (u64, u64) {

Some of these comments are missing a / character.

> +        // SAFETY: Exclusive access to the page table is ensured because
> +        // the pt reference comes from PtUpdateContext, which is created
> +        // during a VM update operation, ensuring the driver does not concurrently
> +        // modify the page table.
> +        let (mapped, result) = unsafe {
> +            pt.map_pages(
> +                curr_iova as usize,
> +                (curr_paddr as usize).try_into().unwrap(),
> +                pgsize as usize,
> +                pgcount as usize,
> +                prot,
> +                GFP_KERNEL,
> +            )
> +        };

It would be ideal if this SAFETY comment explains why this safety
requirement is satisfied:

	This page table must not contain any mapping that overlaps with
	the mapping created by this call.

(It's because GPUVM tells you to unmap pages before it tells you to map
them.)

> +/// Unmaps a virtual address range from the page table.
> +///
> +/// This function removes all page table entries in the specified range,
> +/// automatically handling different page sizes that may be present.
> +fn pt_unmap(pt: &IoPageTable<'_, ARM64LPAES1>, range: Range<u64>) -> Result {
> +    let mut iova = range.start;
> +    let mut bytes_left_to_unmap = range.end - range.start;
> +
> +    while bytes_left_to_unmap > 0 {
> +        let (pgsize, pgcount) = get_pgsize(iova, bytes_left_to_unmap);
> +
> +        // SAFETY: Exclusive access to the page table is ensured because
> +        // the pt reference comes from PtUpdateContext, which was
> +        // created while holding &mut Vm, preventing any other access to the
> +        // page table for the duration of this operation.
> +        let unmapped = unsafe { pt.unmap_pages(iova as usize, pgsize as usize, pgcount as usize) };

It would be ideal if this SAFETY comment explains why this safety
requirement is satisfied:

	This page table must contain one or more consecutive mappings
	starting at `iova` whose total size is `pgcount * pgsize`.

I.e. why can we be sure that this call isn't trying to unmap a 4KB
sub-page in something that exists as a 2MB mapping in the page table?

(It's because GPUVM tells you to unmap exactly the range you were
previously told to map.)

Alice

  reply	other threads:[~2026-07-10 14:15 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-09 21:36 [PATCH v6 0/7] drm/tyr: firmware loading and MCU boot support Deborah Brouwer
2026-07-09 21:36 ` [PATCH v6 1/7] drm/tyr: add resources to RegistrationData Deborah Brouwer
2026-07-09 21:36 ` [PATCH v6 2/7] drm/tyr: add a generic slot manager Deborah Brouwer
2026-07-10 13:23   ` Alice Ryhl
2026-07-09 21:36 ` [PATCH v6 3/7] drm/tyr: add Memory Management Unit (MMU) support Deborah Brouwer
2026-07-10 13:45   ` Alice Ryhl
2026-07-09 21:36 ` [PATCH v6 4/7] drm/tyr: add GPU virtual memory (VM) support Deborah Brouwer
2026-07-10 14:15   ` Alice Ryhl [this message]
2026-07-10 14:27   ` Alice Ryhl
2026-07-09 21:36 ` [PATCH v6 5/7] drm/tyr: add a kernel buffer object Deborah Brouwer
2026-07-09 21:36 ` [PATCH v6 6/7] drm/tyr: add parser for firmware binary Deborah Brouwer
2026-07-09 21:36 ` [PATCH v6 7/7] drm/tyr: add Microcontroller Unit (MCU) booting Deborah Brouwer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alD-bUuMS2913WJO@google.com \
    --to=aliceryhl@google.com \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=alvin.sun@linux.dev \
    --cc=beata.michalska@arm.com \
    --cc=boris.brezillon@collabora.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=deborah.brouwer@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=laura.nao@collabora.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=lyude@redhat.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=samitolvanen@google.com \
    --cc=simona@ffwll.ch \
    --cc=steven.price@arm.com \
    --cc=work@onurozkan.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox