diff options
| -rw-r--r-- | drivers/gpu/nova-core/gpu.rs | 36 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/regs.rs | 21 |
2 files changed, 45 insertions, 12 deletions
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 88a6d7af9f37..3e3375f8fe99 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -160,8 +160,8 @@ pub(crate) struct Revision { minor: u8, } -impl From<regs::NV_PMC_BOOT_0> for Revision { - fn from(boot0: regs::NV_PMC_BOOT_0) -> Self { +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(), @@ -183,19 +183,41 @@ pub(crate) struct Spec { impl Spec { fn new(bar: &Bar0) -> Result<Spec> { + // Some brief notes about boot0 and boot42, in chronological order: + // + // NV04 through NV50: + // + // Not supported by Nova. boot0 is necessary and sufficient to identify these GPUs. + // boot42 may not even exist on some of these GPUs. + // + // Fermi through Volta: + // + // Not supported by Nova. boot0 is still sufficient to identify these GPUs, but boot42 + // is also guaranteed to be both present and accurate. + // + // Turing and later: + // + // Supported by Nova. Identified by first checking boot0 to ensure that the GPU is not + // 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); - Spec::try_from(boot0) + if boot0.is_older_than_fermi() { + return Err(ENODEV); + } + + Spec::try_from(regs::NV_PMC_BOOT_42::read(bar)) } } -impl TryFrom<regs::NV_PMC_BOOT_0> for Spec { +impl TryFrom<regs::NV_PMC_BOOT_42> for Spec { type Error = Error; - fn try_from(boot0: regs::NV_PMC_BOOT_0) -> Result<Self> { + fn try_from(boot42: regs::NV_PMC_BOOT_42) -> Result<Self> { Ok(Self { - chipset: boot0.chipset()?, - revision: boot0.into(), + chipset: boot42.chipset()?, + revision: boot42.into(), }) } } diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index b32c07092f93..60b543ed254a 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -40,13 +40,24 @@ register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the GPU" }); impl NV_PMC_BOOT_0 { - /// Combines `architecture_0` and `architecture_1` to obtain the architecture of the chip. - pub(crate) fn architecture(self) -> Result<Architecture> { - Architecture::try_from( - self.architecture_0() | (self.architecture_1() << Self::ARCHITECTURE_0_RANGE.len()), - ) + 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; + + // Older chips left arch1 zeroed out. That, combined with an arch0 value that is less than + // GF100, means "older than Fermi". + self.architecture_1() == 0 && self.architecture_0() < NV_PMC_BOOT_0_ARCHITECTURE_GF100 } +} + +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> { self.architecture() |