[PATCH REF 21/24] gpu: nova-core: use HRT lifetime for Bar

Danilo Krummrich
2026-04-27T22:14:20Z

Take advantage of the lifetime-parameterized pci::Bar<'a> to hold the
BAR mapping directly in NovaCore<'a>, and pass a borrowed reference to
Gpu<'a>.

This eliminates the Arc<Devres<Bar0>> indirection, removes runtime
revocation checks for BAR access, and simplifies Gpu::unbind().

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/gpu/nova-core/driver.rs | 40 ++++++++++++++----------------
drivers/gpu/nova-core/gpu.rs | 27 ++++++++------------
drivers/gpu/nova-core/nova_core.rs | 2 +-
3 files changed, 30 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 149a20748e86..ec9cecb30f63 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -14,12 +14,9 @@
},
prelude::*,
sizes::SZ_16M,
- sync::{
- atomic::{
- Atomic,
- Relaxed, //
- },
- Arc,
+ sync::atomic::{
+ Atomic,
+ Relaxed, //
},
types::ForLt,
};
@@ -30,9 +27,10 @@
static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0);

#[pin_data]
-pub(crate) struct NovaCore {
+pub(crate) struct NovaCore<'a> {
#[pin]
- pub(crate) gpu: Gpu,
+ pub(crate) gpu: Gpu<'a>,
+ bar: pci::Bar<'a, BAR0_SIZE>,
#[allow(clippy::type_complexity)]
_reg: Devres<auxiliary::Registration<ForLt!(())>>,
}
@@ -47,12 +45,12 @@ pub(crate) struct NovaCore {
// DMA addresses. These systems should be quite rare.
const GPU_DMA_BITS: u32 = 47;

-pub(crate) type Bar0 = pci::Bar<'static, BAR0_SIZE>;
+pub(crate) type Bar0 = kernel::io::Mmio<BAR0_SIZE>;

kernel::pci_device_table!(
PCI_TABLE,
MODULE_PCI_TABLE,
- <NovaCore as pci::Driver<'_>>::IdInfo,
+ <NovaCore<'_> as pci::Driver<'_>>::IdInfo,
[
// Modern NVIDIA GPUs will show up as either VGA or 3D controllers.
(
@@ -74,7 +72,7 @@ pub(crate) struct NovaCore {
]
);

-impl<'a> pci::Driver<'a> for NovaCore {
+impl<'a> pci::Driver<'a> for NovaCore<'a> {
type IdInfo = ();
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;

@@ -93,14 +91,14 @@ fn probe(
// other threads of execution.
unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? };

- let bar = Arc::new(
- pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?
- .into_devres()?,
- GFP_KERNEL,
- )?;
-
- Ok(try_pin_init!(Self {
- gpu <- Gpu::new(pdev, bar.clone(), bar.access(pdev.as_ref())?),
+ Ok(try_pin_init!(NovaCore {
+ bar: pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?,
+ // TODO: Use `&bar` self-referential pin-init syntax once available.
+ //
+ // SAFETY: `bar` is initialized before this expression is evaluated
+ // (`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) }),
_reg: auxiliary::Registration::new(
pdev.as_ref(),
c"nova-drm",
@@ -114,7 +112,7 @@ fn probe(
})
}

- fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) {
- this.gpu.unbind(pdev.as_ref());
+ fn unbind(_pdev: &'a pci::Device<Core>, this: Pin<&'a Self>) {
+ this.gpu.unbind();
}
}
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 0f6fe9a1b955..922197f2aeef 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -2,13 +2,11 @@

use kernel::{
device,
- devres::Devres,
fmt,
io::Io,
num::Bounded,
pci,
- prelude::*,
- sync::Arc, //
+ prelude::*, //
};

use crate::{
@@ -224,10 +222,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

/// Structure holding the resources required to operate the GPU.
#[pin_data]
-pub(crate) struct Gpu {
+pub(crate) struct Gpu<'a> {
spec: Spec,
- /// MMIO mapping of PCI BAR 0
- bar: Arc<Devres<Bar0>>,
+ /// MMIO mapping of PCI BAR 0.
+ bar: &'a Bar0,
/// System memory page required for flushing all pending GPU-side memory writes done through
/// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
sysmem_flush: SysmemFlush,
@@ -240,10 +238,9 @@ pub(crate) struct Gpu {
gsp: Gsp,
}

-impl Gpu {
- pub(crate) fn new<'a>(
+impl<'a> Gpu<'a> {
+ pub(crate) fn new(
pdev: &'a pci::Device<device::Bound>,
- devres_bar: Arc<Devres<Bar0>>,
bar: &'a Bar0,
) -> impl PinInit<Self, Error> + 'a {
try_pin_init!(Self {
@@ -257,6 +254,8 @@ pub(crate) fn new<'a>(
.inspect_err(|_| dev_err!(pdev, "GFW boot did not complete\n"))?;
},

+ bar,
+
sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?,

gsp_falcon: Falcon::new(
@@ -270,19 +269,13 @@ pub(crate) fn new<'a>(
gsp <- Gsp::new(pdev),

_: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)? },
-
- bar: devres_bar,
})
}

/// Called when the corresponding [`Device`](device::Device) is unbound.
///
/// Note: This method must only be called from `Driver::unbind`.
- pub(crate) fn unbind(&self, dev: &device::Device<device::Core>) {
- kernel::warn_on!(self
- .bar
- .access(dev)
- .inspect(|bar| self.sysmem_flush.unregister(bar))
- .is_err());
+ pub(crate) fn unbind(&self) {
+ self.sysmem_flush.unregister(self.bar);
}
}
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 49c093a0cb42..ed5eb39c8201 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -49,7 +49,7 @@ struct NovaCoreModule {
// then `_debugfs_guard` clears `DEBUGFS_ROOT`.
#[allow(clippy::type_complexity)]
#[pin]
- _driver: Registration<pci::Adapter<ForLt!(driver::NovaCore)>>,
+ _driver: Registration<pci::Adapter<ForLt!(driver::NovaCore<'_>)>>,
_debugfs_guard: DebugfsRootGuard,
}

--
2.54.0