diff options
Diffstat (limited to 'drivers/gpu/nova-core/gpu.rs')
| -rw-r--r-- | drivers/gpu/nova-core/gpu.rs | 115 |
1 files changed, 88 insertions, 27 deletions
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index af20e2daea24..629c9d2dc994 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -1,13 +1,26 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::{device, devres::Devres, error::code::*, fmt, pci, prelude::*, sync::Arc}; +use kernel::{ + device, + devres::Devres, + fmt, + pci, + prelude::*, + sync::Arc, // +}; -use crate::driver::Bar0; -use crate::falcon::{gsp::Gsp as GspFalcon, sec2::Sec2 as Sec2Falcon, Falcon}; -use crate::fb::SysmemFlush; -use crate::gfw; -use crate::gsp::Gsp; -use crate::regs; +use crate::{ + driver::Bar0, + falcon::{ + gsp::Gsp as GspFalcon, + sec2::Sec2 as Sec2Falcon, + Falcon, // + }, + fb::SysmemFlush, + gfw, + gsp::Gsp, + regs, +}; macro_rules! define_chipset { ({ $($variant:ident = $value:expr),* $(,)* }) => @@ -109,8 +122,14 @@ impl fmt::Display for Chipset { } /// Enum representation of the GPU generation. -#[derive(fmt::Debug)] +/// +/// 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, @@ -129,13 +148,20 @@ impl TryFrom<u8> for Architecture { } } +impl From<Architecture> for u8 { + fn from(value: Architecture) -> Self { + // CAST: `Architecture` is `repr(u8)`, so this cast is always lossless. + value as u8 + } +} + pub(crate) struct Revision { major: u8, minor: u8, } -impl Revision { - fn from_boot0(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(), @@ -149,24 +175,67 @@ impl fmt::Display for Revision { } } -/// Structure holding the metadata of the GPU. +/// Structure holding a basic description of the GPU: `Chipset` and `Revision`. pub(crate) struct Spec { chipset: Chipset, - /// The revision of the chipset. revision: Revision, } impl Spec { - fn new(bar: &Bar0) -> Result<Spec> { + fn new(dev: &device::Device, 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); + if boot0.is_older_than_fermi() { + return Err(ENODEV); + } + + let boot42 = regs::NV_PMC_BOOT_42::read(bar); + Spec::try_from(boot42).inspect_err(|_| { + dev_err!(dev, "Unsupported chipset: {}\n", boot42); + }) + } +} + +impl TryFrom<regs::NV_PMC_BOOT_42> for Spec { + type Error = Error; + + fn try_from(boot42: regs::NV_PMC_BOOT_42) -> Result<Self> { Ok(Self { - chipset: boot0.chipset()?, - revision: Revision::from_boot0(boot0), + chipset: boot42.chipset()?, + revision: boot42.into(), }) } } +impl fmt::Display for Spec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(fmt!( + "Chipset: {}, Architecture: {:?}, Revision: {}", + self.chipset, + self.chipset.arch(), + self.revision + )) + } +} + /// Structure holding the resources required to operate the GPU. #[pin_data] pub(crate) struct Gpu { @@ -192,14 +261,8 @@ impl Gpu { bar: &'a Bar0, ) -> impl PinInit<Self, Error> + 'a { try_pin_init!(Self { - spec: Spec::new(bar).inspect(|spec| { - dev_info!( - pdev.as_ref(), - "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", - spec.chipset, - spec.chipset.arch(), - spec.revision - ); + spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| { + dev_info!(pdev.as_ref(),"NVIDIA ({})\n", spec); })?, // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. @@ -213,14 +276,12 @@ impl Gpu { gsp_falcon: Falcon::new( pdev.as_ref(), spec.chipset, - bar, - spec.chipset > Chipset::GA100, ) .inspect(|falcon| falcon.clear_swgen0_intr(bar))?, - sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar, true)?, + sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?, - gsp <- Gsp::new(), + gsp <- Gsp::new(pdev)?, _: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)? }, |
