[PATCH v2 13/21] gpu: nova-core: register sysmem flush page

Alexandre Courbot
2025-05-01T12:59:34Z

A page of system memory is reserved so sysmembar can perform a read on
it if a system write occurred since the last flush. Do this early as it
can be required to e.g. reset the GPU falcons.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/gpu/nova-core/gpu.rs | 51 +++++++++++++++++++++++++++++++++++++++++--
drivers/gpu/nova-core/regs.rs | 10 +++++++++
2 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index ac246d08141e95927a25cada4ecb7e23156ac6b4..08302967375274fd88bb9b4fef4969e79e82f3b4 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -3,6 +3,7 @@
use kernel::{device, devres::Devres, error::code::*, pci, prelude::*};

use crate::devinit;
+use crate::dma::DmaObject;
use crate::driver::Bar0;
use crate::firmware::Firmware;
use crate::regs;
@@ -158,12 +159,32 @@ fn new(bar: &Devres<Bar0>) -> Result<Spec> {
}

/// Structure holding the resources required to operate the GPU.
-#[pin_data]
+#[pin_data(PinnedDrop)]
pub(crate) struct Gpu {
spec: Spec,
/// MMIO mapping of PCI BAR 0
bar: Devres<Bar0>,
fw: Firmware,
+ // System memory page required for flushing all pending GPU-side memory writes done through
+ // PCIE into system memory.
+ sysmem_flush: DmaObject,
+}
+
+#[pinned_drop]
+impl PinnedDrop for Gpu {
+ fn drop(self: Pin<&mut Self>) {
+ // Unregister the sysmem flush page before we release it.
+ let _ = with_bar!(&self.bar, |b| {
+ regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default()
+ .set_adr_39_08(0)
+ .write(b);
+ if self.spec.chipset >= Chipset::GA102 {
+ regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default()
+ .set_adr_63_40(0)
+ .write(b);
+ }
+ });
+ }
}

impl Gpu {
@@ -186,6 +207,32 @@ pub(crate) fn new(
devinit::wait_gfw_boot_completion(&bar)
.inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?;

- Ok(pin_init!(Self { spec, bar, fw }))
+ // System memory page required for sysmembar to properly flush into system memory.
+ let sysmem_flush = {
+ let page = DmaObject::new(pdev.as_ref(), kernel::bindings::PAGE_SIZE)?;
+
+ // Register the sysmem flush page.
+ with_bar!(bar, |b| {
+ let handle = page.dma_handle();
+
+ regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default()
+ .set_adr_39_08((handle >> 8) as u32)
+ .write(b);
+ if spec.chipset >= Chipset::GA102 {
+ regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default()
+ .set_adr_63_40((handle >> 40) as u32)
+ .write(b);
+ }
+ })?;
+
+ page
+ };
+
+ Ok(pin_init!(Self {
+ spec,
+ bar,
+ fw,
+ sysmem_flush,
+ }))
}
}
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 401d885539cee03cbe732102f5e2233785a7b284..218cb6441eb0e5c6e5b52eabba006163eec0c8b4 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -39,6 +39,16 @@ pub(crate) fn chipset(self) -> Result<Chipset, Error> {
}
}

+/* PFB */
+
+register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 {
+ 31:0 adr_39_08 as u32;
+});
+
+register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 {
+ 23:0 adr_63_40 as u32;
+});
+
/* PGC6 */

register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128 {

--
2.49.0