gpu: nova-core: convert PMC registers to kernel register macro

Convert all PMC registers to use the kernel's register macro and update
the code accordingly.

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260325-b4-nova-register-v4-2-bdf172f0f6ca@nvidia.com
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
This commit is contained in:
Alexandre Courbot 2026-03-25 11:46:15 +09:00
parent b525d0c5e9
commit 1b155edcab
3 changed files with 53 additions and 57 deletions

View File

@ -13,7 +13,10 @@
DmaAddress,
DmaMask, //
},
io::poll::read_poll_timeout,
io::{
poll::read_poll_timeout,
Io, //
},
prelude::*,
sync::aref::ARef,
time::Delta,
@ -531,7 +534,7 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result {
self.hal.reset_wait_mem_scrubbing(bar)?;
regs::NV_PFALCON_FALCON_RM::default()
.set_value(regs::NV_PMC_BOOT_0::read(bar).into())
.set_value(bar.read(regs::NV_PMC_BOOT_0).into())
.write(bar, &E::ID);
Ok(())

View File

@ -4,12 +4,15 @@
device,
devres::Devres,
fmt,
io::Io,
num::Bounded,
pci,
prelude::*,
sync::Arc, //
};
use crate::{
bounded_enum,
driver::Bar0,
falcon::{
gsp::Gsp as GspFalcon,
@ -128,50 +131,26 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
/// Enum representation of the GPU generation.
///
/// TODO: remove the `Default` trait implementation, and the `#[default]`
/// attribute, once the register!() macro (which creates Architecture items) no
/// longer requires it for read-only fields.
#[derive(fmt::Debug, Default, Copy, Clone)]
#[repr(u8)]
pub(crate) enum Architecture {
#[default]
Turing = 0x16,
Ampere = 0x17,
Ada = 0x19,
}
impl TryFrom<u8> for Architecture {
type Error = Error;
fn try_from(value: u8) -> Result<Self> {
match value {
0x16 => Ok(Self::Turing),
0x17 => Ok(Self::Ampere),
0x19 => Ok(Self::Ada),
_ => Err(ENODEV),
}
}
}
impl From<Architecture> for u8 {
fn from(value: Architecture) -> Self {
// CAST: `Architecture` is `repr(u8)`, so this cast is always lossless.
value as u8
bounded_enum! {
/// Enum representation of the GPU generation.
#[derive(fmt::Debug, Copy, Clone)]
pub(crate) enum Architecture with TryFrom<Bounded<u32, 6>> {
Turing = 0x16,
Ampere = 0x17,
Ada = 0x19,
}
}
pub(crate) struct Revision {
major: u8,
minor: u8,
major: Bounded<u8, 4>,
minor: Bounded<u8, 4>,
}
impl From<regs::NV_PMC_BOOT_42> for Revision {
fn from(boot0: regs::NV_PMC_BOOT_42) -> Self {
Self {
major: boot0.major_revision(),
minor: boot0.minor_revision(),
major: boot0.major_revision().cast(),
minor: boot0.minor_revision().cast(),
}
}
}
@ -208,13 +187,13 @@ fn new(dev: &device::Device, bar: &Bar0) -> Result<Spec> {
// from an earlier (pre-Fermi) era, and then using boot42 to precisely identify the GPU.
// Somewhere in the Rubin timeframe, boot0 will no longer have space to add new GPU IDs.
let boot0 = regs::NV_PMC_BOOT_0::read(bar);
let boot0 = bar.read(regs::NV_PMC_BOOT_0);
if boot0.is_older_than_fermi() {
return Err(ENODEV);
}
let boot42 = regs::NV_PMC_BOOT_42::read(bar);
let boot42 = bar.read(regs::NV_PMC_BOOT_42);
Spec::try_from(boot42).inspect_err(|_| {
dev_err!(dev, "Unsupported chipset: {}\n", boot42);
})

View File

@ -8,6 +8,7 @@
pub(crate) mod macros;
use kernel::{
io,
prelude::*,
time, //
};
@ -37,18 +38,38 @@
// PMC
register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the GPU" {
3:0 minor_revision as u8, "Minor revision of the chip";
7:4 major_revision as u8, "Major revision of the chip";
8:8 architecture_1 as u8, "MSB of the architecture";
23:20 implementation as u8, "Implementation version of the architecture";
28:24 architecture_0 as u8, "Lower bits of the architecture";
});
io::register! {
/// Basic revision information about the GPU.
pub(crate) NV_PMC_BOOT_0(u32) @ 0x00000000 {
/// Lower bits of the architecture.
28:24 architecture_0;
/// Implementation version of the architecture.
23:20 implementation;
/// MSB of the architecture.
8:8 architecture_1;
/// Major revision of the chip.
7:4 major_revision;
/// Minor revision of the chip.
3:0 minor_revision;
}
/// Extended architecture information.
pub(crate) NV_PMC_BOOT_42(u32) @ 0x00000a00 {
/// Architecture value.
29:24 architecture ?=> Architecture;
/// Implementation version of the architecture.
23:20 implementation;
/// Major revision of the chip.
19:16 major_revision;
/// Minor revision of the chip.
15:12 minor_revision;
}
}
impl NV_PMC_BOOT_0 {
pub(crate) fn is_older_than_fermi(self) -> bool {
// From https://github.com/NVIDIA/open-gpu-doc/tree/master/manuals :
const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u8 = 0xc;
const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u32 = 0xc;
// Older chips left arch1 zeroed out. That, combined with an arch0 value that is less than
// GF100, means "older than Fermi".
@ -56,13 +77,6 @@ pub(crate) fn is_older_than_fermi(self) -> bool {
}
}
register!(NV_PMC_BOOT_42 @ 0x00000a00, "Extended architecture information" {
15:12 minor_revision as u8, "Minor revision of the chip";
19:16 major_revision as u8, "Major revision of the chip";
23:20 implementation as u8, "Implementation version of the architecture";
29:24 architecture as u8 ?=> Architecture, "Architecture value";
});
impl NV_PMC_BOOT_42 {
/// Combines `architecture` and `implementation` to obtain a code unique to the chipset.
pub(crate) fn chipset(self) -> Result<Chipset> {
@ -76,8 +90,8 @@ pub(crate) fn chipset(self) -> Result<Chipset> {
/// Returns the raw architecture value from the register.
fn architecture_raw(self) -> u8 {
((self.0 >> Self::ARCHITECTURE_RANGE.start()) & ((1 << Self::ARCHITECTURE_RANGE.len()) - 1))
as u8
((self.into_raw() >> Self::ARCHITECTURE_RANGE.start())
& ((1 << Self::ARCHITECTURE_RANGE.len()) - 1)) as u8
}
}
@ -86,7 +100,7 @@ fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> kernel::fmt::Result {
write!(
f,
"boot42 = 0x{:08x} (architecture 0x{:x}, implementation 0x{:x})",
self.0,
self.inner,
self.architecture_raw(),
self.implementation()
)