[PATCH v11 02/22] gpu: nova-core: Hopper/Blackwell: new location for PCI config mirror
From: John Hubbard
Date: Fri May 29 2026 - 23:15:38 EST
Hopper and Blackwell GPUs moved the PCI config space mirror from
0x088000 to 0x092000. Select the correct address per architecture
when building the GSP system info command.
Co-developed-by: Alexandre Courbot <acourbot@xxxxxxxxxx>
Signed-off-by: Alexandre Courbot <acourbot@xxxxxxxxxx>
Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
---
drivers/gpu/nova-core/gpu.rs | 7 +++++++
drivers/gpu/nova-core/gpu/hal.rs | 5 +++++
drivers/gpu/nova-core/gpu/hal/gh100.rs | 9 +++++++++
drivers/gpu/nova-core/gpu/hal/tu102.rs | 9 +++++++++
drivers/gpu/nova-core/gsp/boot.rs | 2 +-
drivers/gpu/nova-core/gsp/commands.rs | 8 +++++---
drivers/gpu/nova-core/gsp/fw/commands.rs | 15 +++++++++++----
7 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 38c75df77e16..7dd736e5b190 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
+use core::ops::Range;
+
use kernel::{
device,
dma::Device,
@@ -134,6 +136,11 @@ pub(crate) const fn arch(self) -> Architecture {
pub(crate) const fn needs_fwsec_bootloader(self) -> bool {
matches!(self.arch(), Architecture::Turing) || matches!(self, Self::GA100)
}
+
+ /// Returns the address range of the PCI config mirror space.
+ pub(crate) fn pci_config_mirror_range(self) -> Range<u32> {
+ hal::gpu_hal(self).pci_config_mirror_range()
+ }
}
// TODO
diff --git a/drivers/gpu/nova-core/gpu/hal.rs b/drivers/gpu/nova-core/gpu/hal.rs
index 0b636b713593..cd833bd49b9b 100644
--- a/drivers/gpu/nova-core/gpu/hal.rs
+++ b/drivers/gpu/nova-core/gpu/hal.rs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
+use core::ops::Range;
+
use kernel::{
dma::DmaMask,
prelude::*, //
@@ -22,6 +24,9 @@ pub(crate) trait GpuHal {
/// Returns the DMA mask for the current architecture.
fn dma_mask(&self) -> DmaMask;
+
+ /// Returns the address range of the PCI config mirror space.
+ fn pci_config_mirror_range(&self) -> Range<u32>;
}
pub(super) fn gpu_hal(chipset: Chipset) -> &'static dyn GpuHal {
diff --git a/drivers/gpu/nova-core/gpu/hal/gh100.rs b/drivers/gpu/nova-core/gpu/hal/gh100.rs
index 41fbabb04ff8..17778a618900 100644
--- a/drivers/gpu/nova-core/gpu/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gpu/hal/gh100.rs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
+use core::ops::Range;
+
use kernel::{
dma::DmaMask,
prelude::*, //
@@ -19,6 +21,13 @@ fn wait_gfw_boot_completion(&self, _bar: &Bar0) -> Result {
fn dma_mask(&self) -> DmaMask {
DmaMask::new::<52>()
}
+
+ fn pci_config_mirror_range(&self) -> Range<u32> {
+ const PCI_CONFIG_MIRROR_START: u32 = 0x092000;
+ const PCI_CONFIG_MIRROR_SIZE: u32 = 0x001000;
+
+ PCI_CONFIG_MIRROR_START..PCI_CONFIG_MIRROR_START + PCI_CONFIG_MIRROR_SIZE
+ }
}
const GH100: Gh100 = Gh100;
diff --git a/drivers/gpu/nova-core/gpu/hal/tu102.rs b/drivers/gpu/nova-core/gpu/hal/tu102.rs
index 2881ab03dbcd..125478bfe07a 100644
--- a/drivers/gpu/nova-core/gpu/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gpu/hal/tu102.rs
@@ -18,6 +18,8 @@
//!
//! Note that the devinit sequence also needs to run during suspend/resume.
+use core::ops::Range;
+
use kernel::{
dma::DmaMask,
io::{
@@ -85,6 +87,13 @@ fn wait_gfw_boot_completion(&self, bar: &Bar0) -> Result {
fn dma_mask(&self) -> DmaMask {
DmaMask::new::<47>()
}
+
+ fn pci_config_mirror_range(&self) -> Range<u32> {
+ const PCI_CONFIG_MIRROR_START: u32 = 0x088000;
+ const PCI_CONFIG_MIRROR_SIZE: u32 = 0x001000;
+
+ PCI_CONFIG_MIRROR_START..PCI_CONFIG_MIRROR_START + PCI_CONFIG_MIRROR_SIZE
+ }
}
const TU102: Tu102 = Tu102;
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 087ee59da6d9..8c316fa2e585 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -144,7 +144,7 @@ pub(crate) fn boot(
dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
self.cmdq
- .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev))?;
+ .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
self.cmdq
.send_command_no_wait(bar, commands::SetRegistry::new())?;
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 3a365455d10c..f84de9f4f045 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -19,6 +19,7 @@
};
use crate::{
+ gpu::Chipset,
gsp::{
cmdq::{
Cmdq,
@@ -37,12 +38,13 @@
/// The `GspSetSystemInfo` command.
pub(crate) struct SetSystemInfo<'a> {
pdev: &'a pci::Device<device::Bound>,
+ chipset: Chipset,
}
impl<'a> SetSystemInfo<'a> {
/// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`.
- pub(crate) fn new(pdev: &'a pci::Device<device::Bound>) -> Self {
- Self { pdev }
+ pub(crate) fn new(pdev: &'a pci::Device<device::Bound>, chipset: Chipset) -> Self {
+ Self { pdev, chipset }
}
}
@@ -53,7 +55,7 @@ impl<'a> CommandToGsp for SetSystemInfo<'a> {
type InitError = Error;
fn init(&self) -> impl Init<Self::Command, Self::InitError> {
- Self::Command::init(self.pdev)
+ Self::Command::init(self.pdev, self.chipset)
}
}
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 42985d446bae..7bcc41fc7fa0 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -11,7 +11,10 @@
}, //
};
-use crate::gsp::GSP_PAGE_SIZE;
+use crate::{
+ gpu::Chipset,
+ gsp::GSP_PAGE_SIZE, //
+};
use super::bindings;
@@ -25,8 +28,12 @@ pub(crate) struct GspSetSystemInfo {
impl GspSetSystemInfo {
/// Returns an in-place initializer for the `GspSetSystemInfo` command.
#[allow(non_snake_case)]
- pub(crate) fn init<'a>(dev: &'a pci::Device<device::Bound>) -> impl Init<Self, Error> + 'a {
+ pub(crate) fn init<'a>(
+ dev: &'a pci::Device<device::Bound>,
+ chipset: Chipset,
+ ) -> impl Init<Self, Error> + 'a {
type InnerGspSystemInfo = bindings::GspSystemInfo;
+ let pci_config_mirror_range = chipset.pci_config_mirror_range();
let init_inner = try_init!(InnerGspSystemInfo {
gpuPhysAddr: dev.resource_start(0)?,
gpuPhysFbAddr: dev.resource_start(1)?,
@@ -36,8 +43,8 @@ pub(crate) fn init<'a>(dev: &'a pci::Device<device::Bound>) -> impl Init<Self, E
// Using TASK_SIZE in r535_gsp_rpc_set_system_info() seems wrong because
// TASK_SIZE is per-task. That's probably a design issue in GSP-RM though.
maxUserVa: (1 << 47) - 4096,
- pciConfigMirrorBase: 0x088000,
- pciConfigMirrorSize: 0x001000,
+ pciConfigMirrorBase: pci_config_mirror_range.start,
+ pciConfigMirrorSize: pci_config_mirror_range.end - pci_config_mirror_range.start,
PCIDeviceID: (u32::from(dev.device_id()) << 16) | u32::from(dev.vendor_id().as_raw()),
PCISubDeviceID: (u32::from(dev.subsystem_device_id()) << 16)
--
2.54.0