* [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support
@ 2026-08-27 8:51 Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 01/10] gpu: nova-core: mm: Add VramAddress type Eliot Courtney
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
This series adds support for the PRAMIN window, plus some documentation.
Some of these patches were originally written by Joel Fernandes [1]. I
have updated them with changelog notes in each patch. For example, I
updated them for the newer IO machinery from Gary Guo.
This series adds a Pramin structure which deals with updating the PRAMIN
window and handing out typed MMIO views. The PRAMIN window is a method
that lets arbitrary VRAM be written over BAR0 by configuring a 1 MiB
window through GPU registers. That 1 MiB window can point anywhere in
VRAM. This is useful for bootstrapping e.g. GPU side page tables.
The Pramin structure hands out typed MMIO views to do writes through
rather than letting callers write directly through it. A follow up
series will add support for GPU side page table entry writing through
this mechanism. This abstraction is important for later since we will
eventually want to write the PTEs via BAR2 not PRAMIN - using a view
that we grab from the Pramin structure can abstract this out.
This is based on next-20260817 (e6664f2b33db), with Gary's register IO
projection v3 series [2] applied on top.
[1]: https://lore.kernel.org/all/20260518180342.2387845-1-joelagnelf@nvidia.com/
[2]: https://patch.msgid.link/20260819-typed_register-v3-0-3699a75fadf1@garyguo.net
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
Changes in v3:
- Dropped first three Bounded patches which are merged now
- Rebase on v3 of IO reg projections
- Carry Gary's Io::cast patch which was dropped in the v3 since we use
it.
- Link to v2: https://patch.msgid.link/20260810-pramin-split-v2-0-65a00b3c7309@nvidia.com
Changes in v2:
- Rebase onto Gary's IO register projection series
- Drop Region::try_subregion patch in favour of Gary's reg projection
- Convert Pramin code to use Gary's reg projection
- Fix const {assert!} -> const_assert! (Gary)
- Add #[inline] to shr_exact (Sashiko, Alex)
- Link to v1: https://patch.msgid.link/20260805-pramin-split-v1-0-ff3e84a75dac@nvidia.com
---
Eliot Courtney (3):
gpu: nova-core: mm: Implement Alignable and Debug for VramAddress
gpu: nova-core: mm: Add the memory management HAL
gpu: nova-core: Add self-test assertion macros and config option
Gary Guo (1):
rust: io: add static `cast()` method for views
Joel Fernandes (6):
gpu: nova-core: mm: Add VramAddress type
gpu: nova-core: mm: Add PRAMIN window registers
gpu: nova-core: mm: Add support to use PRAMIN windows to write to VRAM
docs: gpu: nova-core: Document the PRAMIN aperture mechanism
gpu: nova-core: mm: Add GpuMm centralized memory manager
gpu: nova-core: mm: Add PRAMIN aperture self-tests
Documentation/gpu/nova/core/pramin.rst | 128 +++++++++++++
Documentation/gpu/nova/index.rst | 1 +
drivers/gpu/nova-core/Kconfig | 9 +
drivers/gpu/nova-core/driver.rs | 3 +
drivers/gpu/nova-core/gpu.rs | 30 ++-
drivers/gpu/nova-core/gsp/commands.rs | 4 +
drivers/gpu/nova-core/gsp/fw/commands.rs | 5 +
drivers/gpu/nova-core/mm.rs | 163 ++++++++++++++++
drivers/gpu/nova-core/mm/hal.rs | 56 ++++++
drivers/gpu/nova-core/mm/hal/gb100.rs | 35 ++++
drivers/gpu/nova-core/mm/hal/gh100.rs | 35 ++++
drivers/gpu/nova-core/mm/hal/tu102.rs | 37 ++++
drivers/gpu/nova-core/mm/pramin.rs | 312 +++++++++++++++++++++++++++++++
drivers/gpu/nova-core/mm/regs.rs | 70 +++++++
drivers/gpu/nova-core/nova_core.rs | 3 +
drivers/gpu/nova-core/selftest.rs | 64 +++++++
rust/kernel/io.rs | 39 ++++
17 files changed, 993 insertions(+), 1 deletion(-)
---
base-commit: e6664f2b33db9b6811eb4cec109f06cb2b4f458d
change-id: 20260804-pramin-split-950e210b6e3f
prerequisite-change-id: 20260721-typed_register-176eab3abee7:v3
prerequisite-patch-id: 9d08451e181409e33cda3549dd2f6a18ad742a38
prerequisite-patch-id: 35e98efa10cce8cdd6c9df954c34d778a8b57e97
prerequisite-patch-id: 9dc002f047fb0c688c0ccce751535161fde8c216
prerequisite-patch-id: 551843cf854964cd9ef49378aa99000c8af73710
prerequisite-patch-id: 798405871b568af61cb6b9f0bf035c03b50eafe7
prerequisite-patch-id: fd9f266b3d8c80cc7ef4a3d59e302c25af9bb145
prerequisite-patch-id: 131291b0a4dc1ee7e43dd038f6f99fc5dc0eb99b
prerequisite-patch-id: 7c66eb2438e79edc6566b9e977ee33137d3e7fa1
prerequisite-patch-id: 8224018b7cfec0b00cce46b238abd9f68240e187
prerequisite-patch-id: cc910d5993c190268077d2dd56d787abd984465d
prerequisite-patch-id: 9590fa1a5c856c952eec73b630949a50e90ab4e8
prerequisite-patch-id: 511ce76481fe20bb1c498f020a5151bb008525f1
prerequisite-patch-id: 127be60ba6331574f6784cc8a5013d4f91b47df4
prerequisite-patch-id: d2faa8292625cbdc43f262f3773a1c5cc1f90935
prerequisite-patch-id: c447b4c47960e45497bd75bea84e6f1aea30eb74
prerequisite-patch-id: 5051a948fa965dd94348da1ec2f93bee8ff86106
Best regards,
--
Eliot Courtney <ecourtney@nvidia.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 01/10] gpu: nova-core: mm: Add VramAddress type
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 02/10] gpu: nova-core: mm: Implement Alignable and Debug for VramAddress Eliot Courtney
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
From: Joel Fernandes <joelagnelf@nvidia.com>
Add the `VramAddress` type representing a physical address in VRAM. Also
add an arithmetic helper, comparison, and operator overloads which are
required in later patches for address arithmetic.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[ecourtney: create mm.rs here, squashing in the arithmetic patch]
[ecourtney: splice the two commit bodies]
[ecourtney: drop the Pfn fields, open-coding what bitfield! generated]
[ecourtney: drop align_down and the IntoVramOffset/IntoVramRange traits]
[ecourtney: make checked_add() const over a plain u64, derive the ordering]
[ecourtney: doc wording, header, import, and signature cleanups]
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/mm.rs | 60 ++++++++++++++++++++++++++++++++++++++
drivers/gpu/nova-core/nova_core.rs | 1 +
2 files changed, 61 insertions(+)
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
new file mode 100644
index 000000000000..dcd5e5e919bf
--- /dev/null
+++ b/drivers/gpu/nova-core/mm.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Memory management subsystems.
+
+#![expect(dead_code)]
+
+use core::{
+ fmt::LowerHex,
+ ops, //
+};
+
+use kernel::fmt;
+
+/// Physical VRAM address in GPU video memory.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(transparent)]
+pub(crate) struct VramAddress(u64);
+
+impl VramAddress {
+ /// Creates an address from a raw value.
+ pub(crate) const fn from_raw(addr: u64) -> Self {
+ Self(addr)
+ }
+
+ /// Returns the address as a raw value.
+ pub(crate) const fn into_raw(self) -> u64 {
+ self.0
+ }
+
+ /// Adds `rhs` to this address, returning [`None`] on overflow.
+ pub(crate) const fn checked_add(self, rhs: u64) -> Option<Self> {
+ match self.into_raw().checked_add(rhs) {
+ Some(addr) => Some(Self::from_raw(addr)),
+ None => None,
+ }
+ }
+}
+
+impl LowerHex for VramAddress {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ LowerHex::fmt(&self.into_raw(), f)
+ }
+}
+
+impl ops::Add<u64> for VramAddress {
+ type Output = Self;
+
+ fn add(self, rhs: u64) -> Self::Output {
+ Self::from_raw(self.into_raw() + rhs)
+ }
+}
+
+impl ops::Sub for VramAddress {
+ type Output = u64;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.into_raw() - rhs.into_raw()
+ }
+}
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 35a8b1214b0e..8f59cfa97017 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -18,6 +18,7 @@
mod gpu;
mod gsp;
mod mctp;
+mod mm;
#[macro_use]
mod num;
mod regs;
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 02/10] gpu: nova-core: mm: Implement Alignable and Debug for VramAddress
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 01/10] gpu: nova-core: mm: Add VramAddress type Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 03/10] gpu: nova-core: mm: Add PRAMIN window registers Eliot Courtney
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney
Later patches align VRAM addresses down to the PRAMIN window. Implement
`Alignable` trait for `VramAddress` and plus add a `ZERO` constant.
Also print the address in hex under `{:?}`, so it reads well in debug
output.
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/mm.rs | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index dcd5e5e919bf..f9d80ffbe01d 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -10,7 +10,14 @@
ops, //
};
-use kernel::fmt;
+use kernel::{
+ fmt,
+ prelude::*,
+ ptr::{
+ Alignable,
+ Alignment, //
+ },
+};
/// Physical VRAM address in GPU video memory.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -18,6 +25,9 @@
pub(crate) struct VramAddress(u64);
impl VramAddress {
+ /// The zero address.
+ pub(crate) const ZERO: Self = Self::from_raw(0);
+
/// Creates an address from a raw value.
pub(crate) const fn from_raw(addr: u64) -> Self {
Self(addr)
@@ -37,12 +47,28 @@ pub(crate) const fn checked_add(self, rhs: u64) -> Option<Self> {
}
}
+impl Alignable for VramAddress {
+ fn align_down(self, alignment: Alignment) -> Self {
+ Self::from_raw(self.into_raw().align_down(alignment))
+ }
+
+ fn align_up(self, alignment: Alignment) -> Option<Self> {
+ self.into_raw().align_up(alignment).map(Self::from_raw)
+ }
+}
+
impl LowerHex for VramAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
LowerHex::fmt(&self.into_raw(), f)
}
}
+impl fmt::Debug for VramAddress {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_fmt(fmt!("{:#x}", self))
+ }
+}
+
impl ops::Add<u64> for VramAddress {
type Output = Self;
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 03/10] gpu: nova-core: mm: Add PRAMIN window registers
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 01/10] gpu: nova-core: mm: Add VramAddress type Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 02/10] gpu: nova-core: mm: Implement Alignable and Debug for VramAddress Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 04/10] gpu: nova-core: mm: Add the memory management HAL Eliot Courtney
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
From: Joel Fernandes <joelagnelf@nvidia.com>
PRAMIN apertures are a crucial mechanism for direct CPU read/write to
VRAM. Add the BAR0 window registers that position the PRAMIN aperture
on all supported GPU architectures: Turing, Ampere, Ada (via
`NV_PBUS_BAR0_WINDOW`), Hopper (via `gh100::NV_XAL_EP_BAR0_WINDOW`),
and Blackwell (via `gb100::NV_XAL_EP_BAR0_WINDOW`).
Hopper/Blackwell window-base registers are based on Eliot Courtney's
offlist reference patch.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[ecourtney: split the registers out of the PRAMIN patch into mm/regs.rs]
[ecourtney: drop the register read path]
[ecourtney: reword the message for the split, narrow visibility to mm]
[ecourtney: plain base fields, as the bitfield cast+shift patch is dropped]
[ecourtney: rename the target to VidMem, fix derives, redo the target docs]
[ecourtney: annotate the register base types]
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/mm.rs | 2 ++
drivers/gpu/nova-core/mm/regs.rs | 70 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index f9d80ffbe01d..7d24ad790310 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -19,6 +19,8 @@
},
};
+mod regs;
+
/// Physical VRAM address in GPU video memory.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
diff --git a/drivers/gpu/nova-core/mm/regs.rs b/drivers/gpu/nova-core/mm/regs.rs
new file mode 100644
index 000000000000..82de6dfa4e8b
--- /dev/null
+++ b/drivers/gpu/nova-core/mm/regs.rs
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Registers used by the memory management subsystems: the BAR0 PRAMIN window.
+
+use kernel::io::register;
+
+use crate::{
+ bounded_enum,
+ driver::NovaRegisters, //
+};
+
+// PRAMIN window
+
+bounded_enum! {
+ /// Target memory type for the BAR0 window register.
+ ///
+ /// Only VRAM is needed by the driver. Pre-Hopper window registers also define
+ /// system-memory targets that are unused here; Hopper+ uses a separate register
+ /// without a target field.
+ #[derive(Debug, Copy, Clone)]
+ pub(super) enum Bar0WindowTarget with TryFrom<Bounded<u32, 2>> {
+ /// Video memory (GPU framebuffer memory).
+ VidMem = 0,
+ }
+}
+
+register! {
+ base: NovaRegisters;
+
+ /// BAR0 window control for PRAMIN access.
+ pub(super) NV_PBUS_BAR0_WINDOW(u32) @ 0x00001700 {
+ /// Target memory aperture for the window.
+ 25:24 target ?=> Bar0WindowTarget;
+ /// PRAMIN window base bits 39:16.
+ 23:0 base;
+ }
+}
+
+pub(super) mod gh100 {
+ use kernel::io::register;
+
+ use crate::driver::NovaRegisters;
+
+ register! {
+ base: NovaRegisters;
+
+ /// Hopper register for PRAMIN window.
+ pub(crate) NV_XAL_EP_BAR0_WINDOW(u32) @ 0x0010fd40 {
+ /// PRAMIN window base bits 37:16.
+ 21:0 base;
+ }
+ }
+}
+
+pub(super) mod gb100 {
+ use kernel::io::register;
+
+ use crate::driver::NovaRegisters;
+
+ register! {
+ base: NovaRegisters;
+
+ /// Blackwell GB10x/GB20x register for PRAMIN window.
+ pub(crate) NV_XAL_EP_BAR0_WINDOW(u32) @ 0x0010fd40 {
+ /// PRAMIN window base bits 38:16.
+ 22:0 base;
+ }
+ }
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 04/10] gpu: nova-core: mm: Add the memory management HAL
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (2 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 03/10] gpu: nova-core: mm: Add PRAMIN window registers Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 05/10] rust: io: add static `cast()` method for views Eliot Courtney
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney
Positioning the PRAMIN window requires writing an architecture-specific
register: `NV_PBUS_BAR0_WINDOW` on Turing, Ampere and Ada, and
`NV_XAL_EP_BAR0_WINDOW` with a different field width on Hopper and on
Blackwell.
A `MmHal` trait with one implementation per hardware family hides the
register choice from the rest of the mm code, matching the layout of
the driver's other HALs.
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/mm.rs | 1 +
drivers/gpu/nova-core/mm/hal.rs | 56 +++++++++++++++++++++++++++++++++++
drivers/gpu/nova-core/mm/hal/gb100.rs | 35 ++++++++++++++++++++++
drivers/gpu/nova-core/mm/hal/gh100.rs | 35 ++++++++++++++++++++++
drivers/gpu/nova-core/mm/hal/tu102.rs | 37 +++++++++++++++++++++++
5 files changed, 164 insertions(+)
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index 7d24ad790310..07dce4ce2473 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -19,6 +19,7 @@
},
};
+mod hal;
mod regs;
/// Physical VRAM address in GPU video memory.
diff --git a/drivers/gpu/nova-core/mm/hal.rs b/drivers/gpu/nova-core/mm/hal.rs
new file mode 100644
index 000000000000..e7fd1e38bd38
--- /dev/null
+++ b/drivers/gpu/nova-core/mm/hal.rs
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Memory management HAL.
+
+use kernel::{
+ num::Bounded,
+ prelude::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ gpu::{
+ Architecture,
+ Chipset, //
+ },
+ mm::VramAddress, //
+};
+
+mod gb100;
+mod gh100;
+mod tu102;
+
+/// Trait implemented by per-architecture MM HALs.
+///
+/// `Sync` is required so that the `&'static dyn MmHal` references can be stored in `Send`
+/// structures.
+pub(super) trait MmHal: Sync {
+ /// Positions the PRAMIN window at `base`.
+ ///
+ /// This fails if `base` is not aligned to the 64 KiB window alignment or is too large for
+ /// the receiving register.
+ fn write_pramin_window_base(&self, bar: Bar0<'_>, base: VramAddress) -> Result;
+}
+
+/// Returns the HAL corresponding to `chipset`.
+pub(super) fn mm_hal(chipset: Chipset) -> &'static dyn MmHal {
+ match chipset.arch() {
+ Architecture::Turing | Architecture::Ampere | Architecture::Ada => tu102::TU102_HAL,
+ Architecture::Hopper => gh100::GH100_HAL,
+ Architecture::BlackwellGB10x | Architecture::BlackwellGB20x => gb100::GB100_HAL,
+ }
+}
+
+/// Converts `base` into the value of the window-base register field.
+///
+/// Fails with [`EINVAL`] if `base` is not aligned to the window alignment required by the register
+/// field's shift, or if the shifted value does not fit within `RES` bits.
+fn window_base<const RES: u32>(base: VramAddress) -> Result<Bounded<u64, RES>> {
+ const WINDOW_BASE_SHIFT: u32 = 16;
+
+ Bounded::<u64, 64>::from(base.into_raw())
+ .shr_exact::<WINDOW_BASE_SHIFT, { 64 - WINDOW_BASE_SHIFT }>()
+ .and_then(Bounded::try_shrink)
+ .ok_or(EINVAL)
+}
diff --git a/drivers/gpu/nova-core/mm/hal/gb100.rs b/drivers/gpu/nova-core/mm/hal/gb100.rs
new file mode 100644
index 000000000000..3781e143dea7
--- /dev/null
+++ b/drivers/gpu/nova-core/mm/hal/gb100.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Blackwell GB10x/GB20x memory management HAL.
+
+use kernel::{
+ io::Io,
+ prelude::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ mm::{
+ hal::{
+ window_base,
+ MmHal, //
+ },
+ regs,
+ VramAddress, //
+ },
+};
+
+struct Gb100;
+
+impl MmHal for Gb100 {
+ fn write_pramin_window_base(&self, bar: Bar0<'_>, base: VramAddress) -> Result {
+ bar.write_reg(
+ regs::gb100::NV_XAL_EP_BAR0_WINDOW::zeroed().with_base(window_base(base)?.cast()),
+ );
+ Ok(())
+ }
+}
+
+const GB100: Gb100 = Gb100;
+pub(super) const GB100_HAL: &dyn MmHal = &GB100;
diff --git a/drivers/gpu/nova-core/mm/hal/gh100.rs b/drivers/gpu/nova-core/mm/hal/gh100.rs
new file mode 100644
index 000000000000..8af384db2921
--- /dev/null
+++ b/drivers/gpu/nova-core/mm/hal/gh100.rs
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Hopper memory management HAL.
+
+use kernel::{
+ io::Io,
+ prelude::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ mm::{
+ hal::{
+ window_base,
+ MmHal, //
+ },
+ regs,
+ VramAddress, //
+ },
+};
+
+struct Gh100;
+
+impl MmHal for Gh100 {
+ fn write_pramin_window_base(&self, bar: Bar0<'_>, base: VramAddress) -> Result {
+ bar.write_reg(
+ regs::gh100::NV_XAL_EP_BAR0_WINDOW::zeroed().with_base(window_base(base)?.cast()),
+ );
+ Ok(())
+ }
+}
+
+const GH100: Gh100 = Gh100;
+pub(super) const GH100_HAL: &dyn MmHal = &GH100;
diff --git a/drivers/gpu/nova-core/mm/hal/tu102.rs b/drivers/gpu/nova-core/mm/hal/tu102.rs
new file mode 100644
index 000000000000..e4fe7561223c
--- /dev/null
+++ b/drivers/gpu/nova-core/mm/hal/tu102.rs
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Turing, Ampere and Ada memory management HAL.
+
+use kernel::{
+ io::Io,
+ prelude::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ mm::{
+ hal::{
+ window_base,
+ MmHal, //
+ },
+ regs,
+ VramAddress, //
+ },
+};
+
+struct Tu102;
+
+impl MmHal for Tu102 {
+ fn write_pramin_window_base(&self, bar: Bar0<'_>, base: VramAddress) -> Result {
+ bar.write_reg(
+ regs::NV_PBUS_BAR0_WINDOW::zeroed()
+ .with_target(regs::Bar0WindowTarget::VidMem)
+ .with_base(window_base(base)?.cast()),
+ );
+ Ok(())
+ }
+}
+
+const TU102: Tu102 = Tu102;
+pub(super) const TU102_HAL: &dyn MmHal = &TU102;
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 05/10] rust: io: add static `cast()` method for views
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (3 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 04/10] gpu: nova-core: mm: Add the memory management HAL Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 06/10] gpu: nova-core: mm: Add support to use PRAMIN windows to write to VRAM Eliot Courtney
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney
From: Gary Guo <gary@garyguo.net>
Add a compile-time checked variant of `try_cast()` using the minimum size
and alignment information.
Signed-off-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260805-typed_register-v2-1-c3ca142220a0@garyguo.net
[ecourtney: fix the doc example type and doc grammar per v2 review]
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
rust/kernel/io.rs | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 4542187d6b91..5f1be3b31acd 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -436,6 +436,45 @@ fn is_empty<T>(self) -> bool
self.len() == 0
}
+ /// Convert into a different typed I/O view.
+ ///
+ /// The target type must be known (statically) to be of the same or smaller size to current
+ /// type, and the current view must be properly aligned for the target type.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use kernel::io::{
+ /// io_project,
+ /// Mmio,
+ /// Io,
+ /// Region,
+ /// };
+ /// #[derive(FromBytes, IntoBytes)]
+ /// #[repr(C)]
+ /// struct MyStruct { field: u32, }
+ ///
+ /// # fn test(mmio: &Mmio<'_, Region<0x1000>>) {
+ /// // let mmio: Mmio<'_, Region<0x1000>>;
+ /// let whole: Mmio<'_, MyStruct> = mmio.cast();
+ /// # }
+ /// ```
+ #[inline]
+ fn cast<U>(self) -> <Self::Backend as IoBackend>::View<'a, U>
+ where
+ Self::Target: FromBytes + IntoBytes,
+ U: FromBytes + IntoBytes,
+ {
+ let view = self.as_view();
+ let ptr = Self::Backend::as_ptr(view);
+
+ const_assert!(size_of::<U>() <= Self::Target::MIN_SIZE);
+ const_assert!(align_of::<U>() <= Self::Target::MIN_ALIGN.as_usize());
+
+ // SAFETY: We have checked bounds and alignment, so this is a valid projection.
+ unsafe { Self::Backend::project_view(view, ptr.cast()) }
+ }
+
/// Try to convert into a different typed I/O view.
///
/// A runtime check is performed to ensure that the target type is of same or smaller size to
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 06/10] gpu: nova-core: mm: Add support to use PRAMIN windows to write to VRAM
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (4 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 05/10] rust: io: add static `cast()` method for views Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 07/10] docs: gpu: nova-core: Document the PRAMIN aperture mechanism Eliot Courtney
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
From: Joel Fernandes <joelagnelf@nvidia.com>
PRAMIN apertures are a crucial mechanism for direct CPU read/write to
VRAM. Add a `Pramin` manager whose `window_at()` returns a typed MMIO
view of VRAM through the 1 MiB PRAMIN aperture in BAR0, validating the
view against the VRAM region and repositioning the window as needed for
the accessed address.
A view borrows `Pramin` mutably, so the window cannot move while
the view is in use, and it inserts an ordering point on Drop.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[ecourtney: split the registers and HAL into the two preceding patches]
[ecourtney: rebase w.r.t. Bar0 lifetime changes and register projections]
[ecourtney: drop the window guard and mutex, use &mut self]
[ecourtney: position at init to avoid reads, reposition in window_offset]
[ecourtney: return typed MMIO views instead of read/write accessors]
[ecourtney: insert an ordering read when a view drops]
[ecourtney: declare the window location, drop the doc examples]
[ecourtney: add the copyright header, doc and naming cleanups]
[ecourtney: the pramin module is mm-internal]
Co-developed-by: Eliot Courtney <ecourtney@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/mm.rs | 1 +
drivers/gpu/nova-core/mm/pramin.rs | 178 +++++++++++++++++++++++++++++++++++++
2 files changed, 179 insertions(+)
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index 07dce4ce2473..ef5b1cad56c3 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -20,6 +20,7 @@
};
mod hal;
+mod pramin;
mod regs;
/// Physical VRAM address in GPU video memory.
diff --git a/drivers/gpu/nova-core/mm/pramin.rs b/drivers/gpu/nova-core/mm/pramin.rs
new file mode 100644
index 000000000000..20be3fc471ba
--- /dev/null
+++ b/drivers/gpu/nova-core/mm/pramin.rs
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Utilities for accessing VRAM through the PRAMIN window.
+
+use core::ops::Range;
+
+use kernel::{
+ io::{
+ io_project,
+ register,
+ register::OffsetLoc,
+ Io,
+ Mmio, //
+ },
+ prelude::*,
+ ptr::{
+ Alignable,
+ Alignment, //
+ },
+ sizes::{
+ SZ_1M,
+ SZ_64K, //
+ },
+};
+
+use crate::{
+ driver::{
+ Bar0,
+ NovaRegisters, //
+ },
+ gpu::Chipset,
+ mm::{
+ hal::{
+ self,
+ MmHal, //
+ },
+ VramAddress, //
+ },
+ num::IntoSafeCast, //
+};
+
+/// Size of the PRAMIN window (1 MiB).
+const WINDOW_SIZE: usize = SZ_1M;
+
+/// The PRAMIN window, which is a 1 MiB window into VRAM at a fixed BAR0 offset.
+#[derive(FromBytes, IntoBytes)]
+struct PraminWindow([u8; WINDOW_SIZE]);
+
+register! {
+ base: NovaRegisters;
+
+ /// Location of the window inside BAR0.
+ PRAMIN: PraminWindow @ 0x700000;
+}
+
+/// Owner of the PRAMIN window state.
+///
+/// [`Pramin::window_at()`] repositions the window as needed and returns a typed MMIO view into
+/// it, holding the manager borrowed for the lifetime of the view.
+pub(super) struct Pramin<'gpu> {
+ bar: Bar0<'gpu>,
+ hal: &'static dyn MmHal,
+ /// MMIO view of the PRAMIN window in BAR0.
+ window: Mmio<'gpu, PraminWindow>,
+ /// VRAM range to keep the PRAMIN window inside.
+ vram_range: Range<VramAddress>,
+ /// Cached window position.
+ window_range: Range<VramAddress>,
+}
+
+/// Typed view of VRAM through the PRAMIN window.
+///
+/// Inserts an ordering point after previous writes through the window on drop. Views returned
+/// by [`PraminAccess::view()`] cannot outlive this access, so the ordering point covers every
+/// write made through them.
+pub(super) struct PraminAccess<'a, T>
+where
+ T: FromBytes + IntoBytes,
+{
+ view: Mmio<'a, T>,
+}
+
+impl<T> PraminAccess<'_, T>
+where
+ T: FromBytes + IntoBytes,
+{
+ /// Returns the MMIO view of the accessed location.
+ pub(super) fn view(&self) -> Mmio<'_, T> {
+ self.view
+ }
+}
+
+impl<T> Drop for PraminAccess<'_, T>
+where
+ T: FromBytes + IntoBytes,
+{
+ fn drop(&mut self) {
+ // Insert an ordering point after previous writes through this window.
+ self.view.cast::<u8>().read_val();
+ }
+}
+
+impl<'gpu> Pramin<'gpu> {
+ /// Alignment required by the PRAMIN window.
+ const BASE_ALIGN: Alignment = Alignment::new::<SZ_64K>();
+
+ /// Creates the window manager for the given VRAM region.
+ pub(super) fn new(
+ bar: Bar0<'gpu>,
+ chipset: Chipset,
+ vram_range: Range<VramAddress>,
+ ) -> Result<Self> {
+ let hal = hal::mm_hal(chipset);
+ let window = io_project!(bar, build: PRAMIN);
+ let base = vram_range.start.align_down(Self::BASE_ALIGN);
+ let window_range = Self::window_range(base)?;
+ hal.write_pramin_window_base(bar, base)?;
+
+ Ok(Self {
+ bar,
+ hal,
+ window,
+ vram_range,
+ window_range,
+ })
+ }
+
+ /// Returns the VRAM range a window based at `base` exposes.
+ fn window_range(base: VramAddress) -> Result<Range<VramAddress>> {
+ let end = base
+ .checked_add(WINDOW_SIZE.into_safe_cast())
+ .ok_or(EINVAL)?;
+ Ok(base..end)
+ }
+
+ /// Check the window covers `len` bytes at `addr`, moving it if needed.
+ ///
+ /// Returns the window offset at which to perform the access.
+ fn window_offset(&mut self, addr: VramAddress, len: usize) -> Result<usize> {
+ let end = addr.checked_add(len.into_safe_cast()).ok_or(EINVAL)?;
+
+ let inside = |r: &Range<VramAddress>| r.contains(&addr) && end <= r.end;
+ if !inside(&self.vram_range) {
+ return Err(EINVAL);
+ }
+
+ // Reposition the window if the access falls outside it.
+ if !inside(&self.window_range) {
+ let base = addr.align_down(Self::BASE_ALIGN);
+ let window_range = Self::window_range(base)?;
+ if !inside(&window_range) {
+ return Err(EINVAL);
+ }
+ self.hal.write_pramin_window_base(self.bar, base)?;
+ self.window_range = window_range;
+ }
+
+ Ok((addr - self.window_range.start).into_safe_cast())
+ }
+
+ /// Return a typed MMIO view of a `T` at `vram_addr`.
+ ///
+ /// Returns an error if `vram_addr` is not aligned to `T`'s alignment, or if
+ /// a `T` at `vram_addr` does not fit within the VRAM region.
+ pub(super) fn window_at<'a, T>(
+ &'a mut self,
+ vram_addr: VramAddress,
+ ) -> Result<PraminAccess<'a, T>>
+ where
+ T: FromBytes + IntoBytes,
+ {
+ let offset = self.window_offset(vram_addr, size_of::<T>())?;
+ let view = io_project!(self.window, try: OffsetLoc::new(offset));
+
+ Ok(PraminAccess { view })
+ }
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 07/10] docs: gpu: nova-core: Document the PRAMIN aperture mechanism
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (5 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 06/10] gpu: nova-core: mm: Add support to use PRAMIN windows to write to VRAM Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 08/10] gpu: nova-core: mm: Add GpuMm centralized memory manager Eliot Courtney
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
From: Joel Fernandes <joelagnelf@nvidia.com>
Add documentation for the PRAMIN aperture mechanism used by nova-core
for direct VRAM access.
Nova only uses TARGET=VRAM for VRAM access. The SYS_MEM target values
are documented for completeness but not used by the driver.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[ecourtney: fix the TARGET encodings, KiB/MiB units, wording nits]
[ecourtney: wrap at 80 columns]
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
Documentation/gpu/nova/core/pramin.rst | 128 +++++++++++++++++++++++++++++++++
Documentation/gpu/nova/index.rst | 1 +
2 files changed, 129 insertions(+)
diff --git a/Documentation/gpu/nova/core/pramin.rst b/Documentation/gpu/nova/core/pramin.rst
new file mode 100644
index 000000000000..f50b052d73ba
--- /dev/null
+++ b/Documentation/gpu/nova/core/pramin.rst
@@ -0,0 +1,128 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================
+PRAMIN aperture mechanism
+=========================
+
+.. note::
+ The following description is approximate and current as of the Ampere
+ family. It may change for future generations and is intended to assist in
+ understanding the driver code.
+
+Introduction
+============
+
+PRAMIN is a hardware aperture mechanism that provides CPU access to GPU Video
+RAM (VRAM) before the GPU's Memory Management Unit (MMU) and page tables are
+initialized. This 1 MiB sliding window, located at a fixed offset within BAR0,
+is essential for setting up page tables and other critical GPU data structures
+without relying on the GPU's MMU.
+
+Architecture Overview
+=====================
+
+The PRAMIN aperture mechanism is logically implemented by the GPU's PBUS (PCIe
+Bus Controller Unit) and provides a CPU-accessible window into VRAM through the
+PCIe interface::
+
+ +-----------------+ PCIe +------------------------------+
+ | CPU |<----------->| GPU |
+ +-----------------+ | |
+ | +----------------------+ |
+ | | PBUS | |
+ | | (Bus Controller) | |
+ | | | |
+ | | +--------------+ <------------ [1]
+ | | | PRAMIN | | |
+ | | | Window | | |
+ | | | (1 MiB) | | |
+ | | +--------------+ | |
+ | | | | |
+ | +---------|------------+ |
+ | | |
+ | v |
+ | +----------------------+ <------- [2]
+ | | VRAM | |
+ | | (Several GiB) | |
+ | | | |
+ | | FB[0x0000000000] | |
+ | | ... | |
+ | | FB[0xFFFFFFFFFF] | |
+ | +----------------------+ |
+ +------------------------------+
+
+ [1] Window starts at BAR0 + 0x700000.
+ [2] Program PRAMIN to any 64 KiB-aligned VRAM boundary.
+
+PBUS is responsible for, among other things, handling MMIO
+accesses to the BAR registers.
+
+PRAMIN Window Operation
+=======================
+
+The PRAMIN window provides a 1 MiB sliding aperture that can be repositioned
+over the entire VRAM address space using the ``NV_PBUS_BAR0_WINDOW`` register.
+
+Window Control Mechanism
+-------------------------
+
+::
+
+ NV_PBUS_BAR0_WINDOW Register (0x1700):
+ +-------+--------+--------------------------------------+
+ | 31:26 | 25:24 | 23:0 |
+ | RSVD | TARGET | BASE_ADDR |
+ | | | (bits 39:16 of VRAM address) |
+ +-------+--------+--------------------------------------+
+
+ The 24-bit BASE_ADDR field encodes bits [39:16] of the target VRAM address,
+ providing 40-bit (1 TiB) address space coverage with 64 KiB alignment.
+
+ TARGET field (bits 25:24):
+ - 0x0: VRAM (Video Memory)
+ - 0x1: Reserved (unused)
+ - 0x2: SYS_MEM_COH (Coherent System Memory)
+ - 0x3: SYS_MEM_NONCOH (Non-coherent System Memory)
+
+.. note::
+ Nova only uses TARGET=VRAM (0x0) for video memory access. The SYS_MEM
+ target values are documented here for hardware completeness but are
+ not used by the driver.
+
+64 KiB Alignment Requirement
+----------------------------
+
+The PRAMIN window must be aligned to 64 KiB boundaries in VRAM. This is enforced
+by the ``BASE_ADDR`` field representing bits [39:16] of the target address::
+
+ VRAM Address Calculation:
+ actual_vram_addr = (BASE_ADDR << 16) + pramin_offset
+ Where:
+ - BASE_ADDR: 24-bit value from NV_PBUS_BAR0_WINDOW[23:0]
+ - pramin_offset: 20-bit offset within the PRAMIN window [0x00000-0xFFFFF]
+
+ Example Window Positioning:
+ +---------------------------------------------------------+
+ | VRAM Space |
+ | |
+ | 0x0000000000 +-----------------+ <-- 64 KiB aligned |
+ | | PRAMIN Window | |
+ | | (1 MiB) | |
+ | 0x00000FFFFF +-----------------+ |
+ | |
+ | | ^ |
+ | | | Window can slide |
+ | v | to any 64 KiB-aligned boundary |
+ | |
+ | 0x0123400000 +-----------------+ <-- 64 KiB aligned |
+ | | PRAMIN Window | |
+ | | (1 MiB) | |
+ | 0x01234FFFFF +-----------------+ |
+ | |
+ | ... |
+ | |
+ | 0xFFFFF00000 +-----------------+ <-- 64 KiB aligned |
+ | | PRAMIN Window | |
+ | | (1 MiB) | |
+ | 0xFFFFFFFFFF +-----------------+ |
+ +---------------------------------------------------------+
diff --git a/Documentation/gpu/nova/index.rst b/Documentation/gpu/nova/index.rst
index 2afa58e8f08d..59b206238498 100644
--- a/Documentation/gpu/nova/index.rst
+++ b/Documentation/gpu/nova/index.rst
@@ -34,3 +34,4 @@ vGPU manager VFIO driver and the nova-drm driver.
core/fwsec
core/falcon
core/tlv
+ core/pramin
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 08/10] gpu: nova-core: mm: Add GpuMm centralized memory manager
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (6 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 07/10] docs: gpu: nova-core: Document the PRAMIN aperture mechanism Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 09/10] gpu: nova-core: Add self-test assertion macros and config option Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 10/10] gpu: nova-core: mm: Add PRAMIN aperture self-tests Eliot Courtney
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
From: Joel Fernandes <joelagnelf@nvidia.com>
Introduce GpuMm as the centralized GPU memory manager. At this point in
the series, GpuMm only owns the PRAMIN window for direct VRAM access;
the buddy allocator and TLB manager are added later when those backing
types become available.
This provides a clean ownership model where GpuMm provides accessor
methods for its components that can be used for memory management
operations, and lets follow-on patches (such as the PRAMIN aperture
self-tests) reference `pramin_mut()` cleanly.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[ecourtney: squash the total VRAM end patch, drop its dev_info print]
[ecourtney: take the maximum FB limit before adding one, fail with EINVAL]
[ecourtney: rebase for the Bar0 lifetime and ownership changes, drop Arcs]
[ecourtney: source the chipset through gsp_resources]
[ecourtney: build the VRAM region in new(), pramin() becomes pramin_mut()]
[ecourtney: declare mm before gsp_resources, doc wording cleanups]
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/gpu.rs | 18 +++++++++++++++-
drivers/gpu/nova-core/gsp/commands.rs | 4 ++++
drivers/gpu/nova-core/gsp/fw/commands.rs | 5 +++++
drivers/gpu/nova-core/mm.rs | 35 ++++++++++++++++++++++++++++++++
4 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index fd1414004dd0..7b3e378c429b 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -29,6 +29,10 @@
Gsp,
GspBootContext, //
},
+ mm::{
+ GpuMm,
+ VramAddress, //
+ },
regs,
vgpu::VgpuManager, //
};
@@ -283,6 +287,11 @@ pub(crate) struct Gpu<'gpu> {
spec: Spec,
/// Static GPU information as provided by the GSP.
gsp_static_info: GetGspStaticInfoReply,
+ /// GPU memory manager owning memory management resources.
+ ///
+ /// Must be kept declared *before* `gsp_resources`, so that its components are dropped while
+ /// the GSP is still operational.
+ mm: GpuMm<'gpu>,
/// GSP and its resources.
#[pin]
gsp_resources: GspResources<'gpu>,
@@ -410,7 +419,14 @@ pub(crate) fn new<'a>(
}
info
- }
+ },
+
+ // Create GPU memory manager owning memory management resources.
+ mm: GpuMm::new(
+ bar,
+ gsp_resources.spec.chipset,
+ VramAddress::from_raw(gsp_static_info.total_fb_end),
+ )?,
})
}
}
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index ffc25fd8c47b..eea1c9ed4684 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -216,6 +216,8 @@ pub(crate) struct GetGspStaticInfoReply {
gpu_name: [u8; 64],
/// Usable FB (VRAM) regions for driver memory allocation.
pub(crate) usable_fb_regions: KVec<Range<u64>>,
+ /// Exclusive end of the FB physical address space.
+ pub(crate) total_fb_end: u64,
}
impl MessageFromGsp for GetGspStaticInfoReply {
@@ -231,10 +233,12 @@ fn read(
for region in msg.usable_fb_regions() {
usable_fb_regions.push(region, GFP_KERNEL)?;
}
+ let total_fb_end = msg.total_fb_end().ok_or(EINVAL)?;
Ok(GetGspStaticInfoReply {
gpu_name: msg.gpu_name_str(),
usable_fb_regions,
+ total_fb_end,
})
}
}
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 6dc31d1bf5ae..6e85442a4b13 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -165,6 +165,11 @@ pub(crate) fn usable_fb_regions(&self) -> impl Iterator<Item = Range<u64>> + '_
}
})
}
+
+ /// Computes the exclusive end of the FB physical address space.
+ pub(crate) fn total_fb_end(&self) -> Option<u64> {
+ self.fb_regions().map(|reg| reg.limit).max()?.checked_add(1)
+ }
}
// SAFETY: Padding is explicit and will not contain uninitialized data.
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index ef5b1cad56c3..58dce211a337 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -19,10 +19,45 @@
},
};
+use crate::{
+ driver::Bar0,
+ gpu::Chipset, //
+};
+
mod hal;
mod pramin;
mod regs;
+/// GPU Memory Manager - owns all core MM components.
+///
+/// Provides centralized ownership of memory management resources:
+/// - [`pramin::Pramin`] for direct VRAM access.
+pub(crate) struct GpuMm<'gpu> {
+ pramin: pramin::Pramin<'gpu>,
+}
+
+impl<'gpu> GpuMm<'gpu> {
+ /// Creates the GPU memory manager.
+ pub(crate) fn new(
+ bar: Bar0<'gpu>,
+ chipset: Chipset,
+ total_fb_end: VramAddress,
+ ) -> Result<Self> {
+ // PRAMIN covers all physical VRAM (including GSP-reserved areas
+ // above the usable region, e.g. the BAR1 page directory).
+ let vram_region = VramAddress::ZERO..total_fb_end;
+
+ Ok(Self {
+ pramin: pramin::Pramin::new(bar, chipset, vram_region)?,
+ })
+ }
+
+ /// Access the [`pramin::Pramin`].
+ fn pramin_mut(&mut self) -> &mut pramin::Pramin<'gpu> {
+ &mut self.pramin
+ }
+}
+
/// Physical VRAM address in GPU video memory.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 09/10] gpu: nova-core: Add self-test assertion macros and config option
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (7 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 08/10] gpu: nova-core: mm: Add GpuMm centralized memory manager Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 10/10] gpu: nova-core: mm: Add PRAMIN aperture self-tests Eliot Courtney
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney
The existing assert! and assert_eq! macros cause a panic. For self tests
in nova-core, it's inconvenient to cause a panic since these need to be
run on actual hardware. Instead, define similar macros that log an error
then return an Err.
Also add the NOVA_CORE_SELFTESTS Kconfig option that gates the driver
self-tests.
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/Kconfig | 9 ++++++
drivers/gpu/nova-core/nova_core.rs | 2 ++
drivers/gpu/nova-core/selftest.rs | 64 ++++++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+)
diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig
index f918f69e0599..cb7f0b00f796 100644
--- a/drivers/gpu/nova-core/Kconfig
+++ b/drivers/gpu/nova-core/Kconfig
@@ -15,3 +15,12 @@ config NOVA_CORE
This driver is work in progress and may not be functional.
If M is selected, the module will be called nova-core.
+
+config NOVA_CORE_SELFTESTS
+ bool "Nova Core driver self-tests"
+ depends on NOVA_CORE
+ default n
+ help
+ Build the driver self-tests and run them when the GPU is probed.
+
+ If unsure, say N.
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 8f59cfa97017..1133c6ce5c55 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -23,6 +23,8 @@
mod num;
mod regs;
mod sbuffer;
+#[cfg(CONFIG_NOVA_CORE_SELFTESTS)]
+mod selftest;
mod vbios;
mod vgpu;
diff --git a/drivers/gpu/nova-core/selftest.rs b/drivers/gpu/nova-core/selftest.rs
new file mode 100644
index 000000000000..f5b5965b7e6a
--- /dev/null
+++ b/drivers/gpu/nova-core/selftest.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+//! Assertion macros for driver self-tests.
+//!
+//! Self-tests run against live hardware during probe, so a failed assertion should not panic. These
+//! macros log the failure on the device and fail the enclosing test by returning
+//! [`EIO`](kernel::error::code::EIO) instead.
+
+/// Like [`assert!`], but logs the failure via `dev` and fails the enclosing test instead of
+/// panicking.
+///
+/// As with [`assert!`], a custom message with format arguments can follow the condition.
+#[macro_export]
+macro_rules! selftest_assert {
+ ($dev:expr, $cond:expr $(,)?) => {
+ $crate::selftest_assert!($dev, $cond, "assertion failed: {}", ::core::stringify!($cond))
+ };
+ ($dev:expr, $cond:expr, $($arg:tt)+) => {{
+ if !$cond {
+ ::kernel::dev_err!(
+ $dev,
+ "Selftest: {}:{}: {}\n",
+ ::core::file!(),
+ ::core::line!(),
+ ::kernel::prelude::fmt!($($arg)+)
+ );
+ return Err(::kernel::error::code::EIO);
+ }
+ }};
+}
+
+/// Like [`assert_eq!`], but logs the failure via `dev` and fails the enclosing test instead of
+/// panicking.
+///
+/// As with [`assert_eq!`], a custom message with format arguments can follow the compared values.
+#[macro_export]
+macro_rules! selftest_assert_eq {
+ ($dev:expr, $left:expr, $right:expr $(,)?) => {
+ match (&$left, &$right) {
+ (left, right) => $crate::selftest_assert!(
+ $dev,
+ left == right,
+ "assertion `{} == {}` failed: left {:?}, right {:?}",
+ ::core::stringify!($left),
+ ::core::stringify!($right),
+ left,
+ right
+ ),
+ }
+ };
+ ($dev:expr, $left:expr, $right:expr, $($arg:tt)+) => {
+ match (&$left, &$right) {
+ (left, right) => $crate::selftest_assert!(
+ $dev,
+ left == right,
+ "assertion `left == right` failed: {}: left {:?}, right {:?}",
+ ::kernel::prelude::fmt!($($arg)+),
+ left,
+ right
+ ),
+ }
+ };
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 10/10] gpu: nova-core: mm: Add PRAMIN aperture self-tests
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
` (8 preceding siblings ...)
2026-08-27 8:51 ` [PATCH v3 09/10] gpu: nova-core: Add self-test assertion macros and config option Eliot Courtney
@ 2026-08-27 8:51 ` Eliot Courtney
9 siblings, 0 replies; 11+ messages in thread
From: Eliot Courtney @ 2026-08-27 8:51 UTC (permalink / raw)
To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Jonathan Corbet, Shuah Khan
Cc: John Hubbard, Alistair Popple, Timur Tabi, rust-for-linux,
linux-kernel, nova-gpu, dri-devel, linux-doc, Eliot Courtney,
Joel Fernandes
From: Joel Fernandes <joelagnelf@nvidia.com>
Add self-tests for the PRAMIN aperture mechanism to verify correct
operation during GPU probe. The tests validate various alignment
requirements and corner cases.
The tests are default disabled and behind CONFIG_NOVA_CORE_SELFTESTS.
When enabled, tests run after GSP boot during probe.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[ecourtney: convert the tests to window_at(), macros, and the new types]
[ecourtney: cfg-gate the tests and expect(dead_code), not a runtime no-op]
[ecourtney: run the self-tests on all architectures, drop the chipset arg]
[ecourtney: test within a usable FB region, skip when none is large enough]
[ecourtney: report failures without failing probe, start banner at dev_dbg]
[ecourtney: removed the mm-specific Kconfig option]
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
drivers/gpu/nova-core/driver.rs | 3 +
drivers/gpu/nova-core/gpu.rs | 12 ++++
drivers/gpu/nova-core/mm.rs | 40 ++++++++++-
drivers/gpu/nova-core/mm/pramin.rs | 134 +++++++++++++++++++++++++++++++++++++
4 files changed, 188 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index cf3534dd47d4..8cef4c284277 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -86,6 +86,9 @@ fn probe<'bound>(
// (`try_pin_init!()` initializes fields in declaration order), lives at a pinned
// stable address, and is dropped after `gpu` (struct field drop order).
gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }),
+ // Run optional GPU selftests.
+ #[cfg(CONFIG_NOVA_CORE_SELFTESTS)]
+ _: { gpu.run_selftests(pdev) },
_reg: auxiliary::Registration::new(
pdev.as_ref(),
c"nova-drm",
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 7b3e378c429b..f0cba7336b29 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -429,4 +429,16 @@ pub(crate) fn new<'a>(
)?,
})
}
+
+ /// Runs self-tests on the constructed [`Gpu`], logging failures without failing probe.
+ #[cfg(CONFIG_NOVA_CORE_SELFTESTS)]
+ pub(crate) fn run_selftests(self: Pin<&mut Self>, pdev: &pci::Device<device::Bound>) {
+ let this = self.project();
+ let dev = pdev.as_ref();
+ let regions = &this.gsp_static_info.usable_fb_regions;
+
+ if let Err(err) = crate::mm::selftest::run(dev, this.mm, regions) {
+ dev_err!(dev, "self-tests failed: {:?}\n", err);
+ }
+ }
}
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index 58dce211a337..9e4338c7c393 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -3,7 +3,7 @@
//! Memory management subsystems.
-#![expect(dead_code)]
+#![cfg_attr(not(CONFIG_NOVA_CORE_SELFTESTS), expect(dead_code))]
use core::{
fmt::LowerHex,
@@ -123,3 +123,41 @@ fn sub(self, rhs: Self) -> Self::Output {
self.into_raw() - rhs.into_raw()
}
}
+
+#[cfg(CONFIG_NOVA_CORE_SELFTESTS)]
+pub(crate) mod selftest {
+ use core::ops::Range;
+
+ use kernel::{
+ device,
+ sizes::SizeConstants, //
+ };
+
+ use super::*;
+
+ /// Run MM subsystem self-tests during probe.
+ pub(crate) fn run(
+ dev: &device::Device<device::Bound>,
+ mm: &mut GpuMm<'_>,
+ usable_fb_regions: &[Range<u64>],
+ ) -> Result {
+ // VRAM span the self-tests are free to overwrite, from the chosen test base.
+ const SELFTEST_SPAN: u64 = u64::SZ_64M;
+
+ let base = usable_fb_regions.iter().find_map(|region| {
+ // Tests rely on this being 8 byte aligned for checking misalignment handling.
+ let base = region.start.align_up(Alignment::new::<8>())?;
+ (base.checked_add(SELFTEST_SPAN)? <= region.end).then_some(base)
+ });
+ let Some(base) = base else {
+ dev_warn!(
+ dev,
+ "PRAMIN: skipping self-tests, no usable VRAM region of {:#x} bytes\n",
+ SELFTEST_SPAN
+ );
+ return Ok(());
+ };
+
+ pramin::selftest::run(dev, mm.pramin_mut(), VramAddress::from_raw(base))
+ }
+}
diff --git a/drivers/gpu/nova-core/mm/pramin.rs b/drivers/gpu/nova-core/mm/pramin.rs
index 20be3fc471ba..7f89c093d591 100644
--- a/drivers/gpu/nova-core/mm/pramin.rs
+++ b/drivers/gpu/nova-core/mm/pramin.rs
@@ -176,3 +176,137 @@ pub(super) fn window_at<'a, T>(
Ok(PraminAccess { view })
}
}
+
+#[cfg(CONFIG_NOVA_CORE_SELFTESTS)]
+pub(super) mod selftest {
+ use kernel::{
+ device,
+ io::io_read,
+ sizes::SizeConstants, //
+ };
+
+ use super::*;
+ use crate::{
+ selftest_assert,
+ selftest_assert_eq, //
+ };
+
+ /// Test read/write at byte granularity, at unaligned addresses.
+ fn test_byte_readwrite(
+ dev: &device::Device<device::Bound>,
+ pramin: &mut Pramin<'_>,
+ base: VramAddress,
+ ) -> Result {
+ for i in 0u8..4 {
+ let addr = base + 1 + u64::from(i);
+ pramin.window_at::<u8>(addr)?.view().write_val(0xA0 + i);
+ }
+
+ for i in 0u8..4 {
+ let addr = base + 1 + u64::from(i);
+ selftest_assert_eq!(
+ dev,
+ pramin.window_at::<u8>(addr)?.view().read_val(),
+ 0xA0 + i
+ );
+ }
+ Ok(())
+ }
+
+ /// Test writing a `u32` and reading back as individual `u8`s.
+ fn test_u32_as_bytes(
+ dev: &device::Device<device::Bound>,
+ pramin: &mut Pramin<'_>,
+ base: VramAddress,
+ ) -> Result {
+ let addr = base + 0x10;
+ let val: u32 = 0xDEADBEEF;
+ pramin.window_at::<u32>(addr)?.view().write_val(val);
+
+ let window = pramin.window_at::<[u8; 4]>(addr)?;
+ for (i, &expected) in val.to_le_bytes().iter().enumerate() {
+ selftest_assert_eq!(dev, io_read!(window.view(), [build: i]), expected);
+ }
+ Ok(())
+ }
+
+ /// Test window repositioning across 1 MiB boundaries.
+ fn test_window_reposition(
+ dev: &device::Device<device::Bound>,
+ pramin: &mut Pramin<'_>,
+ base: VramAddress,
+ ) -> Result {
+ let addr_a = base;
+ let addr_b = base + u64::SZ_2M; // base + 2 MiB (different 1 MiB region).
+ let val_a: u32 = 0x11111111;
+ let val_b: u32 = 0x22222222;
+
+ pramin.window_at::<u32>(addr_a)?.view().write_val(val_a);
+ pramin.window_at::<u32>(addr_b)?.view().write_val(val_b);
+
+ selftest_assert_eq!(
+ dev,
+ pramin.window_at::<u32>(addr_a)?.view().read_val(),
+ val_a
+ );
+ selftest_assert_eq!(
+ dev,
+ pramin.window_at::<u32>(addr_b)?.view().read_val(),
+ val_b
+ );
+ Ok(())
+ }
+
+ /// Test that offsets outside the VRAM region are rejected.
+ fn test_invalid_offset(
+ dev: &device::Device<device::Bound>,
+ pramin: &mut Pramin<'_>,
+ vram_end: VramAddress,
+ ) -> Result {
+ selftest_assert!(dev, pramin.window_at::<u32>(vram_end).is_err());
+ Ok(())
+ }
+
+ /// Test that misaligned accesses are rejected.
+ fn test_misaligned_access(
+ dev: &device::Device<device::Bound>,
+ pramin: &mut Pramin<'_>,
+ base: VramAddress,
+ ) -> Result {
+ // `u16` at odd offset (not 2-byte aligned).
+ selftest_assert!(dev, pramin.window_at::<u16>(base + 0x21).is_err());
+
+ // `u32` at 2-byte-aligned (not 4-byte-aligned) offset.
+ selftest_assert!(dev, pramin.window_at::<u32>(base + 2).is_err());
+
+ // `u64` at a 4-byte-aligned (not 8-byte-aligned) address.
+ selftest_assert!(dev, pramin.window_at::<u64>(base + 0x44).is_err());
+
+ // A `u16` view at an even address is allowed.
+ pramin.window_at::<u16>(base + 0x22)?;
+ Ok(())
+ }
+
+ /// Run PRAMIN self-tests during probe.
+ ///
+ /// `base` is the start of a driver-usable VRAM span that the tests are free to
+ /// overwrite.
+ pub(crate) fn run(
+ dev: &device::Device<device::Bound>,
+ pramin: &mut Pramin<'_>,
+ base: VramAddress,
+ ) -> Result {
+ dev_dbg!(dev, "PRAMIN: starting self-tests\n");
+
+ let vram_end = pramin.vram_range.end;
+
+ test_byte_readwrite(dev, pramin, base)?;
+ test_u32_as_bytes(dev, pramin, base)?;
+ test_window_reposition(dev, pramin, base)?;
+ test_invalid_offset(dev, pramin, vram_end)?;
+ test_misaligned_access(dev, pramin, base)?;
+
+ dev_info!(dev, "PRAMIN: self-tests passed\n");
+ Ok(())
+ }
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-08-27 8:52 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27 8:51 [PATCH v3 00/10] gpu: nova-core: add PRAMIN window support Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 01/10] gpu: nova-core: mm: Add VramAddress type Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 02/10] gpu: nova-core: mm: Implement Alignable and Debug for VramAddress Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 03/10] gpu: nova-core: mm: Add PRAMIN window registers Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 04/10] gpu: nova-core: mm: Add the memory management HAL Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 05/10] rust: io: add static `cast()` method for views Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 06/10] gpu: nova-core: mm: Add support to use PRAMIN windows to write to VRAM Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 07/10] docs: gpu: nova-core: Document the PRAMIN aperture mechanism Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 08/10] gpu: nova-core: mm: Add GpuMm centralized memory manager Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 09/10] gpu: nova-core: Add self-test assertion macros and config option Eliot Courtney
2026-08-27 8:51 ` [PATCH v3 10/10] gpu: nova-core: mm: Add PRAMIN aperture self-tests Eliot Courtney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox