[PATCH v2 11/32] gpu: nova-core: mm: add VramRegion

From: Zhi Wang

Date: Mon Sep 14 2026 - 04:11:47 EST


BAR mappings do not necessarily cover an entire VRAM block. A region
layer lets a mapping select a byte range while keeping the underlying
allocation alive.

For vGPU, communication buffers occupy only part of the management heap
and need a BAR mapping of that range.

Add VramRegion to describe ranges within a shared VramBlock and support
bounds-checked subregions.

Cc: Alistair Popple <apopple@xxxxxxxxxx>
Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
---
drivers/gpu/nova-core/mm/vram.rs | 62 ++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)

diff --git a/drivers/gpu/nova-core/mm/vram.rs b/drivers/gpu/nova-core/mm/vram.rs
index 743a2a163318..2c7183f08027 100644
--- a/drivers/gpu/nova-core/mm/vram.rs
+++ b/drivers/gpu/nova-core/mm/vram.rs
@@ -34,6 +34,68 @@ impl VramBlock {
pub(crate) const fn address(&self) -> u64 {
self.address
}
+
+ /// Creates a byte range relative to this allocation, retaining its backing storage.
+ pub(crate) fn region(self: &Arc<Self>, range: Range<u64>) -> Result<VramRegion> {
+ VramRegion::new(self.clone(), range)
+ }
+}
+
+/// A byte range that keeps its VRAM allocation alive.
+#[derive(Clone)]
+pub(crate) struct VramRegion {
+ backing: Arc<VramBlock>,
+ address: u64,
+ size: u64,
+}
+
+impl VramRegion {
+ fn new(backing: Arc<VramBlock>, range: Range<u64>) -> Result<Self> {
+ let size = range
+ .end
+ .checked_sub(range.start)
+ .filter(|size| *size != 0)
+ .ok_or(EINVAL)?;
+ if range.end > backing.size {
+ return Err(EINVAL);
+ }
+ let address = backing.address.checked_add(range.start).ok_or(EOVERFLOW)?;
+ backing.address.checked_add(range.end).ok_or(EOVERFLOW)?;
+
+ Ok(Self {
+ backing,
+ address,
+ size,
+ })
+ }
+
+ pub(crate) const fn address(&self) -> u64 {
+ self.address
+ }
+
+ pub(crate) const fn size(&self) -> u64 {
+ self.size
+ }
+
+ /// Creates a nonempty subregion relative to this view's start.
+ pub(crate) fn subregion(&self, range: Range<u64>) -> Result<Self> {
+ let size = range
+ .end
+ .checked_sub(range.start)
+ .filter(|size| *size != 0)
+ .ok_or(EINVAL)?;
+ if range.end > self.size {
+ return Err(EINVAL);
+ }
+ let address = self.address.checked_add(range.start).ok_or(EOVERFLOW)?;
+ address.checked_add(size).ok_or(EOVERFLOW)?;
+
+ Ok(Self {
+ backing: self.backing.clone(),
+ address,
+ size,
+ })
+ }
}

impl GpuMm<'_> {